你如何分离RouteNotFoundStrategy

时间:2014-01-31 21:07:22

标签: php zend-framework2

默认情况下,如果响应状态代码设置为404,ZF2将呈现404页面。

给出以下代码:

/** @var \Zend\Http\Response $response */
$response = $this->getResponse();
$response->setStatusCode( 404 );

$posts = null;
/**
 * If we have a slug, try to load posts by the author.
 */
if( $this->params( 'slug' ) )
{
    $posts = $this->postService->findMoreByAuthorSlug( $slug, 5 );   
}

$vm = new ViewModel( compact( 'posts' ) );
$vm->setTemplate( 'posts/notfound' );

return $vm;

Zf2的RouteNotFoundStrategy将拦截ViewModel并将其替换为可自定义的404。

有没有办法阻止这种情况?

我们试过像这样分开它:

    $sm = $this->getServiceLocator();
    /** @var \Zend\EventManager\EventManager $eventManager */
    $eventManager = $sm->get('Application')->getEventManager();

    /** @var \Zend\Mvc\View\Http\ViewManager $viewManager */
    $viewManager = $sm->get('HttpViewManager');

    $viewManager->getRouteNotFoundStrategy()->detach( $eventManager );
    $eventManager->detach( $viewManager->getRouteNotFoundStrategy() );

由\ Zend \ Mvc \ View \ Http \ ViewManager:

注册
    $routeNotFoundStrategy   = $this->getRouteNotFoundStrategy();
    $exceptionStrategy       = $this->getExceptionStrategy();
    $mvcRenderingStrategy    = $this->getMvcRenderingStrategy();
    $createViewModelListener = new CreateViewModelListener();
    $injectTemplateListener  = new InjectTemplateListener();
    $injectViewModelListener = new InjectViewModelListener();

    $this->registerMvcRenderingStrategies($events);
    $this->registerViewStrategies();

    $events->attach($routeNotFoundStrategy);
    $events->attach($exceptionStrategy);
    $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($injectViewModelListener, 'injectViewModel'), -100);
    $events->attach(MvcEvent::EVENT_RENDER_ERROR, array($injectViewModelListener, 'injectViewModel'), -100);
    $events->attach($mvcRenderingStrategy);

    $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, array($createViewModelListener, 'createViewModelFromArray'), -80);
    $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, array($routeNotFoundStrategy, 'prepareNotFoundViewModel'), -90);

修改

策略检查控制器是否返回响应或视图模型。以下内容可行,但我不想在控制器中呈现html。

    $vm = new ViewModel();
    $vm->setVariables( compact( 'posts' ) );
    $vm->setTemplate( 'posts/notfound' );
    $viewRender = $this->getServiceLocator()->get( 'ViewRenderer' );
    $layout     = new ViewModel();
    $layout->setTemplate( "layout/main" );
    $layout->setVariable( "content", $viewRender->render( $vm ) );

    $response->setContent( $viewRender->render( $layout ) );

    return $response;

1 个答案:

答案 0 :(得分:1)

好的,看起来共享事件的回调处理程序由于某种原因未存储在聚合侦听器(RouteNotFoundStrategy)中。所以,你仍然可以删除策略,但它有点hacky:

<?php

namespace App;

use Zend\Mvc\MvcEvent;
use Zend\Stdlib\CallbackHandler;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        if (PHP_SAPI == 'cli')
        {
            return;
        }

        $app = $event->getApplication();
        $services = $app->getServiceManager();
        $events = $app->getEventManager();
        $sharedEvents = $events->getSharedManager();

        $listener = $services->get('Zend\Mvc\View\RouteNotFoundStrategy');
        $events->detach($listener);

        /** @var CallbackHandler[] $handlers */
        $handlers = $sharedEvents->getListeners('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH);
        foreach ($handlers as $handler)
        {
            $callback = $handler->getCallback();
            if (is_array($callback) && $callback[0] === $listener)
            {
                $sharedEvents->detach('Zend\Stdlib\DispatchableInterface', $handler);
            }
        }
    }
}