-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Possible BC break introduce since v3.4.20 #30017
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
Comments
Would you be able to submit a failing test case? |
@nicolas-grekas Yes. Here is a broken app : https://github.com/nykopol/broken-app |
@nykopol , you should not inject entity manager via constructor because that leads to a circular dependency. Listeners are "child" objects in relation to the manager, so they cannot receive it as a dependency. Instead you should use the second argument of your callable to retrieve the relevant entity manager: <?php
namespace AppBundle\Listener;
use AppBundle\Entity\MyEntity;
use Doctrine\ORM\Event\PreUpdateEventArgs;
class ServiceThatWillNotFailAnymore
{
public function __construct(/* other args */)
{
}
public function prePersist(MyEntity $entity, PreUpdateEventArgs $args)
{
$entityManager = $args->getEntityManager();
}
} |
I hope, that will solve your issue. Btw, you can find more about the listener's arguments in the official Doctrine Documentation. I think we should explain how to retrieve entity manager in the Doctrine Bundle's docs. @javiereguiluz, @nicolas-grekas, WDYT? |
@vudaltsov I understand the fact that Listener is a "child" object and that I can get the manager in the For the principle, a Listener is a service. Why he's not allowed to inject this service ? We can imagine a use case where the listener collect some information on |
Circular dependency is a bad practice 99% of the time, no matter how long the dependency chain is. As a rule it points at some architectural problems. In your case I see the problem of mixing different contexts. The context of the entity manager transaction and the request context. Here you can create a separate service called While my solution is still not ideal and might be improved for your particular case, it uses a mediator object (see Indirection in GRASP) to organize communication between services and to eliminate the circular dependency problem. |
…kas) This PR was merged into the 3.4 branch. Discussion ---------- [DI] Fix dumping Doctrine-like service graphs | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #30017 #29637 #29693 | License | MIT | Doc PR | - I'm unable to provide a reproducer for this, the required service reference graph is too crazy, but that does the job :) Commits ------- ed96830 [DI] Fix dumping Doctrine-like service graphs
thanks for the help |
Symfony version(s) affected: v3.4.20 and v3.4.21
Description
I'm not sure if it's a BC break in Symfony or a bad practice in Doctrine ORM (doctrine/orm:v2.5.14).
Since the commit 0d0be12, if a service is attached to the lifecycle events of doctrine, the service is not called. Instead, doctrine try to implement a new instance of the service (without the arguments).
How to reproduce
Configure a service that is attached to a doctrine event:
The service:
Trigger the event and an error occur:
Additional context
By digging inside, I found that inside the
ListenersInvoker
of Doctrine, a resolver has the responsibility to resolve the class and method attached to an event into an instance.Before v3.4.20, the resolver was an instance of
ContainerAwareEntityListenerResolver
which is capable of translating the class in the corresponding service.Since v3.4.20, it's a
DefaultEntityResolverListener
which only create a new instance of the class without arguments.It's a problem of timing.
The resolver is not directly injected on the constructor of the
ListenersInvoker
. Instead, theListenersInvoker
receive thedoctrine.orm.configuration
from which it retrieve the resolver inside the constructor. But at this state, thedoctrine.orm.configuration
is not yet configured.The
doctrine.orm.configuration
service is configured by some setters. The fact is that since the v3.4.20, the setters are called afterListenersInvoker::construct()
. So theListenersInvoker
don't have the good resolver.The text was updated successfully, but these errors were encountered: