Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TwigComponent] Add new ComponentReflection to extract properties from TwigComponent #2498

Open
wants to merge 9 commits into
base: 2.x
Choose a base branch
from

Conversation

Halleck45
Copy link

@Halleck45 Halleck45 commented Jan 10, 2025

Q A
Bug fix? no
New feature? yes
Issues
License MIT

Hello,

I'm currently trying to build a tool that analyzes TwigComponent to document (automatically) the components of a project. A bit like what StoryBook does, but for Twig.

For this, I need to retrieve the properties of a component. The TwigComponentDebugCommand command already does this. This PR extracts the relevant code, and moves it to the new ComponentPropertiesExtractor class.

A BC is introduced: I need to inject the ComponentPropertiesExtractor class into the TwigComponentDebugCommand, but the last argument of the constructor is optional. This is normally not a problem: the class is internal
If necessary, I can keep backward compatibility by building the object directly in the code (rather than injecting it), but in the long run this may introduce testability issues.
Edit: fixed thanks to @Kocal suggestion

Thank you for your feedback!

@Halleck45 Halleck45 force-pushed the properties_extractor branch 5 times, most recently from 88c149a to 5eb4948 Compare January 10, 2025 10:43
@Halleck45 Halleck45 changed the title Add new ComponentPropertiesExtractor to extract properties from TwigComponent [TwigComponent] Add new ComponentPropertiesExtractor to extract properties from TwigComponent Jan 10, 2025
@Halleck45 Halleck45 force-pushed the properties_extractor branch from 5eb4948 to afc9f40 Compare January 10, 2025 10:52
@Halleck45 Halleck45 marked this pull request as ready for review January 10, 2025 10:54
@carsonbot carsonbot added Feature New Feature TwigComponent Status: Needs Review Needs to be reviewed labels Jan 10, 2025
Copy link
Member

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feature, that's really interesting and could be really useful for some use cases, and we have new tests! :D

Just a minor comment about the BC break.

cc @smnandre

@Halleck45 Halleck45 force-pushed the properties_extractor branch from afc9f40 to 567d81a Compare January 10, 2025 11:23
@Halleck45
Copy link
Author

Thanks for the feature, that's really interesting and could be really useful for some use cases, and we have new tests! :D

Just a minor comment about the BC break.

@Kocal I'm glad you like it! 😊 Thanks for the feedback. The BC break is now fixed and pushed!

@smnandre
Copy link
Member

Hi! I need to digg deeper in the code (later today), but already a big thank you for opening this and contributing!

First reaction is: some code here is redondant with the ComponentProperties class.

I think we should differenciate here the extraction of props from templates, and props from classes.

Making ComponentProperties call different sources (maybe more "Loaders" than "extractors" in the end).


And starting after that building the ComponentMetadataFactory / ies we need.

@@ -1,5 +1,9 @@
# CHANGELOG

## 2.23.0

- Add `ComponentPropertiesExtractor` to extract component properties from a Twig component
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to expose this class (with BC promise) for something like this. At least in a first step.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, BC is resolved now. Do you still want me to remove this change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, my point is i'm not sure we should make this class "public" for now. Because once it's done, we cannot go back.

And, as i said in the previous message, we need to clarifiy first whose class has which responsibility, the contracts, etc.

Comment on lines 37 to 39
/**
* @return array<string, string>
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the good type (you return an array of string => array{name: display: type: ...} for no)

@smnandre
Copy link
Member

I started this work here : 2.x...smnandre:ux:dev/template-properties

@smnandre smnandre added Status: Reviewing Review is ongoing, refining with author and removed Status: Needs Review Needs to be reviewed labels Jan 10, 2025
@WebMamba
Copy link
Contributor

Hey there 👋 Thanks @Halleck45 for your PR! I am interested about your debugging tool! Why not using : https://packagist.org/packages/sensiolabs/storybook-bundle ? What your debugging tool gonna do ? 😁

Copy link
Contributor

@WebMamba WebMamba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thinks that it's a good idea to move the logic to extract property information into a dedicated service, and we should do the same for the service to find the components. But I thinks all of that should not be separate from the core. I don't have any solution yet 😅

@Halleck45 Halleck45 requested a review from Kocal January 14, 2025 08:38
@carsonbot carsonbot added the Status: Needs Review Needs to be reviewed label Jan 14, 2025
@smnandre
Copy link
Member

Any thought about my main points @Halleck45 ? (ComponentProperties / ComponentPropertyExtractor and the metadata thing)

@Halleck45 Halleck45 changed the title [TwigComponent] Add new ComponentPropertiesExtractor to extract properties from TwigComponent [TwigComponent] Add new ComponentReflection to extract properties from TwigComponent Jan 15, 2025
@smnandre
Copy link
Member

Hmm that does not feel entirely right to me right now.. :|

And i understand you need this for something. But we cannot introduce a class that, at least for a part, does what is already done by another, with cache and preloading instead of runtime.

So i'm very sorry for this, but yeah it's probably a safer choice in these conditions to go back at your original proposal.

The problems of code duplication and maintaining this class afterwards being still here in both case, i'd suggest the following:

  • move it into a Debug folder (or something like that in the name, you know, to clearly identify it) .... (and probably not include it when not APP_DEBUG=true, or do i miss something here?)
  • but most importantly i'd set this class as experimental, allowing us to revert this change if we roll out a clean Metadata Factory/Loader before the end of the year.

I know this seems not much, but you cannot imagine the time i'm spending on debug/maintenance on tiny things like this, and I really would love to spend more of my time on new things :)

@Halleck45 Halleck45 force-pushed the properties_extractor branch from 111715c to 091a2a3 Compare January 16, 2025 09:10
@Halleck45
Copy link
Author

Hmm that does not feel entirely right to me right now.. :|

No problem, I just reverted the last commit.

I'll keep the branch handy anyway, as I think it would be cleaner to have strong typing on what's being extracted.

Copy link
Member

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, and I think we will be ready to merge it :)

src/TwigComponent/src/ComponentPropertiesExtractor.php Outdated Show resolved Hide resolved
src/TwigComponent/src/ComponentPropertiesExtractor.php Outdated Show resolved Hide resolved
}

/**
* @return array<array{display: string, name: string, type: string, default: mixed}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can be a little bit more precise by setting string as the array key:

Suggested change
* @return array<array{display: string, name: string, type: string, default: mixed}>
* @return array<string, array{display: string, name: string, type: string, default: mixed}>

src/TwigComponent/src/ComponentPropertiesExtractor.php Outdated Show resolved Hide resolved
Comment on lines +64 to +66
$propertyDisplay = $typeName.' $'.$propertyName.(null !== $value ? ' = '.json_encode(
$value
) : '');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$propertyDisplay = $typeName.' $'.$propertyName.(null !== $value ? ' = '.json_encode(
$value
) : '');
$propertyDisplay = $typeName.' $'.$propertyName.(null !== $value ? ' = '.json_encode($value) : '');

/**
* Extract properties from {% props %} tag in anonymous template.
*
* @return array<array{display: string, name: string, type: string, default: mixed}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @return array<array{display: string, name: string, type: string, default: mixed}>
* @return array<array{display: string, name: string, type: string, default: ?string}>

'name' => $propertyName,
'display' => $propertyDisplay,
'type' => $typeName,
'default' => $value,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be json encoded as the other one

}

/**
* @return array<string, array{display: string, name: string, type: string, default: mixed}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @return array<string, array{display: string, name: string, type: string, default: mixed}>
* @return array<string, array{display: string, name: string, type: string, default: ?string}>

(once fixed the value json encoding)

/**
* @return array<string, array{display: string, name: string, type: string, default: mixed}>
*/
private function getNonAnonymousComponentProperties(ComponentMetadata $metadata): array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid double negation if possible. Anonymous component are a special type of components.

But "non anonymous components" are just "components".

Comment on lines +218 to +221
$propertiesAsArrayOfStrings = array_filter(array_map(
fn (array $property) => $property['display'],
$properties,
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$propertiesAsArrayOfStrings = array_filter(array_map(
fn (array $property) => $property['display'],
$properties,
));
$properties = array_column($properties, 'display');

1/3

// Anonymous Component
if ($metadata->isAnonymous()) {
$table->addRows([
['Type', '<comment>Anonymous</comment>'],
new TableSeparator(),
['Properties', implode("\n", $this->getAnonymousComponentProperties($metadata))],
['Properties', implode("\n", $propertiesAsArrayOfStrings)],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
['Properties', implode("\n", $propertiesAsArrayOfStrings)],
['Properties', implode("\n", $properties)],

2/3

@@ -229,7 +237,7 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void
new TableSeparator(),
// ['Attributes Var', $metadata->get('attributes_var')],
['Public Props', $metadata->isPublicPropsExposed() ? 'Yes' : 'No'],
['Properties', implode("\n", $this->getComponentProperties($metadata))],
['Properties', implode("\n", $propertiesAsArrayOfStrings)],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
['Properties', implode("\n", $propertiesAsArrayOfStrings)],
['Properties', implode("\n", $properties)],

3/3

@smnandre
Copy link
Member

(last comments and LGTM ;) )

@WebMamba
Copy link
Contributor

Hey @Halleck45! Thanks for your interest, but I am not sure we gonna merge this PR. The reason is that I see the value of exposing such classes to your project, but I think there is less value for the Symfony UX project. We don't have any plan to use this code in another place than in the debug command; this is why I think we don't need to move the code to a dedicated class. Exposing such classes has cost (maintenance, BC, ...), so I don't think it gonna be valuable for us to have this class. Sorry about that, don't take it personally, we really appreciate having you here. @smnandre @Kocal WDYT ?

@Kocal
Copy link
Member

Kocal commented Jan 23, 2025

I think it's fine to make it public but with the @experimental annotation, so we are free to not respect the BC promise, but the users must use it carefully.

We can also tag it as internal, with a warning message This class is not covered by the Symfony backward compatibility promise. like PHPUnit does.

@Halleck45
Copy link
Author

No worries about closing this PR. I think I can move forward in another way. Thanks for your feedback anyway!

@WebMamba, I couldn't get storybook-bundle to work, but it makes me want to dig deeper.

See you soon!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New Feature Status: Reviewed Has been reviewed by a maintainer Status: Reviewing Review is ongoing, refining with author TwigComponent
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants