Jake
Jake

Reputation: 26117

ZF2 - Make onbootstrap events in one module supersede every other module

I have a ZF2 module called "Browsercheck", when used with other modules, checks the user's browser and shows an "Unsupported Browser" page if the browser is not supported. The issue I am having is, that the following code which is onBootstrap of the "Browsercheck" is not taking the first preference when other modules encounter an exception or a 404 error. IT works otherwise.

How can I make sure this code executes for every event and supersede any other event? Ideally in ZF1, I use code like this in index.php.. but not sure how it should be in ZF2. Basically if the browser is not supported, it shouldn't matter whether it's a 404 or an exception. It should go ahead and render the unsupported browser page.

public function onBootstrap(MvcEvent $e)
{   
    $sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
    $sharedEvents->attach('Zend\Mvc\Controller\AbstractController','dispatch',
    function($event)
    {
        $browser = new \BrowserCheck\Service\BrowserCheck();
        if (!$browser->isCompatible())
        {
            $viewModel = new \Zend\View\Model\ViewModel();
            $viewModel->setTerminal(true);

            $request = $event->getRequest();
            $response = $event->getResponse();


            $viewModel->setTemplate('browser-check/index/index.phtml');
            //Replace the entire view
            $event->setViewModel($viewModel);
            $event->stopPropagation();
            $response->setStatusCode(200);
            return $viewModel;
        }
    });
}

UPDATE:

$browserEventListener = function($event)
    {
        $browser = new \BrowserCheck\Service\BrowserCheck();
        if (!$browser->isCompatible())
        {
            $viewModel = new \Zend\View\Model\ViewModel();
            $viewModel->setTerminal(true);

            $request = $event->getRequest();
            $response = $event->getResponse();

            $viewModel->setTemplate('browser-check/index/index.phtml');

            //Replace the entire view
            $event->setViewModel($viewModel);
            $event->stopPropagation();
            $response->setStatusCode(200);
            return $viewModel;
        }
    };
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEvents->attach('Zend\Mvc\Controller\AbstractController',
  array('dispatch','dispatch.error'), $browserEventListener, 100);

Upvotes: 0

Views: 1131

Answers (1)

shadyyx
shadyyx

Reputation: 16055

The problem here is that you register your event listener on the dispatch event, which occurs after bootstrap and after route events. If the event listener triggered at route event cannot identify the route, you receive a 404 error page and the application lifecycle is terminated before any other dispatch event listener could be invoked.

In order to invoke your event listener before any routing is applied, you now have two options:

  • either register your event listener on bootstrap event with lower prio (e.g. lower than 10000)
  • or to register it on route listener with some higher priority, 10 should be enough

According to ZF2 doc page, onBoostrap() module methods are called with priority 10000 and onRoute() methods of \Zend\Mvc\ModuleRouteListener and \Zend\Mvc\RouteListener are called with priority 1 (higher the number higher the priority).

EDIT:

You should be doing something like this:

public function onBootstrap(MvcEvent $e)
{
    /* ... all the default stuff here ... */


    $this->registerBrowserCheckEvent($e);
}

private function registerBrowserCheckEvent(MvcEvent $e)
{
    $eventManager = $e->getApplication()->getEventManager();
    $browserEventListener = function ($event) {
        $browser = new \BrowserCheck\Service\BrowserCheck();
        if (!$browser->isCompatible()) {
            $viewModel = new \Zend\View\Model\ViewModel();
            $viewModel->setTerminal(true);

            $request = $event->getRequest();
            $response = $event->getResponse();

            $viewModel->setTemplate('browser-check/index/index.phtml');

            //Replace the entire view
            $event->setViewModel($viewModel);
            $event->stopPropagation();
            $response->setStatusCode(200);
            return $viewModel;
        }
    };

    $eventManager->attach(MvcEvent::EVENT_BOOTSTRAP, $browserEventListener, 100);
}

Also please notice that ZF2 uses PSR-2 (at least) and your code should follow this convention as well (mind the small differences between your code and mine).

Upvotes: 0

Related Questions