手动触发404错误

时间:2014-08-29 08:08:13

标签: zend-framework2

我一直在努力从另一个控制器监听器中手动触发dispatch.error

目标是引发404错误,其中路由参数无效并被标准Zend\Mvc\View\Http\RouteNotFoundStrategy“捕获”,以便呈现404页面。

public function FooController extends AbstractActionController
{
    protected $foo;

    public function getEventManager()
    {  
        $em = parent::getEventManager();

        // Attach with higher priority than dispatched indexAction
        $em->attach('dispatch', array($this, 'getFooFromRouteParam'), 10);
    }

    public function indexAction()
    {
        $foo = $this->getFoo(); // Error 500 (not 400)
    }

    public function getFooFromRouteParam(EventInterface $event)
    {
        $id = $this->params('id', false);

        if (! empty($id)) {

            $foo = $this->aDatabaseService->loadFromTheDatabase($id);

            if ($foo instanceof Foo) {

                $this->setFoo($foo);
                return;
            }
        }

        $response = $event->getResponse();

        $response->setStatusCode(404);
        $event->setError(\Zend\Mvc\Application::ERROR_ROUTER_NO_MATCH);

        $event->getApplication()
              ->getEventManager()
              ->trigger('dispatch.error', $event);

        //return $response;
    }

    public function getObjectFoo()
    {
        if (null == $this->foo) {
            throw new \RuntimeException('foo not set');
        }
        return $this->foo;
    }

    public fucntion setObjectFoo(Foo $object)
    {
        $this->foo = $object;
    }
}

事件被正确触发,调试它们给了我:

  

CALLED Zend\Mvc\View\Http\RouteNotFoundStrategy::detectNotFoundError(错误为:error-controller-not-found

     

CALLED Zend\Mvc\View\Http\RouteNotFoundStrategy::prepareNotFoundViewModel    CALLED Zend\Mvc\View\Http\RouteNotFoundStrategy::injectNotFoundReason

然而,在给出一个没有身体的404之后返回响应。

return $response; // ends execution with 404 but no body, just white screen.

如果我没有返回响应,则调度继续,我收到500错误

  

RuntimeException'foo not set'

如何手动触发404错误并正确呈现404模板?

3 个答案:

答案 0 :(得分:1)

我认为你不能,也不应该。当你在控制器中时,路由器已经完成了它的工作,所以回到Zend\Mvc\View\Http\RouteNotFoundStrategy将不起作用。

你应该做的是在路线中制作所需的参数,这样路由器就会为你做检查。

如果你已经考虑过这个问题,但仍想对请求处理错误使用404响应,请看看实际的DispatchListener如何处理它:

$event->setError($application::ERROR_EXCEPTION)
      ->setController($controllerName)
      ->setParam('exception', $exception);

$events  = $application->getEventManager();
$results = $events->trigger(MvcEvent::EVENT_DISPATCH_ERROR, $event);
$return  = $results->last();
if (! $return) {
    $return = $event->getResult();
}

答案 1 :(得分:1)

最后成功解决了这个问题。

Zend\Mvc\Controller\AbstractController方法期望在停止执行控制器事件之前返回Response

这是dispatch方法的相关部分。

$result = $this->getEventManager()->trigger(MvcEvent::EVENT_DISPATCH, $e, 
    function ($test) {
        return ($test instanceof Response);
    }
);

if ($result->stopped()) {
    return $result->last();
}

return $e->getResult();

我需要做的是返回我的结果(这是错误视图模型)并手动停止事件传播(以确保未执行剩余的控制器操作)

// Set the event's 'error' vars
$event->setError(Application::ERROR_EXCEPTION);
$event->setParam('exception', new \Exception('A custom error message here'));

// Trigger the dispatch.error event
$event->getApplication()
      ->getEventManager()
      ->trigger(MvcEvent::EVENT_DISPATCH_ERROR, $event);

// The missing piece! Required to ensure the remaining dispatch 
// listeners are not triggered
$event->stopPropagation(true);

// Contains the view model that was set via the ExceptionStrategy
return $event->getResult();

答案 2 :(得分:1)

对于Zend Framework 3

在Controller中手动分析404并在错误监听器中获取它:

public function articleAction()
{
    // For eg. if we can not found article fetched by url_slug
    if(!$article){
        $this->getResponse()->setStatusCode(404);
        $this->getEvent()->setName(MvcEvent::EVENT_DISPATCH_ERROR);
        $this->getEvent()->getApplication()->getEventManager()->triggerEvent($this->getEvent());

        return false;
    }

    return ['article' => $article];
}
相关问题