Reputation: 33148
I'm working on an application which uses a REST API backend. This API has a login step which creates a token used for all subsequent API requests. I store this token in the auth storage, and I have an event hook that checks if the user is logged in, and if not, renders the login page:
$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);
This works great.
The API also sometimes expires the login tokens in a way that I can't easily predict, which means all API calls will return a 'Session expired' type error. I've written an event trigger after the API calls that I can hook into. I want to check for these 'session expired' responses and somehow render the login page in the same way I do above:
$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);
but since this isn't an MVC event, even if I could access the response object here, returning it wouldn't do anything. What would be the best way to interrupt the application flow in a non-MVC event?
Upvotes: 1
Views: 110
Reputation: 686
I'm not sure but I'm assuming that your API events do occur in a dedicated EventManager
instance (so your API may be an implementation of EventManagerAwareInterface
) and not in the MVC one (which is the one you grab from the Zend\Mvc\Application
instance).
If that's the case, you could inject both the main EventManager
and the MvcEvent
inside your API, and then short circuit the MVC cycle from the call
listener.
I.e. assume your dependencies are in $mvcEvent
and $mvcEventManager
properties with getters, this is how you would listen for the call
event:
$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);
There are better ways to do it for sure, choosing the best will depend on the architecture of your API class.
You could use Zend\EventManager\ResponseCollection
returned by your trigger, rather than using the MVC event inside the listener; that would enable your API event cycle to continue even if some error occurs. That's actually how Zend\Mvc\Application
uses its own event manager in the run()
method, so you can peek at that for an example.
Upvotes: 1