这是您可以使用侦听器捕获的内容,在早期事件 MvcEvent::EVENT_ROUTE 上触发。
我建议使用专门的类和工厂来区分对onBootstrap 函数使用的关注。您可以通过注册和“激活”一个 Listener 类来做到这一点,如下所示:
'listeners' => [
// This makes sure it "gets listened to" from the very start of the application (onBootstrap)
RouteExistsListener::class,
],
'service_manager' => [
'factories' => [
// This is just what you think it is
RouteExistsListener::class => InvokableFactory::class,
],
],
您可以只为此侦听器使用InvokableFactory,因为没有特殊要求。
class RouteExistsListener implements ListenerAggregateInterface
{
/**
* @var array
*/
protected $listeners = [];
/**
* @param EventManagerInterface $events
*/
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
/**
* @param EventManagerInterface $events
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$events->attach(MvcEvent::EVENT_ROUTE, [$this, 'doesRouteExist'], 100);
}
/**
* @param MvcEvent $event
*
* @return void|Response
* @throws Exception
*/
public function doesRouteExist(MvcEvent $event)
{
/** @var TranslatorAwareTreeRouteStack|TreeRouteStack $router */
$router = $event->getRouter();
/** @var Request $request */
$request = $event->getRequest();
/** @var RouteMatch|null $routeExists */
$routeExists = $router->match($request); // Return RouteMatch|null
if ($routeExists instanceof RouteMatch) {
return; // Route exists - nothing to do
}
$url = $router->assemble([], ['name' => 'home']); // Name of your redirect route (ie. not_found/404, or something)
/** @var Response $response */
$response = $event->getResponse();
$response->getHeaders()->addHeaderLine('Location', $url);
$response->setStatusCode(302);
$response->sendHeaders();
$event->getApplication()->getEventManager()->attach(
MvcEvent::EVENT_ROUTE,
function (MvcEvent $event) use ($response) {
$event->stopPropagation();
return $response;
},
-10000
);
return $response;
}
}
注意: 使用我自己的现有类进行上述操作,并按照我认为应该可以工作的方式进行了修改。但是,可能包含一两个错误;-) 不过,我认为应该为您指明正确的方向。