Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Register Event Listeners in Configuration File

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on May 18, 2013

zf2-zendframework2Zend Framework 2.2 released. It comes with ton of new features. Now, I will show you how to set event listeners in Configuration File. Event Listeners can be registered in config/application.config.php.

For example, I have a sample listener like this :

//module/YourModule/src/YourModule/Event/MySampleListener.php
namespace YourModule\Event;

use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\EventInterface;

class MySampleListener implements ListenerAggregateInterface
{
    protected $listeners = array();

    public function attach(EventManagerInterface $events)
    {
        $this->listeners[] = $events->attach('eventName', array($this, 'doEvent'));
    }

    public function detach(EventManagerInterface $events)
    {
        foreach ($this->listeners as $index => $listener) {
            if ($events->detach($listener)) {
                unset($this->listeners[$index]);
            }
        }
    }

    public function doEvent(EventInterface $event)
    {
        echo 'param id  = '.$event->getParam('id');
    }
}

Let’s register :
a. in config/application.config.php

return array(
    
    'listeners' => array(
        'MySampleListener'
    ),
    
    // This should be an array of module namespaces used in the application.
    'modules' => array(
        'Application',
        'YourModule', //Your module here 
    ),

    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor',
        ),
        'config_glob_paths' => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
    ),
);

b. register as service at YourModule/config/module.config.php

//module/YourModule/config/module.config.php
return array(    
    'service_manager' => array(
        'invokables' => array(
            'MySampleListener' => 'YourModule\Event\MySampleListener',
        ),
    ),    
    'controllers' => array(
          //other config here...
     ),
    'routes' => array(
         //other config here...
    ),
);

Try calling in Controller :

//module/YourModule/src/YourModule/Controller/IndexController.php
namespace YourModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class IndexController extends AbstractActionController
{  
    public function indexAction()
    {   
       $mysampleListener = $this->getServiceLocator()->get('MySampleListener');
       $this->getEventManager()->attachAggregate($mysampleListener);
       
       $parameter = array('id' => 1); 
       $this->getEventManager()->trigger('eventName', $this, $parameter);
    }
}

Um…, let’s make it separate, attach via Module::onBootstrap :

//module/YourModule/Module.php
namespace YourModule;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $eventManager        = $e->getApplication()->getEventManager();
        $sharedManager = $eventManager->getSharedManager();
        $sm = $e->getApplication()->getServiceManager();

        $sharedManager->attach('Zend\Mvc\Controller\AbstractActionController',  'dispatch', function($e)
                           use ($sm) {
           $controller = $e->getTarget();
           $controller->getEventManager()->attachAggregate($sm->get('MySampleListener'));
        }, 2);
    }

    public function getConfig(){/* common code here */}
    public function getAutoloaderConfig(){ /* common code here */}
}

And you just call in controller by :

//module/YourModule/src/YourModule/Controller/IndexController.php
namespace YourModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
       $parameter = array('id' => 1); 
       $this->getEventManager()->trigger('eventName', $this, $parameter);
    }
}

I got some question about why need to register at config/application.config.php ? It’s to make it callable during onBootstrap(MvcEvent $e) directly by :

$eventManager->trigger('eventName', $this, array('id' => 1));

at the Module.php.

References :
1. https://github.com/zendframework/zf2/pull/3931
2. http://samminds.com/2013/04/understanding-zf2-configuration/
3. http://framework.zend.com/blog/zend-framework-2-2-0-stable-released.html

23 Responses

Subscribe to comments with RSS.

  1. Latch said, on May 19, 2013 at 7:06 pm

    Thanks for article! For what listeners are used in practice?

  2. pradnya999 said, on May 21, 2013 at 7:10 pm

    where to create this MySampleListener class ?there is no event folder in MyModule…do i have to create one?please explain

    • samsonasik said, on May 22, 2013 at 1:17 am

      Look at the namespace. Please read the docs on module section.

      • srushti said, on May 24, 2013 at 6:23 pm

        not clear.i have read modules section of the docs but did not come across something that explains this..can u help me with a link plz..i know that listeners are added in zend/modulemanager/listener..if the namespace is mymoule/event then it must be in that directory..so wanted some clarification..it would be great if u could explain

      • samsonasik said, on May 25, 2013 at 3:09 am

        updated. hopefully help you.

  3. srushti said, on May 25, 2013 at 1:06 pm

    thanks for updating the post and sorry if it caused too much trouble.we turn to blogs for knowledge when we fail to understand the doc.thanks for helping though

  4. Isolde said, on July 26, 2013 at 2:45 am

    Hi, thank you for this good example. I finally got it to work! Thank you again and do keep blogging, I have learned a lot from you.

  5. abarnesuk said, on October 25, 2013 at 4:28 pm

    Hi, thanks for your great worked example.

    One question though, I’m running ZF 2.2.4 and the config array “listeners” doesn’t appear to do anything. As in I have your example working and if I delete that config entry everything still works fine.

    Could you shed any more light on what this array is supposed to be doing:

    ‘listeners’ => array(
    ‘MySampleListener’
    )

    Many thanks

    • samsonasik said, on November 23, 2013 at 8:04 am

      Hi abarnesuk, thanks for pointing that, I’ve updated the post, it should be written at config/application.config.php. by writing that, it to make triggered directly at Module.php at onBootstrap function :

          public function onBootstrap(MvcEvent $e)
          {
              $eventManager        = $e->getApplication()->getEventManager();
              $sharedEventManager  = $eventManager->getSharedManager();
              
              $eventManager->trigger('eventName', $this, array('id' => 1));
          }
      
  6. Robbie said, on November 22, 2013 at 11:43 pm

    Hello i have two questions about your tutorial:

    1. What does ‘listeners’ key in module.config.php? I can’t find any official documentation about that.
    2. How can i prevent adding a closure in module.php’s onBootstrap method? Is there another way to do same thing instead of defining a closure in module.php?

    • samsonasik said, on November 23, 2013 at 8:07 am

      thanks for pointing that, I’ve updated the post, it should be written at config/application.config.php.
      1. by writing that, it to make triggered directly at Module.php at onBootstrap function :

          public function onBootstrap(MvcEvent $e)
          {
              $eventManager        = $e->getApplication()->getEventManager();
              $sharedEventManager  = $eventManager->getSharedManager();
              
              $eventManager->trigger('eventName', $this, array('id' => 1));
          }
      

      You can contribute to make the docs better 🙂 https://github.com/zendframework/zf2-documentation
      2. you can do like this :

          public function onBootstrap(MvcEvent $e)
          {
              $eventManager        = $e->getApplication()->getEventManager();
              $sharedEventManager  = $eventManager->getSharedManager();
              
              $sharedEventManager->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', array($this, 'settingEventController'), 3);
          }
          
          public function settingEventController(MvcEvent $e)
          {
              $controller = $e->getTarget();
              $controller->getEventManager()->attachAggregate($controller->getServiceLocator()->get('MySampleListener'));
          }
      
  7. Văn Khương Vũ said, on December 6, 2013 at 1:32 am

    Hello samsonasik , Can you help me to resolve a little problem with event ?
    I have a chunk of code in my project follow :
    ======================================================
    class Module {
    public function onBootstrap(MvcEvent $e) {
    $eventManager = $e->getApplication()->getEventManager();
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);
    $sharedEvent->attach(‘Test\Controller\IndexController’,[b] MvcEvent::EVENT_RENDER[/b], function($event){
    echo ‘render’;
    });
    }
    ======================================================
    It’s not display “render” . Please help me .
    SELECT `myidol` FROM `persons` WHERE `nameperson` = ‘samsonasik’ .
    Sorry . Im not good english. im a vietnamese

  8. Văn Khương Vũ said, on December 6, 2013 at 1:33 am

    Sorry , please remove tag BBcode [b]

  9. Wil said, on April 25, 2014 at 11:47 pm

    How can call same event via trigger from a service class (instance of ServiceAwareInterface)

  10. Filip Halaxa said, on May 5, 2014 at 5:28 pm

    Thank you for the article. However, I don’t see the benefit of having the MySampleListener service listed in ‘listeners’ config key. Where do you access it? What is it actually good for? I see you retrieving and attaching everything manually anyway and see no usage of the config. I would appreciate your reply. Thank you.

    • samsonasik said, on May 7, 2014 at 12:29 am

      you can directly call the event on onbootstrap, see my last sentences on the post.

      • Filip said, on May 7, 2014 at 2:05 pm

        Thank you. I used wrong term benefit I’m sorry. I meant what does the key actually do. The answer is that all services In ‘listeners’ key are automatically attached in Application->bootstrap(). So I don’t need to attach them manually in Module->onBootstrap, which I see you do in the example above. So I got confused a little. Thank you though.

  11. Rah said, on November 30, 2018 at 7:48 pm

    We have problem :- ZF3 Event Listener Class when extends it start listening same event multiple time

    we have class in ZF3 see below classes when we extend event Listener class. Now when event is triggered, it trigger Event listener multiple time. How to avoid multiple hit to same listener ? We need only trigger event in either base class or Derived Listener as & when loaded for two different modules.

    In File: EventListener
    ————————————————————

    class EventListener implements ListenerAggregateInterface
    {

    protected $listeners = array();

    /**
    * {@inheritDoc}
    */
    public function attach(EventManagerInterface $events)
    {
    $sharedEvents = $events->getSharedManager();
    $this->listeners[] = $sharedEvents->attach([‘TestEventService’], ‘event_change’, array($this, ‘onChangeEvent’));

    }

    public function detach(EventManagerInterface $events)
    {

    }

    public function onChangeEvent(){
    // here some code
    }

    }

    in File: EventListenerExtended
    ————————————————————————-

    class EventListenerExtended extends EventListener
    {

    public function onChangeEvent(){
    //here some code
    }

    }

    in two different modules we have module.php that have triggered:
    ———————————————————————————-
    public function onBootstrap(EventInterface $e)
    {

    $eventManager->attach(new EventListener());
    }

    public function onBootstrap(EventInterface $e)
    {
    $eventManager->attach(new EventListenerExtended());
    }

    • samsonasik said, on December 1, 2018 at 8:26 am

      you can register at ‘dispatch’ event, so it can determine when it executed, eg:

              $controller     = $e->getTarget();
              $controllerName = \get_class($controller);
              $moduleName     = \substr($controllerName, 0, (int) \strpos($controllerName, '\\'));
      
              if ($moduleName === 'Application') {
                  return;
              }
              // execute ...
      

Leave a reply to samsonasik Cancel reply