Skip to content

Commit

Permalink
changed named of PropertiesExtractor, and uses typed ComponentPropert…
Browse files Browse the repository at this point in the history
…yReflection
  • Loading branch information
Halleck45 committed Jan 15, 2025
1 parent 091a2a3 commit 111715c
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 159 deletions.
2 changes: 1 addition & 1 deletion src/TwigComponent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 2.23.0

- Add `ComponentPropertiesExtractor` to extract component properties from a Twig component
- Add `ComponentReflection` to extract component properties from a Twig component

## 2.20.0

Expand Down
13 changes: 7 additions & 6 deletions src/TwigComponent/src/Command/TwigComponentDebugCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,28 @@
use Symfony\Component\Finder\Finder;
use Symfony\UX\TwigComponent\ComponentFactory;
use Symfony\UX\TwigComponent\ComponentMetadata;
use Symfony\UX\TwigComponent\ComponentPropertiesExtractor;
use Symfony\UX\TwigComponent\ComponentPropertyReflection;
use Symfony\UX\TwigComponent\ComponentReflection;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

#[AsCommand(name: 'debug:twig-component', description: 'Display components and them usages for an application')]
class TwigComponentDebugCommand extends Command
{
private readonly string $anonymousDirectory;
private readonly ComponentPropertiesExtractor $componentPropertiesExtractor;
private readonly ComponentReflection $componentReflection;

public function __construct(
private string $twigTemplatesPath,
private ComponentFactory $componentFactory,
private Environment $twig,
private readonly array $componentClassMap,
?string $anonymousDirectory = null,
?ComponentPropertiesExtractor $componentPropertiesExtractor = null,
?ComponentReflection $componentReflection = null,
) {
parent::__construct();
$this->anonymousDirectory = $anonymousDirectory ?? 'components';
$this->componentPropertiesExtractor = $componentPropertiesExtractor ?? new ComponentPropertiesExtractor($this->twig);
$this->componentReflection = $componentReflection ?? new ComponentReflection($this->twig);
}

protected function configure(): void
Expand Down Expand Up @@ -214,9 +215,9 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void
['Template', $metadata->getTemplate()],
]);

$properties = $this->componentPropertiesExtractor->getComponentProperties($metadata);
$properties = $this->componentReflection->getProperties($metadata);
$propertiesAsArrayOfStrings = array_filter(array_map(
fn (array $property) => $property['display'],
fn (ComponentPropertyReflection $property) => $property->getCode(),
$properties,
));

Expand Down
59 changes: 59 additions & 0 deletions src/TwigComponent/src/ComponentPropertyReflection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\TwigComponent;

/**
* @author Jean-François Lépine <[email protected]>
*/
class ComponentPropertyReflection
{
public function __construct(
private readonly ComponentMetadata $metadata,
private readonly string $name,
private readonly string $type = 'mixed',
private readonly mixed $defaultValue = null,
) {
}

public function getCode(): string
{
if (null === $this->defaultValue) {
return \sprintf('%s $%s = ""', $this->type, $this->name);
}

if (\is_bool($this->defaultValue)) {
return \sprintf('%s $%s = %s', $this->type, $this->name, $this->defaultValue ? 'true' : 'false');
}

return \sprintf('%s $%s = %s', $this->type, $this->name, json_encode($this->defaultValue));
}

public function getName(): string
{
return $this->name;
}

public function getType(): string
{
return $this->type;
}

public function getDefaultValue(): mixed
{
return $this->defaultValue;
}

public function getMetadata(): ComponentMetadata
{
return $this->metadata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@
use Symfony\UX\TwigComponent\Twig\PropsNode;
use Twig\Environment;

final class ComponentPropertiesExtractor
/**
* @author Jean-François Lépine <[email protected]>
*/
final class ComponentReflection
{
public function __construct(
private readonly Environment $twig,
) {
}

/**
* @return array<array{display: string, name: string, type: string, default: mixed}>
* @return ComponentPropertyReflection[]
*/
public function getComponentProperties(ComponentMetadata $medata)
public function getProperties(ComponentMetadata $medata): array
{
if ($medata->isAnonymous()) {
return $this->getAnonymousComponentProperties($medata);
Expand All @@ -34,8 +37,15 @@ public function getComponentProperties(ComponentMetadata $medata)
return $this->getNonAnonymousComponentProperties($medata);
}

public function getProperty(ComponentMetadata $medata, string $name): ?ComponentPropertyReflection
{
$properties = $this->getProperties($medata);

return $properties[$name] ?? null;
}

/**
* @return array<array{display: string, name: string, type: string, default: mixed}>
* @return ComponentPropertyReflection[]
*/
private function getNonAnonymousComponentProperties(ComponentMetadata $metadata): array
{
Expand All @@ -52,26 +62,13 @@ private function getNonAnonymousComponentProperties(ComponentMetadata $metadata)
$typeName = (string) $type;
}
$value = $property->getDefaultValue();
$propertyDisplay = $typeName.' $'.$propertyName.(null !== $value ? ' = '.json_encode(
$value
) : '');
$properties[$property->name] = [
'name' => $propertyName,
'display' => $propertyDisplay,
'type' => $typeName,
'default' => $value,
];
$properties[$propertyName] = new ComponentPropertyReflection($metadata, $propertyName, $typeName, $value);
}

foreach ($property->getAttributes(ExposeInTemplate::class) as $exposeAttribute) {
/** @var ExposeInTemplate $attribute */
$attribute = $exposeAttribute->newInstance();
$properties[$property->name] = [
'name' => $attribute->name ?? $property->name,
'display' => $attribute->name ?? $property->name,
'type' => 'mixed',
'default' => null,
];
$properties[$property->name] = new ComponentPropertyReflection($metadata, $attribute->name ?? $property->name);
}
}

Expand All @@ -81,7 +78,7 @@ private function getNonAnonymousComponentProperties(ComponentMetadata $metadata)
/**
* Extract properties from {% props %} tag in anonymous template.
*
* @return array<array{display: string, name: string, type: string, default: mixed}>
* @return ComponentPropertyReflection[]
*/
private function getAnonymousComponentProperties(ComponentMetadata $metadata): array
{
Expand All @@ -103,36 +100,18 @@ private function getAnonymousComponentProperties(ComponentMetadata $metadata): a
}

$propertyNames = $propsNode->getAttribute('names');
$properties = array_combine($propertyNames, $propertyNames);
$properties = [];
foreach ($propertyNames as $propName) {
$properties[$propName] = new ComponentPropertyReflection($metadata, $propName, 'mixed');
}

foreach ($propertyNames as $propName) {
if ($propsNode->hasNode($propName)
&& ($valueNode = $propsNode->getNode($propName))
&& $valueNode->hasAttribute('value')
) {
$value = $valueNode->getAttribute('value');
if (\is_bool($value)) {
$value = $value ? 'true' : 'false';
} else {
$value = json_encode($value);
}
$display = $propName.' = '.$value;
$properties[$propName] = [
'name' => $propName,
'display' => $display,
'type' => \is_bool($value) ? 'bool' : 'mixed',
'default' => $value,
];
}
}

foreach ($properties as $propertyData) {
if (\is_string($propertyData)) {
$properties[$propertyData] = [
'name' => $propertyData,
'display' => $propertyData,
'type' => 'mixed',
'default' => null,
];
$properties[$propName] = new ComponentPropertyReflection($metadata, $propName, 'mixed', $value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
use Symfony\UX\TwigComponent\Command\TwigComponentDebugCommand;
use Symfony\UX\TwigComponent\ComponentFactory;
use Symfony\UX\TwigComponent\ComponentProperties;
use Symfony\UX\TwigComponent\ComponentPropertiesExtractor;
use Symfony\UX\TwigComponent\ComponentReflection;
use Symfony\UX\TwigComponent\ComponentRenderer;
use Symfony\UX\TwigComponent\ComponentRendererInterface;
use Symfony\UX\TwigComponent\ComponentStack;
Expand Down Expand Up @@ -135,7 +135,7 @@ static function (ChildDefinition $definition, AsTwigComponent $attribute) {
->setDecoratedService(new Reference('twig.configurator.environment'))
->setArguments([new Reference('ux.twig_component.twig.environment_configurator.inner')]);

$container->register('ux.twig_component.extractor_properties', ComponentPropertiesExtractor::class)
$container->register('ux.twig_component.extractor_properties', ComponentReflection::class)
->setArguments([
new Reference('twig'),
]);
Expand Down
106 changes: 0 additions & 106 deletions src/TwigComponent/tests/Unit/ComponentPropertiesExtractorTest.php

This file was deleted.

Loading

0 comments on commit 111715c

Please sign in to comment.