Skip to content

Missing priority for events in doctrine bridge #21977

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
chapterjason opened this issue Mar 11, 2017 · 7 comments
Closed

Missing priority for events in doctrine bridge #21977

chapterjason opened this issue Mar 11, 2017 · 7 comments

Comments

@chapterjason
Copy link
Contributor

chapterjason commented Mar 11, 2017

Q A
Bug report? no
Feature request? yes
BC Break report? no
RFC? no
Symfony version 3.2.4

I just have two listeners and they have to be in the correct order. My first approach was to set the priority in the tags for the listeners, I noticed that nothing changed the order. After I checked the code in Symfony/Bridge/Doctrine/ContainerAwareEventManager.php#L101 and compared it to Symfony/Component/Form/FormConfigBuilderInterface.php#L33 I just realized that the priority is missing.

Yeah I know that Component/Form and the Bridge/Doctrine are two different parts.

@javiereguiluz
Copy link
Member

You are right: we allow to define priorities everywhere ... so I guess it should be OK to add priorities here too. 👍 from me!

@wouterj
Copy link
Member

wouterj commented Mar 12, 2017

Doctrine is using its own EventManager: https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/EventManager.php This one doesn't have the priority feature, so it's not something we can add in Symfony. It should first be added in the Doctrine EventManager.

@javiereguiluz
Copy link
Member

@chapterjason after @wouterj's comment, I'm afraid we need to close this as "can't fix" because it depends on Doctrine project. If you still want this feature, please open an issue in https://github.com/doctrine/common/issues

Thanks!

@dmaicher
Copy link
Contributor

Aren't the listeners and subscribers already registered in the correct order when specifying priorities on the tag?

https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php#L67

@chapterjason
Copy link
Contributor Author

Thank you @dmaicher I found out that https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php#L91 does not take care of priorities what makes no sense cause the priorities will sorted later in https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php#L95

My prove:
I changed the lines to following

            var_dump(json_encode($taggedListeners));
            $listenersPerCon = $this->groupByConnection($taggedListeners, true);
            var_dump(json_encode($listenersPerCon));

My result:

Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass.php:92:
{
   "my.listener1":[
      {
         "event":"prePersist"
      },
      {
         "event":"preUpdate",
         "priority":50
      }
   ],
   "my.listener2":[
      {
         "event":"postPersist"
      },
      {
         "event":"preUpdate",
         "priority":100
      },
      {
         "event":"preRemove"
      },
      {
         "event":"postFlush"
      }
   ]
}

Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass.php:94:
{
   "default":{
      "my.listener1":{
         "event":[
            "prePersist",
            "preUpdate"
         ]
      },
      "my.listener2":{
         "event":[
            "postPersist",
            "preUpdate",
            "preRemove",
            "postFlush"
         ]
      }
   }
}

@dmaicher
Copy link
Contributor

dmaicher commented Mar 12, 2017

@javiereguiluz we have to re-open this unfortunately 😢 I double checked and there is indeed something broken with handling the priorities.

This only ever worked correctly if there is exactly one tag per service as otherwise the priorities are lost or handled incorrectly.

Thanks @chapterjason for debugging it 👍

Test case that we have for it currently:

    public function testProcessEventListenersWithPriorities()
    {
        $container = $this->createBuilder();

        $container
            ->register('a', 'stdClass')
            ->addTag('doctrine.event_listener', array(
                'event' => 'foo',
                'priority' => -5,
            ))
            ->addTag('doctrine.event_listener', array(
                'event' => 'bar',
            ))
        ;
        $container
            ->register('b', 'stdClass')
            ->addTag('doctrine.event_listener', array(
                'event' => 'foo',
            ))
        ;

        $this->process($container);
        $this->assertEquals(array('b', 'a'), $this->getServiceOrder($container, 'addEventListener'));

        $calls = $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls();
        $this->assertEquals(array('foo', 'bar'), $calls[1][1][0]);
    }

If we switch the tag order for service a like

        $container
            ->register('a', 'stdClass')
            ->addTag('doctrine.event_listener', array(
                'event' => 'bar',
            ))
            ->addTag('doctrine.event_listener', array(
                'event' => 'foo',
                'priority' => -5,
            ))
        ;

Then the tests suddenly fail as the priorities are lost:

There was 1 failure:

1) Symfony\Bridge\Doctrine\Tests\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPassTest::testProcessEventListenersWithPriorities
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    0 => 'foo'
-    1 => 'bar'
+    0 => 'bar'
+    1 => 'foo'
 )

@dmaicher
Copy link
Contributor

@chapterjason I proposed a fix here: #22001
Maybe you can try it with my changes?

fabpot added a commit that referenced this issue Mar 17, 2017
…s (dmaicher)

This PR was merged into the 2.7 branch.

Discussion
----------

[Doctrine Bridge] fix priority for doctrine event listeners

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #21977
| License       | MIT
| Doc PR        | -

This fixes handling the priorities for doctrine event listeners. As found out by @chapterjason in #21977 the priority was incorrectly handled as soon as a listener had more than one tag (so listening to multiple events).

With this changes all tagged listeners are globally sorted by priority (using the same stable sort approach as in the later available `PriorityTaggedServiceTrait`) and then added one by one to the event manager.

I also updated the tests a bit as it was not covering all cases.

We also have to extend the docs for it I think as it does not mention the `priority` and `lazy` option at all? http://symfony.com/doc/current/doctrine/event_listeners_subscribers.html

Commits
-------

9d9d4ef [Doctrine Bridge] fix priority for doctrine event listeners
@fabpot fabpot closed this as completed Mar 17, 2017
symfony-splitter pushed a commit to symfony/doctrine-bridge that referenced this issue Mar 17, 2017
…s (dmaicher)

This PR was merged into the 2.7 branch.

Discussion
----------

[Doctrine Bridge] fix priority for doctrine event listeners

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #21977
| License       | MIT
| Doc PR        | -

This fixes handling the priorities for doctrine event listeners. As found out by @chapterjason in symfony/symfony#21977 the priority was incorrectly handled as soon as a listener had more than one tag (so listening to multiple events).

With this changes all tagged listeners are globally sorted by priority (using the same stable sort approach as in the later available `PriorityTaggedServiceTrait`) and then added one by one to the event manager.

I also updated the tests a bit as it was not covering all cases.

We also have to extend the docs for it I think as it does not mention the `priority` and `lazy` option at all? http://symfony.com/doc/current/doctrine/event_listeners_subscribers.html

Commits
-------

9d9d4efb88 [Doctrine Bridge] fix priority for doctrine event listeners
nicolas-grekas added a commit that referenced this issue May 4, 2018
…s (dmaicher)

This PR was merged into the 3.4 branch.

Discussion
----------

[Doctrine Bridge] fix priority for doctrine event listeners

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #21977
| License       | MIT
| Doc PR        | -

As discussed in #27126 this ports changes from #22001 to 3.4 that were dropped when merging 2.8 into 3.2 here: dc66960#diff-27d2e9b071d766df504c3fe4131e7abf

I took my original changeset from 2.8 and applied all commits since then on top of that.

Commits
-------

b3ac938 [Doctrine Bridge] fix priority for doctrine event listeners
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants