Skip to content

Refactoring EntityUserProvider::__construct() to not do work, cause cache warm error #16772

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

Closed

Conversation

weaverryan
Copy link
Member

Q A
Bug fix? "yes"
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets none
License MIT
Doc PR n/a

This fixes a "Database not Found" error when using doctrine/orm 2.5 while warming up your cache under certain situations. Basically, if you use the EntityUserProvider, then during cache warmup, Twig requires the security.authorization_checker which eventually requires this EntityUserProvider, which previously caused Doctrine to calculate the metadata for your User class. If no database exists (and you haven't specified the platform), you'll get the error.

More broadly, this simply tries to do less work in the constructor. It's a "bug fix", only kind of, but as it's completely an internal refactoring, it should be quite safe.

Thanks!

@stof
Copy link
Member

stof commented Dec 1, 2015

instead of loadMetadata, I suggest getting the repository and the metadata from the entity manager only on demand (getting it several times is not an issue as the entity manager keeps them in memory and so the second access will just read them from the array). This would simplify lots of things (and initializing $this->class requires loading the metadata only when it contains a : to resolve the alias)

}

$this->repository = $em->getRepository($class);
$this->em = $registry->getManager($managerName);
Copy link
Member

Choose a reason for hiding this comment

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

even better: you should store the registry and the manager name instead of instantiating the entity manager here. This would also make it compatible with resetting the EM.

@weaverryan weaverryan force-pushed the lazy-action-entity-user-provider branch 2 times, most recently from 43a8c73 to 4d6d41d Compare December 1, 2015 16:20
@@ -125,7 +125,7 @@ public function testLoadUserByUserNameShouldDeclineInvalidInterface()
private function getManager($em, $name = null)
{
$manager = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
$manager->expects($this->once())
$manager->expects($this->any())
Copy link
Member Author

Choose a reason for hiding this comment

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

We shouldn't really care how many times getManager() is called anyways. And now, it's called multiple times in some tests, and zero times in others.

@weaverryan
Copy link
Member Author

@stof good suggestions - I've just updated this PR: we get everything lazily. This is still an internal refactoring - I tried to minimize the changes to make this obvious.

Now, would this be a bug fix for 2.3? I have the PR opened against 2.8... which doesn't make any sense :). It seems like this should go into 2.3 or into master for 3.1. I'd like to put it into 2.3.

@Tobion
Copy link
Contributor

Tobion commented Dec 1, 2015

Does this fix doctrine/DoctrineBundle#351 ?


private function getClassMetadata()
{
return $this->getEntityManager()->getClassMetadata($this->getClass());
Copy link
Contributor

Choose a reason for hiding this comment

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

getClassMetadata calls getClass and getClass calls getClassMetadata. Looks like a possible endless loop.

Copy link
Member Author

Choose a reason for hiding this comment

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

Wow, good eye. In fact, I should only use getClass() where we actually need a valid PHP class name. I've updated to do that (otherwise, just use the class/alias that was passed in).

@weaverryan
Copy link
Member Author

@Tobion Yes and no. It definitely fixed one more case where that error happens. But are there other situations that still cause that error? Possibly. But yea, when I saw this issue locally, I knew it was doctrine/DoctrineBundle#351 and wanted to squash it :)

@nicolas-grekas
Copy link
Member

👍 for 2.3

@Tobion
Copy link
Contributor

Tobion commented Dec 2, 2015

The only other place where getClassMetadata or getRepository is called in a constructor in symfony is for the ChoiceLoader in Doctrine form type. But that is only constructed on demand when evaluating choices. So that should not be a problem. So i think after this change symfony itself is save against doctrine/DoctrineBundle#351

👍 for 2.3

Status: Reviewed

@xabbuh
Copy link
Member

xabbuh commented Dec 2, 2015

👍

return $class === $this->getClass() || is_subclass_of($class, $this->getClass());
}

private function getEntityManager()
Copy link
Member

Choose a reason for hiding this comment

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

I would call it getObjectManager, as this also supports ODMs

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated

@stof
Copy link
Member

stof commented Dec 2, 2015

I agree this should go in 2.3

…ny work

This helps break a dependency chain during cache warmup, that includes having
Doctrine load metadata, which will fail if there is no database on new Doctrine versions.
@weaverryan weaverryan force-pushed the lazy-action-entity-user-provider branch from ca8b843 to b4246bf Compare December 2, 2015 15:16
@stof
Copy link
Member

stof commented Dec 2, 2015

👍

@weaverryan
Copy link
Member Author

I've just rebased this against 2.3 - it shows as a conflict against 2.8, but will merge cleanly into 2.3.

It should be ready for a merge. Tests before my last rebase all passed except for an unrelated hhvm failure.

@stof
Copy link
Member

stof commented Dec 2, 2015

Thank you @weaverryan.

stof added a commit that referenced this pull request Dec 2, 2015
…rk, cause cache warm error (weaverryan)

This PR was submitted for the 2.8 branch but it was merged into the 2.3 branch instead (closes #16772).

Discussion
----------

Refactoring EntityUserProvider::__construct() to not do work, cause cache warm error

| Q             | A
| ------------- | ---
| Bug fix?      | "yes"
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | none
| License       | MIT
| Doc PR        | n/a

This fixes a "Database not Found" error when using `doctrine/orm` 2.5 while warming up your cache under certain situations. Basically, if you use the `EntityUserProvider`, then during cache warmup, Twig requires the `security.authorization_checker` which eventually requires this `EntityUserProvider`, which previously caused Doctrine to calculate the metadata for your User class. If no database exists (and you haven't specified the platform), you'll get the error.

More broadly, this simply tries to do less work in the constructor. It's a "bug fix", only kind of, but as it's completely an internal refactoring, it should be quite safe.

Thanks!

Commits
-------

44a2861 Refactoring EntityUserProvider::__construct() to not do work, cause cache warm error
@weaverryan
Copy link
Member Author

Thanks @stof! There will be a conflict when merging to 2.8: but it should be simple to fix: use the new side of the diff (i.e. the code from 2.8), but replace $this->repository with $repository (and don't forget the $repository that's way over to the right at the end of a message :)

@stof stof closed this Dec 2, 2015
@stof
Copy link
Member

stof commented Dec 2, 2015

I merge 2.3 into 2.7 and 2.8 to resolve the conflict

@weaverryan weaverryan deleted the lazy-action-entity-user-provider branch December 14, 2015 22:50
This was referenced Dec 26, 2015
This was referenced Dec 26, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants