Silex Route在before()中短路跳过Route但仍在()事件之后执行

时间:2015-11-16 12:28:29

标签: middleware silex

manual表示中间件之前的>可以像这样将路由器短路:

$app->before(function (Request $request) {
    if (...) {
        return new RedirectResponse('/login');
    }
});

我的实现如下:

$app->post( '/push/{id}', function( $id, Request $request, Application $app ) {
    $app['post.data'] = $request->request->all();
})
->assert( 'id', '[a-f\d]{24}' )
->before(function( Request $request, Application $app ){
    $item = $app['mongodb.maps']->findOne([
        '_id' => new MongoId( $request->get('id') )
    ]);
    if( !$item ) {
        return new RedirectResponse( 'http://test.com', 301 );
    } else $app['mapdata'] = $item;
})
->after(function( Request $request, Response $response, Application $app ){
    if( !isset( $app['post.data'] ) ) {
        return new RedirectResponse( 'http://google.com', 301 );
    }
})
->after(function( Request $request, Response $response, Application $app ){
    if( !isset( $app['post.data'] ) ) {
        return new RedirectResponse( 'http://google.com', 301 );
    }
});

如果assert()成功,则before事件获取必要的数据,然后将其传递给全局变量。因为我返回一个重定向,它会跳过路线,但随后会执行after事件。在之后的事件中,我检查是否存在应该在路线中创建的后期数据,因为没有执行该路线会产生错误,即post.data键未被定义。我现在在那里抛出一个重定向,最后重定向。但是我必须在每个after()方法中执行此操作,否则我会得到键未定义的错误。 (它永远不会重定向到test.com)

这是正常的吗?是否有更稳固的方式退出之前并跳过所有其他呼叫?

1 个答案:

答案 0 :(得分:2)

作为documentation states(强调我的):

  

如果之前的中间件返回一个Response对象,请求处理将被短路(下一个中间件将不会运行,也不会运行路由回调),并且Response会立即传递给after中间件< /强>

所以是的,这是正常行为。

我看不到一个简单的方法来做你想做的事。不考虑太多选项可能不是使用默认的after中间件,而是扩展 Silex \ Application 并创建自定义after中间件,检查参数是否存在:

<?php

use Symfony\Component\HttpFoundation\RedirectResponse;
use Silex\Application as SilexApp

class MyApp extends SilexApp
{
    public function myAfter($callback, $priority = 0)
    {
        $app = $this;
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($callback, $app) {
            if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
                return;
            }
            // Make sure that the callback is called when the pre conditions are met
            if (!empty($app['post.data'])) {
                $response = call_user_func($app['callback_resolver']->resolveCallback($callback), $event->getRequest(), $event->getResponse(), $app);
                if ($response instanceof Response) {
                    $event->setResponse($response);
                } elseif (null !== $response) {
                    throw new \RuntimeException('An after middleware returned an invalid response value. Must return null or an instance of Response.');
                }
            }
            else {
                $event->setResponse(new RedirectResponse('http://google.com', 301));
            }
        }, $priority);        
    }
}