gregthegeek
gregthegeek

Reputation: 1423

Zend Framework 2 How to disable event listeners in multiple MVC modules

I have two MVC modules I am trying to build, one (FBWsrv) with JSON output and different security process, and the main MVC module for normal web use (FBWeb). I have the routes all setup and mostly working. The problem I am running into is they both have onBootstrap methods that attach their own event listeners and I would like to disable listeners if not in the correct MVC module.

My routes look like so:

Module FBWeb, the "app" module in url:

/app/controller/action/par1/val1

Module FBWsrv, which is "wsrv" in url:

/wsrv/controller/action/par1/val1

As I mentioned, the route are working fine. I get to the correct controller and action. But the problem is the MVC event listeners are running on both modules, when I am not even running /app from the /wsrv route. What I want to do is disable the events in /app if I am in /wsrv.

The short version of the modules are setup like so:

FBWeb/Module.php:

class Module 
{

    public function onBootstrap(MvcEvent $e)
    {

        $this->sm = $application->getServiceManager();
        $this->config = $e->getApplication()->getConfig();

        $eventManager        = $e->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);

        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'addInstanceObjects'), 5000 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'securityDispatch'), 0 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'preDispatch'), 100 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'postDispatch'), -100 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), -5000);

    }

FBWsrv/Module.php:

class Module 
{
    public function onBootstrap(MvcEvent $e)
    {

        $this->sm = $application->getServiceManager();
        $this->config = $e->getApplication()->getConfig();
        $eventManager        = $e->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);

        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'addWsrvInstanceObjects'), 5900 );
        //$eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'securityWsrvDispatch'), 5800 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'preWsrvDispatch'), 5500 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'postWsrvDispatch'), 5400 );
        $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onWsrvDispatchError'), 5100);

    }

I have the securityWsrvDispatch disabled in FBWsrv as I test things, but I want it running its own process later. For now, I just need to detach the FBWeb events if I am running in FBWsrv as they have no relevance. I know they are all running because errors show up in the opposite module. Not sure how to do this.

Thanks for any help!

Greg

EDIT/NOTES: I also tried adding a simple check for NAMESPACE before attaching the listeners, but it seems that both namespaces are always called, which creates the listeners for both modules, even when only one is desired. How do you isolate them? I tried this, which doesn't work:

if(__NAMESPACE__ == 'FBWeb'){
            $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'addInstanceObjects'), 5000 );
         ...

A var_dump(__NAMESPACE__); always shows both namespaces printed.

EDIT - A bit of a workaround

First, thanks Andrew, you sparked some idea's I am going to work into the project. But, while I am learning, I solved my primary problem by checking the route, and then simply returning from the function if it doesn't match, skipping any additional setup in the module.

I also consolidated my dispatch events, which lessened my confusion. There really wasn't any need for the extra mess. I know this isn't the right way , but it did solve my problem.

(you must have routes setup named 'fbweb' and 'fbwsrv' to match your modules, of course)

In FBWeb/Module.php:

// in FBWeb/Module.php
// (default web MVC module)

public function onBootstrap(MvcEvent $e)
{
    // ... get eventmanager ...

    $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'preDispatch'), 1000 );
    $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), -5000);

}

public function preDispatch(MvcEvent $e)
{
    $this->route = $e->getRouteMatch();
    $this->matchedRouteName = explode('/', $this->route->getMatchedRouteName());
    $this->route_root = $this->matchedRouteName[0];

    // then just test if not in correct route
    if($this->route_root != 'fbweb'){
        // if NOT, bail here, 
        // and skip any other setup in this module dispatch
        return;
    }

    // continue other normal stuff (ACL's, session stuff, etc)
    // ...

}

In my other module: FBWsrv/Module.php:

// in FBWsrv/Module.php

public function onBootstrap(MvcEvent $e)
{
    // ... get eventmanager ...

    $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'preDispatch'), 5500 );
    $eventManager->attach( \Zend\Mvc\MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), -4900);

}

public function preDispatch(MvcEvent $e)
{
    $this->route = $e->getRouteMatch();
    $this->matchedRouteName = explode('/', $this->route->getMatchedRouteName());
    $this->route_root = $this->matchedRouteName[0];
    // then just test if not in correct route
    if($this->route_root != 'fbwsrv'){
        // if NOT, bail here, 
        // and skip any other setup in this module dispatch
        return;
    }

    // continue other normal stuff (ACL's, session stuff, etc)
    // ...

}

Upvotes: 2

Views: 2226

Answers (1)

Andrew
Andrew

Reputation: 12809

Why don't you attach your events using a context via the shared event manager, there's plenty of docs out there helping with shared events manager.

/**
 * On bootstrap event
 * 
 * @param \Zend\Mvc\MvcEvent $e
 */
public function onBootstrap(MvcEvent $e)
{
    // .. other stuff

    /**
     * Example attaching events with shared manager, using context
     */
    $e->getApplication()->getEventManager()->getSharedManager()
        ->attach('MyModule\Controller\AbstractActionController', 'dispatch', function($e) {

        // do something to only be triggerd when dispatch is triggered
        // on a controller extending your nice base controller in this module..

    }, 100);
}

Upvotes: 5

Related Questions