foundry icon indicating copy to clipboard operation
foundry copied to clipboard

Remove doctrine event listeners/subscribers temporarily

Open CharloMez opened this issue 3 years ago • 3 comments

I have an issue with some testing cases:

  • When i want to test my doctrine event subscribers in a functional test, I want predefined data to perform a PUT request. My subscribers are fired when i instantiate foundry fixtures, so i could verify nothing with my call.
  • Same for Functional tests on symfony command

So sometimes I would like to store fixtures that goes raw in database, without any listeners on their creation.

Maybe we can already does it, but I didn't found how, So I made a little code snippet for that:

use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\ORM\EntityManagerInterface;

...

    public function withoutDoctrineListeners()
    {
        /** @var EntityManagerInterface $manager */
        $manager = FooFactory::configuration()->objectManagerFor(Foo::class);
        $listeners = $manager->getConnection()->getEventManager()->getListeners();
        foreach ($listeners as $type => $listenersByType) {
            foreach ($listenersByType as $listener) {
                if ($listener instanceof EventSubscriberInterface) {
                    $manager->getConnection()->getEventManager()->removeEventSubscriber($listener);

                    continue;
                }

                $manager->getConnection()->getEventManager()->removeEventListener($type, $listener);
            }
        }
    }

So do you think is it something you can propose in foundry ?

I thought about something like (function name is probably bad):

        FooFactory::new()->withoutDoctrineListeners()->create();

I can submit a pull request if you like the idea

CharloMez avatar Nov 23 '21 16:11 CharloMez

I do like the idea but there are some nuances we need to think about.

When calling your code that actually tests the listeners, do you do anything to put the event listeners "back"?

Here's (I think) 1 problem:

$factory = FooFactory::new()->withoutDoctrineListeners();
$factory->create(); // creates entity without event listeners

// shutdown/restart kernel

$factory->create(); // creates entity WITH event listeners

Here's another:

FooFactory::new()->withoutDoctrineListeners()->create(); // creates entity without event listeners

BarFactory::new()->create(); // also creates entity without event listeners (this is unexpected)

I believe a solution could be:

  1. ->withoutDoctrineListeners() sets a flag on the factory
  2. ->create() checks for flag before creation, if flag set:
    1. Remove listeners/subscribers
    2. do create
    3. Re-add removed listeners/subscribers

kbond avatar Nov 24 '21 12:11 kbond

Yeah I agree with that, we need to put back listeners after creation.
I thought about something else, the function could have an optional argument, "$eventTypeName":

FooFactory::new()->withoutDoctrineListeners(Events::postPersist)->create();

The function "getListeners" have this optional argument, so it would be nice to allow it and follow it to this function.

Do you want to add the feature yourself, or it is ok for you to let me make a pull request for this ?

CharloMez avatar Nov 24 '21 13:11 CharloMez

I thought about something else, the function could have an optional argument, "$eventTypeName":

Sure, makes sense.

or it is ok for you to let me make a pull request for this

Go ahead with a PR if you're willing!

kbond avatar Nov 24 '21 13:11 kbond