中断来自非MVC事件的应用程序流

时间:2013-10-30 10:43:40

标签: zend-framework2

我正在开发一个使用REST API后端的应用程序。此API具有登录步骤,该步骤创建用于所有后续API请求的令牌。我将此令牌存储在auth存储中,并且我有一个事件挂钩,用于检查用户是否已登录,如果没有,则呈现登录页面:

$eventManager->attach(MvcEvent::EVENT_ROUTE, function($e) use ($view, $auth) {
    $match = $e->getRouteMatch();

    // No route match, this is a 404
    if (!$match instanceof RouteMatch) {
        return;
    }

    // Route is whitelisted
    $matchedRoute = $match->getMatchedRouteName();
    if (in_array($matchedRoute, array('login'))) {
        return;
    }

    // if they're logged in, all is good
    if ($auth->hasIdentity()) {
        return true;
    }

    [render login form and return response object]
}, -100);

这很有效。

API有时也会以我无法轻易预测的方式过期登录令牌,这意味着所有API调用都将返回“会话过期”类型错误。我在API调用之后写了一个事件触发器,我可以挂钩。我想检查这些“会话过期”响应,并以某种方式呈现登录页面,方法与上面相同:

$events->attach('Api', 'call', function ($e) {
    $api = $e->getTarget();
    $params = $e->getParams();

    $result = $params['apiResult'];

    if ([result is a session expired response]) {
        // what can I do here?
    }

}, 999);

但由于这不是MVC事件,即使我可以在这里访问响应对象,返回它也不会做任何事情。什么是在非MVC事件中中断应用程序流的最佳方法?

1 个答案:

答案 0 :(得分:1)

我不确定,但我假设您的API事件确实发生在专用的EventManager实例中(因此您的API可能是EventManagerAwareInterface的实现)而不是MVC实例(你从Zend\Mvc\Application实例中获取的那个。

如果是这种情况,您可以在API中注入主EventManagerMvcEvent,然后从call侦听器中短路MVC周期。

即。假设您的依赖项位于带有getter的$mvcEvent$mvcEventManager属性中,这就是您监听call事件的方式:

$events->attach('call', function($e) {
    $api = $e->getTarget();
    $params = $e->getParams();

    $result = $params['apiResult'];

    if ([result is a session expired response]) {
        $mvcEvent = $api->getMvcEvent();
        $mvcEvent->setError('api error');
        $mvcEvent->setParam('exception', new \Exception('Session expired'));
        $api->getMvcEventManager()->trigger('dispatch.error', $mvcEvent);
    }

}, 999);

有更好的方法可以做到这一点,选择最佳方式取决于API类的体系结构。

您可以使用触发器返回的Zend\EventManager\ResponseCollection,而不是在侦听器中使用MVC事件;这将使您的API事件周期继续,即使发生一些错误。这实际上是Zend\Mvc\Applicationrun()方法中使用自己的事件管理器的方式,因此您可以查看示例。