中间件中的Slim-PHP路由

中间件中的Slim-PHP路由,php,middleware,slim,Php,Middleware,Slim,在Slim中,是否可以在中间件中获取当前路由 class Auth extends \Slim\Middleware{ public function call(){ $currentRoute = $this->app->getRoute(); // Something like this? } } 我知道在调用slim.before.dispatch钩子之后,可以调用$app->router()->getCurrentRoute(),但当您从中间件调用此钩子时

在Slim中,是否可以在中间件中获取当前路由

class Auth extends \Slim\Middleware{
  public function call(){ 
    $currentRoute = $this->app->getRoute(); // Something like this?
  }
}

我知道在调用
slim.before.dispatch
钩子之后,可以调用
$app->router()->getCurrentRoute()
,但当您从中间件调用此钩子时,它返回一个非对象。任何帮助都将不胜感激。

是和否。如果您查看Slim的源代码,您将看到,当调用
Slim::run
方法时,注册的中间件将按后进先出顺序调用,然后Slim在开始处理请求的地方运行自己的“call”方法。正是在这种方法中,Slim解析并处理路由。在这种情况下,您无法在
中间件::call
方法中访问
$app->router()->getCurrentRoute()
,因为尚未对其进行解析和定义

唯一的方法是在中间件中的
slim.before.dispatch
上注册一个监听器,并在该方法中实现您想做的任何事情

根据类的名称,我假设您正在尝试创建一个基本的身份验证模块?我以前也做过类似的事情,事情是这样的:

class AuthMiddleware extends \Slim\Middleware
{
    public function call()
    {
        $this->app->hook('slim.before.dispatch', array($this, 'onBeforeDispatch'));

        $this->next->call();
    }

    public function onBeforeDispatch()
    {
        $route = $this->app->router()->getCurrentRoute();

        //Here I check if the route is "protected" some how, and if it is, check the
        //user has permission, if not, throw either 404 or redirect.

        if (is_route_protected() && !user_has_permission())
        {
            $this->app->redirect('/login?return=' . urlencode(filter_input(INPUT_SERVER, 'REQUEST_URI')));
        }
    }
}
在本例中,
onBeforeDispatch
方法将在调用路由处理程序之前运行。如果您查看源代码,可以看到事件是在一个
try/catch
块中触发的,该块正在侦听由
$app->redirect()
$app->pass()
等引发的异常。这意味着我们可以在这里实现检查/重定向逻辑,就像这是一个路由处理程序函数一样


上面的
是受保护的
用户\u有权限
都是用来说明我的身份验证中间件是如何工作的伪代码。我构造了该类,以便您可以为中间件构造函数中受保护的路由指定路由列表或正则表达式,以及传递实现用户权限检查的服务对象等。希望这有所帮助。

您应该使用app->request()->getPathInfo()而不是app->getRoute()


有另一种方法可以做到这一点,因为我也遇到过同样的情况。我想避免的是按路线匹配任何内容,而是想使用路线名称,因此您可以尝试以下操作:

public function call() {

    $routeIWantToCheckAgainst = $this->slimApp->router()->urlFor('my.route.name');
    $requestRoute = $this->slimApp->request()->getPathInfo();
    if ($routeIWantToCheckAgainst !== $requestRoute) {
        // Do stuff you need to in here
    }

    $this->next->call();
}

您甚至可以有一个不希望中间件运行的路由数组,然后只需检查它是否在_array()等中,如果不在,则执行您需要的操作。

不错的一个。谢谢你简洁的解决方案和详细的解释。在中间件的call()函数中注册钩子是一个好地方吗?这似乎是因为它保持了它的整洁,只是想知道这是否会导致钩子被注册/调用不止一次?我认为可以安全地假设调用方法在每个请求中只被调用一次。实际上,这取决于链中前一个中间件的实现,因为设计使用一个单独的链表,每个中间件在其中调用下一个中间件。如果一个中间件调用了两次链中的下一个调用方法,尽管我认为它做得不对™ 您可能应该停止使用它:)。
public function call() {

    $routeIWantToCheckAgainst = $this->slimApp->router()->urlFor('my.route.name');
    $requestRoute = $this->slimApp->request()->getPathInfo();
    if ($routeIWantToCheckAgainst !== $requestRoute) {
        // Do stuff you need to in here
    }

    $this->next->call();
}