Question

Is there a way to listen to the "dispatch" event of forwarded controllers?

ControllerA.php

class ControllerA extends AbstractActionController
{
    public function forwardAction()
    {        
        $return = $this->forward()->dispatch('ControllerB'));
        return $return;
    }
}

ControllerB.php

class ControllerB extends AbstractActionController
{
    public function indexAction()
    {        
        return "forwarded";
    }
}

Module.php

public function onBootstrap(\Zend\Mvc\MvcEvent $e)
{
    $application = $e->getApplication();
    $eventManager = $application->getEventManager();

    $eventManager->attach('dispatch', array(
        $this,
        'onDispatch'
    ));
}

public function onDispatch(Event $event)
{
    $controller = $event->getTarget();
    var_dump(get_class($controller));
}

Output

ControllerA

Expected / Wanted

ControllerA
ControllerB
Was it helpful?

Solution 2

probaly you can achieve something similar creating a parent class to your controlers, and storing dispatched controller names in a field. something like this.

class MyAbstractActionController extends \Zend\Mvc\Controller\AbstractActionController {


public static $dispatched;


public function dispatch(RequestInterface $request, ResponseInterface $response = null) {


    self::$dispatched[]=__CLASS__;
    return parent::dispatch ( $request, $response );
}
}

class ControllerA extends MyAbstractActionController
{
....
}

class ControllerB extends MyAbstractActionController
{
....
}

After the dispatch, you will have an array in MyAbstractActionController::dispatched with the name of all the classes you have been through

please note that i havent tried this code, some errors can be found, and also you need the code in your module to retrieve the list after the dispatch

OTHER TIPS

There are two "correct" ways of attaching events to controllers.

First, in the factory for the controller (you do have a factory, right?!), you can inject the event manager instance and any listeners manually. (This works in part because if you do this, the initializer for the EventManagerAwareInterface will be a no-op, as it will detect an EM instance is already present.)

function ($controllers) {
    $services = $controllers->getServiceLocator();

    $controller = new SomeController();
    $events = $services->get('EventManager');

    // Attaching here at 100; use the priority that makes sense for the listener
    $events->attach('dispatch', $services->get('YourListener'), 100);

    $controller->setEventManager($events);
    return $controller;
}

The above assumes that your listener is a service; you could also just instantiate it, obviously.

The second way, and most often used, is to use the shared event manager:

$sharedEvents = $events->getSharedManager();
$sharedEvents->attach(<identifier or array of identifiers>, 'dispatch', <listener>, <priority>);

In this case, you have to know one or more "identifiers" that are of interest to you. For any controllers extending one of the ZF abstract controllers, the following are always present:

  • Zend\Stdlib\DispatchableInterface
  • Zend\Mvc\Controller\AbstractController

Now, depending on the controller type, you'll have additional identifiers:

  • Normal action controllers also have Zend\Mvc\Controller\AbstractActionController.
  • REST controllers have both the AbstractActionController as well as Zend\Mvc\Controller\AbstractRestfulController.
  • If you're using Apigility, REST resources also have ZF\Rest\RestController.

Finally, on top of those, the default implementation also includes the controller's FQCN as an identifier.

What this does is provide you granularity of attachment. If you attach using the FQCN as an identifier, the listener will only be triggered if that specific controller is invoked! If you attach using Zend\Mvc\Controller\AbstractActionController as an identifier, the listener will be triggered for any AbstractActionController extension! (And attaching to Zend\Stdlib\DispatchableInterface means that any controller that triggers the dispatch event will trigger the listener.)

The dispatch event is triggered only once no matter what. The Forward plugin will not re-initiate the dispatch process (and it doesn't need to). A controller's action is called directly via ->dispatch ().

I am not sure what exactly are you trying to achieve?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top