-
-
Notifications
You must be signed in to change notification settings - Fork 338
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
base: 2.x
Are you sure you want to change the base?
Conversation
88c149a
to
5eb4948
Compare
5eb4948
to
afc9f40
Compare
There was a problem hiding this 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
src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php
Outdated
Show resolved
Hide resolved
afc9f40
to
567d81a
Compare
@Kocal I'm glad you like it! 😊 Thanks for the feedback. The BC break is now fixed and pushed! |
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. |
src/TwigComponent/CHANGELOG.md
Outdated
@@ -1,5 +1,9 @@ | |||
# CHANGELOG | |||
|
|||
## 2.23.0 | |||
|
|||
- Add `ComponentPropertiesExtractor` to extract component properties from a Twig component |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
/** | ||
* @return array<string, string> | ||
*/ |
There was a problem hiding this comment.
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)
I started this work here : 2.x...smnandre:ux:dev/template-properties |
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 ? 😁 |
There was a problem hiding this 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 😅
Any thought about my main points @Halleck45 ? (ComponentProperties / ComponentPropertyExtractor and the metadata thing) |
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:
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 :) |
111715c
to
091a2a3
Compare
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. |
There was a problem hiding this 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 :)
} | ||
|
||
/** | ||
* @return array<array{display: string, name: string, type: string, default: mixed}> |
There was a problem hiding this comment.
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:
* @return array<array{display: string, name: string, type: string, default: mixed}> | |
* @return array<string, array{display: string, name: string, type: string, default: mixed}> |
Co-authored-by: Hugo Alliaume <[email protected]>
Co-authored-by: Hugo Alliaume <[email protected]>
Co-authored-by: Hugo Alliaume <[email protected]>
Co-authored-by: Simon André <[email protected]>
Co-authored-by: Simon André <[email protected]>
$propertyDisplay = $typeName.' $'.$propertyName.(null !== $value ? ' = '.json_encode( | ||
$value | ||
) : ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$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}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @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, |
There was a problem hiding this comment.
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}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @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 |
There was a problem hiding this comment.
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".
$propertiesAsArrayOfStrings = array_filter(array_map( | ||
fn (array $property) => $property['display'], | ||
$properties, | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$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)], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
['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)], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
['Properties', implode("\n", $propertiesAsArrayOfStrings)], | |
['Properties', implode("\n", $properties)], |
3/3
(last comments and LGTM ;) ) |
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 ? |
I think it's fine to make it public but with the We can also tag it as internal, with a warning message |
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! |
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 newComponentPropertiesExtractor
class.A BC is introduced: I need to inject theComponentPropertiesExtractor
class into theTwigComponentDebugCommand
, but the last argument of the constructor is optional. This is normally not a problem: the class is internalIf 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!