Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ZF2 how to listen to the dispatch event of a specific controller

How can I listen to the dispatch event of a specific controller? At the moment I do the following:

Module.php

public function onBootstrap(EventInterface $event) {
    $application = $event->getApplication();
    $eventManager = $application->getEventManager();
    $serviceManager  = $application->getServiceManager();

    $eventManager->attach($serviceManager->get('MyListener'));
}

MyListener.php

class MyListener extends AbstractListenerAggregate {

    public function attach(EventManagerInterface $eventManager) {
        $this->listeners[] = $eventManager->attach(
            MvcEvent::EVENT_DISPATCH, function($event) {
                $this->setLayout($event);
            }, 100
        );
    }

    public function setLayout(EventInterface $event) {
        $event->getViewModel()->setTemplate('mylayout');
    }
}

This sets the layout for all controller dispatches. Now I want to set the layout only if the application dispatches a specific controller.

like image 307
Dominik Barann Avatar asked Feb 15 '15 09:02

Dominik Barann


2 Answers

Like all Modules have an onBootstrap() method, all controllers extending AbstractController have an onDispatch() method.

Considering you want to apply a different layout for a single specific controller, you can simply do the following:

<?php

namespace MyModule\Controller;

use Zend\Mvc\Controller\AbstractActionController; // Or AbstractRestfulController or your own
use Zend\View\Model\ViewModel; // Or JsonModel or your own
use Zend\Mvc\MvcEvent;

class MyController extends AbstractActionController
{
    public function onDispatch(MvcEvent $e)
    {
        $this -> layout('my-layout'); // The layout name has been declared somewhere in your config
        return parent::onDispatch($e); // Get back to the usual dispatch process
    }

    // ... Your actions
}

You may do this for every controller that has a special layout. For those who don't, well, you don't have to write anything.

If you often need to change your layout (e.g. you have to handle not a single controller but several), you can attach an MvcEvent in your module.php to get your layout setting code in one place.

To keep things simple, I'm not using a custom listener here, but you may use one as well.

<?php

namespace MyModule;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $eventManager = $e -> getApplication() -> getEventManager();
        $eventManager -> attach(
            MvcEvent::EVENT_DISPATCH,
            // Add dispatch error event only if you want to change your layout in your error views. A few lines more are required in that case.
            // MvcEvent::EVENT_DISPATCH | MvcEvent::EVENT_DISPATCH_ERROR
            array($this, 'onDispatch'), // Callback defined as onDispatch() method on $this object
            100 // Note that you don't have to set this parameter if you're managing layouts only
        );
    }

    public function onDispatch(MvcEvent $e)
    {
        $routeMatch = $e -> getRouteMatch();
        $routeParams = $routeMatch -> getParams();
        switch ($routeParams['__CONTROLLER__']) {
            // You may use $routeParams['controller'] if you need to check the Fully Qualified Class Name of your controller
            case 'MyController':
                $e -> getViewModel() -> setTemplate('my-first-layout');
                break;
            case 'OtherController':
                $e -> getViewModel() -> setTemplate('my-other-layout');
                break;
            default:
                // Ignore
                break;
        }
    }

    // Your other module methods...
}
like image 84
S2HNT Avatar answered Oct 21 '22 22:10

S2HNT


You have to attach your event listener to the SharedEventManager and listen MvcEvent::EVENT_DISPATCH of the "Zend\Stdlib\DispatchableInterface" interface.

See an example:

$eventManager->getSharedManager()
            ->attach(
                'Zend\Stdlib\DispatchableInterface',
                MvcEvent::EVENT_DISPATCH,
                $serviceManager->get('MyListener')
            );

Within your listener you can get the instance of the target controller like so $controller = $event->getTarget();

So, eventually, the method "setLayout" may look like this:

public function setLayout(MvcEvent $event)
{
    $controller  = $event->getTarget();

    if ($controller instanceof MyController)
    {
        $event->getViewModel()->setTemplate('mycontroller-layout');
    }
}
like image 3
Next Developer Avatar answered Oct 21 '22 22:10

Next Developer