Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 2: Disable Doctrine event listener in ContainerAwareCommand

I am using several Doctrine listeners registered in configuration file for some automatic updates (created_on, updated_on timestamps etc.). Currently I have implemented additional functionality that requires stashing prepared values in the database for easier searching.

I am thinking about update Symfony command that would prepare these values instead of SQL update script (actually any sort of change or update in the way the value is crated would than require just running this single command). However this would also trigger the EventListeners mentioned earlier.

Is there a way how to disable particular EventLister for single Command?

like image 734
Wolfer Avatar asked Jun 22 '16 07:06

Wolfer


3 Answers

something like this should do the trick :

$searchedListener = null;
$em = $this->getDoctrine()->getManager();
foreach ($em->getEventManager()->getListeners() as $event => $listeners) {
    foreach ($listeners as $key => $listener) {
        if ($listener instanceof ListenerClassYouLookFor) {
            $searchedListener = $listener;
            break 2;
        }
    }
}
if ($searchedListener) {
    $evm = $em->getEventManager();
    $evm->removeEventListener(array('onFlush'), $searchedListener);
}
else { //listener not found

}
like image 125
Sylvain Guilbert Avatar answered Nov 14 '22 01:11

Sylvain Guilbert


In services.yaml I have my listener defined this way:

services: 
    App\EventListener\DoctrinePostUpdateListener:
        tags:
            - { name: doctrine.event_listener, event: postUpdate }

To my listener class I added private variable $enabled with condition to stop execution:

class DoctrinePostUpdateListener
{
    private $enabled = true;    

    public function postUpdate(LifecycleEventArgs $args) 
    {
        if ($this->enabled === false) { //stop execution
            return;
        }

        .. your code to execute ..

        return;
    }

    public function setEnabled(bool $enabled)
    {
        $this->enabled = $enabled;
    }

}

and then in my service/controller code where I don't want to execute this listener I just set this $enable variable to false:

    $listeners = $this->em->getEventManager()->getListeners('postUpdate');
    foreach ($listeners as $key => $listener) {
        if ($listener instanceof DoctrinePostUpdateListener) {
            $listener->setEnabled(false);
            break;
        }
    }
like image 32
bepe Avatar answered Nov 14 '22 03:11

bepe


It make more sense to wrap the logic inside Doctrine listener around a:

if ($this->enabled) {

So everyone can understand that the logic can be disabled or not.

You could use a parameter to enable or not the code (see http://symfony.com/doc/current/service_container/parameters.html).

my_doctrine_listener_enabled: true

You set it to false in your command:

$container->setParameter('my_doctrine_listener_enabled', false);

Since the parameter is modified at runtime, I recommend you to not use it via DIC but via

$container->getParameter('my_doctrine_listener_enabled')

Or another approach, could be:

  1. Create variable "enabled" inside Doctrine listener
  2. Inject Doctrine listener in command
  3. Set $this->myListener->enabled = false
like image 2
Thomas Decaux Avatar answered Nov 14 '22 02:11

Thomas Decaux