-
-
Notifications
You must be signed in to change notification settings - Fork 64
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
Fix Metadata Caching when it changes in EventListeners #21
Fix Metadata Caching when it changes in EventListeners #21
Conversation
a39a722
to
4e124e8
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.
Looking good, just some minor details
tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php
Outdated
Show resolved
Hide resolved
tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php
Outdated
Show resolved
Hide resolved
tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php
Outdated
Show resolved
Hide resolved
tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php
Outdated
Show resolved
Hide resolved
Can you also rebase your branch to organise your commits, please? |
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.
Apart from the issues highlighted by @lcobucci, LGTM! Thanks @andrey-bondar-dron!
lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
Outdated
Show resolved
Hide resolved
93248ee
to
6f785d5
Compare
Hi! Guys, someone has already fixed all required changes, while I was absent. Thanks. :) |
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.
The change and refactoring looks good overall, but there is one issue that needs to be addressed (see inline comment).
Note that class aliases are to be removed in next major, but now they only cause troubles (like out-of-sync metadata during setMetadata() or in cache).
@@ -167,7 +167,9 @@ public function getMetadataFor($className) | |||
|
|||
if (isset($this->loadedMetadata[$realClassName])) { | |||
// We do not have the alias name in the map, include it | |||
return $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; | |||
$this->setMetadataFor($realClassName, $this->loadedMetadata[$realClassName]); |
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.
This particular change breaks in-memory caching ($this->loadedMetadata
) for aliased classes, therefore breaking hot path at the top of this method for those:
public function testGettingAliasesOnlyFetchesFromCacheOnce() : void
{
$loadedReflection = new ReflectionProperty(AbstractClassMetadataFactory::class, 'loadedMetadata');
$loadedReflection->setAccessible(true);
$this->cmf->getMetadataFor(RootEntity::class);
self::assertArrayHasKey(RootEntity::class, $loadedReflection->getValue($this->cmf));
self::assertArrayNotHasKey('Alias:RootEntity', $loadedReflection->getValue($this->cmf));
$this->cmf->getMetadataFor('Alias:RootEntity');
self::assertArrayHasKey(RootEntity::class, $loadedReflection->getValue($this->cmf));
self::assertArrayHasKey('Alias:RootEntity', $loadedReflection->getValue($this->cmf));
}
It's because this condition has changed semantics and no longer does what the comment above says: "We do not have the alias name in the map, include it"
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.
@Majkl578 When it is needed to change metadata for some entity in EventListeners, we do not know about aliases that were used.
When I call setMetadataFor with real class name, AbstractClassMetadataFactory should replace metadata for all aliases in $loadedMetadata. And vise versa when I call setMetadataFor with alias.
For my opinion, it is normal when we will save only real classes in $loadedMetadata, because it prevent to have many problems with aliases.
On every call getMetadataFor with alias this code will be executed
// Check for namespace alias
if (strpos($className, ':') !== false) {
[$namespaceAlias, $simpleClassName] = explode(':', $className, 2);
$realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
} else {
$realClassName = $this->getRealClass($className);
}
In order to prevent it I can create map for 'alias' => 'realClassName' and replace this code
// Check for namespace alias
if (strpos($className, ':') !== false) {
[$namespaceAlias, $simpleClassName] = explode(':', $className, 2);
$realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
} else {
$realClassName = $this->getRealClass($className);
}
with something like this
switch (true) {
case isset($this->aliasesMap[$className]):
$realClassName = $this->aliasesMap[$className];
break;
case strpos($className, ':') !== false // Check for namespace alias
[$namespaceAlias, $simpleClassName] = explode(':', $className, 2);
$realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
$this->aliasesMap[$className] = $realClassName;
break;
default:
$realClassName = $this->getRealClass($className);
}
In this case AbstractClassMetadataFactory will not be too coupled with aliases in setMetadataFor/getMetadataFor methods.
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.
So, fixed.
For now in in-memory cache (also in MetadataCache) will be saved single value for all aliases.
Calling setMetadataFor and getMetadataFor with aliases or FQCN will same keys.
c4719a7
to
7784315
Compare
*/ | ||
private function getRealClass(string $class) : string | ||
private function getRealClassName($className) |
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.
Type hints are here to stay: there's no reason you should assume anything else than a string for $className
.
*/ | ||
private function getRealClass(string $class) : string | ||
private function getRealClassName($className) |
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 may also profit from making this method protected
: class name resolution for proxy class names is currently more difficult in ODM 2.0 and ORM 3.0 (master) since moving away from the legacy proxies. Overriding this method would at least temporarily solve this problem. Opinions @lcobucci @Majkl578?
8e28527
to
6b47038
Compare
This PR fixed 2 bugs:
I hope, it will be merged to version 1.0.2 and released ASAP.