Skip to content

Fix instantiating LiveComponentMetadata multiple times #1251

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

Merged
merged 1 commit into from
Nov 6, 2023

Conversation

TheDutchScorpion
Copy link
Contributor

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

This pull request fixes an issue with instantiating LiveComponentMetadata multiple times, when loading the same component multiple times.

@@ -33,12 +33,17 @@ public function __construct(

public function getMetadata(string $name): LiveComponentMetadata
{
static $liveComponentMetadata;
Copy link
Member

Choose a reason for hiding this comment

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

Maybe a private typed property ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could change it to

/** @var LiveComponentMetadata[] */
private static array $liveComponentMetadata = [];

...

public function getMetadata(string $name): LiveComponentMetadata
{
    if (isset(self::$liveComponentMetadata[$name])) {
        return self::$liveComponentMetadata[$name];
    }
    
    $componentMetadata = $this->componentFactory->metadataFor($name);

    $reflectionClass = new \ReflectionClass($componentMetadata->getClass());
    $livePropsMetadata = $this->createPropMetadatas($reflectionClass);

    return self::$liveComponentMetadata[$name] = new LiveComponentMetadata($componentMetadata, $livePropsMetadata);
}

Copy link
Member

Choose a reason for hiding this comment

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

Yup - do this. But don't make the property static. In practice, there will only be one LiveComponentMetadataFactory service, so static vs non-static won't make any real difference. But we should not enforce that there can only be one instance of this object by using static.

$componentMetadata = $this->componentFactory->metadataFor($name);

$reflectionClass = new \ReflectionClass($componentMetadata->getClass());
$livePropsMetadata = $this->createPropMetadatas($reflectionClass);

return new LiveComponentMetadata($componentMetadata, $livePropsMetadata);
return $liveComponentMetadata[$name] = new LiveComponentMetadata($componentMetadata, $livePropsMetadata);
Copy link
Member

Choose a reason for hiding this comment

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

Are we sure we want to share a single metadata instance for all the components of the same name ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The ComponentFactory metadataFor method also returns ComponentMetadata with configurations based on name, so it won't be a problem.

Copy link
Member

Choose a reason for hiding this comment

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

But is the instance modified elsewhere in the code ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The metadata DTO LiveComponentMetadata that will be stored only has private propeties and getters. All data within the DTO is static and related to property attribute LiveProp and static component configurations.

Copy link
Member

Choose a reason for hiding this comment

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

Yup, this looks good to me too. LiveComponentMetadata is meant to be the metadata for the component with the name $name. If we ever modify any of that metadata on component-by-component basis, that should be considered a bug (and I don't see any of that at the moment).

Copy link
Member

@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

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

Good PR 👍

@@ -33,12 +33,17 @@ public function __construct(

public function getMetadata(string $name): LiveComponentMetadata
{
static $liveComponentMetadata;
Copy link
Member

Choose a reason for hiding this comment

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

Yup - do this. But don't make the property static. In practice, there will only be one LiveComponentMetadataFactory service, so static vs non-static won't make any real difference. But we should not enforce that there can only be one instance of this object by using static.

$componentMetadata = $this->componentFactory->metadataFor($name);

$reflectionClass = new \ReflectionClass($componentMetadata->getClass());
$livePropsMetadata = $this->createPropMetadatas($reflectionClass);

return new LiveComponentMetadata($componentMetadata, $livePropsMetadata);
return $liveComponentMetadata[$name] = new LiveComponentMetadata($componentMetadata, $livePropsMetadata);
Copy link
Member

Choose a reason for hiding this comment

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

Yup, this looks good to me too. LiveComponentMetadata is meant to be the metadata for the component with the name $name. If we ever modify any of that metadata on component-by-component basis, that should be considered a bug (and I don't see any of that at the moment).

Copy link
Member

@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

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

just a php-cs thing - then good to go!

@@ -25,6 +25,9 @@
*/
class LiveComponentMetadataFactory
{
/** @var LiveComponentMetadata[] */
private array $liveComponentMetadata = [];

Copy link
Member

Choose a reason for hiding this comment

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

This empty line has some extra whitespace (you can see it in the php-cs-fixer job)

Copy link
Contributor Author

@TheDutchScorpion TheDutchScorpion Nov 6, 2023

Choose a reason for hiding this comment

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

This is what happens when using committing via github.com 😄

@weaverryan weaverryan force-pushed the fix-metadata-factory branch from 2603216 to 7e03119 Compare November 6, 2023 20:05
@weaverryan
Copy link
Member

Fantastic! Thanks @TheDutchScorpion!

@weaverryan weaverryan merged commit 633b02d into symfony:2.x Nov 6, 2023
@TheDutchScorpion TheDutchScorpion deleted the fix-metadata-factory branch November 6, 2023 20:07
@norkunas
Copy link
Contributor

norkunas commented Nov 6, 2023

Maybe this should implement Symfony's ResetInterface in case of long-running webserver?

@weaverryan
Copy link
Member

I'm not sure. Are Doctrine or validation metadata, for example, reset in this way? Or, perhaps those use proper caching vs storing on a property. So, you might have a point

@TheDutchScorpion
Copy link
Contributor Author

Should I open a PR for this or do you make this change? @weaverryan

@smnandre
Copy link
Member

smnandre commented Nov 6, 2023

Thanks @TheDutchScorpion 👍

@norkunas
Copy link
Contributor

norkunas commented Nov 7, 2023

I'm not sure. Are Doctrine or validation metadata, for example, reset in this way? Or, perhaps those use proper caching vs storing on a property. So, you might have a point

I mean that if we don't reset it could eat more memory than it should to without releasing the cache, so I think it's fine to have in memory cache for fetching metadata of same component many times, but sometimes it needs to be cleared up :)

weaverryan added a commit that referenced this pull request Nov 7, 2023
…hScorpion)

This PR was squashed before being merged into the 2.x branch.

Discussion
----------

Add ResetInterface to LiveComponentMetadataFactory

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| Issues        | N/A
| License       | MIT

This PR is a follow-up to the already merged PR #1251

Commits
-------

8d3d328 Add ResetInterface to LiveComponentMetadataFactory
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants