Slim 3 在中间件中获取当前路由

Slim 3 get current route in middleware

我想在中间件class中获取当前I路由的名称。以前(在 Slim 2.* 中)你可以像这样获取当前路由:

$route = $this->app->router->getCurrentRoute();

但是这个功能在Slim的3.0版本中已经被移除了。我在 Slim\App__invoke 方法中找到了以下代码:

    // Get the route info
    $routeInfo = $request->getAttribute('routeInfo');

    /** @var \Slim\Interfaces\RouterInterface $router */
    $router = $this->container->get('router');

    // If router hasn't been dispatched or the URI changed then dispatch
    if (null === $routeInfo || ($routeInfo['request'] !== [$request->getMethod(), (string) $request->getUri()])) {
        $request = $this->dispatchRouterAndPrepareRoute($request, $router);
        $routeInfo = $request->getAttribute('routeInfo');
    }

这表示当前路由作为属性routeInfo存储在Request中。但似乎我的自定义中间件 class 在设置属性之前被调用(通过 $this->dispatchRouterAndPrepareRoute($request, $router); 方法)。因为调用 $request->getAttribute('routeInfo') 解析为 NULL.

所以我的问题是;如何从中间件 function/class?

获取当前路由(或路由名称)

或者我应该从 Slim\App 复制上面的代码吗?

以下是否为您提供了所需的足够信息,或者您是否还需要 routeInfo 中的 'request' 位?

$app->getContainer()->get('router')->dispatch($req);

如果您还需要 'request' 位,那么您将需要手动执行与 dispatchRouterAndPrepareRoute 相同的操作。

if ($routeInfo[0] === Dispatcher::FOUND) {
            $routeArguments = [];
            foreach ($routeInfo[2] as $k => $v) {
                $routeArguments[$k] = urldecode($v);
            }

            $route = $router->lookupRoute($routeInfo[1]);
            $route->prepare($request, $routeArguments);

            // add route to the request's attributes in case a middleware or handler needs access to the route
            $request = $request->withAttribute('route', $route);
        }

        $routeInfo['request'] = [$request->getMethod(), (string) $request->getUri()];

希望对您有所帮助。

显然,您可以使用以下设置配置 Slim 以在进入中间件之前确定路由:

$app = new Slim\App([
    'settings'  => [
        'determineRouteBeforeAppMiddleware' => true,
    ]
]);

我不确定这会产生什么样的影响,但它对我有用:)

以下是在 Slim 框架 3 的中间件中获取当前路由的方法:

$routeInfo = $request->getAttribute('routeInfo');

请注意,您应该在中间件的 __invoke() 函数中使用它。这是示例用法:

public function __invoke($request, $response, $next)
    {
        ....
        $routeInfo = $request->getAttribute('routeInfo');
        ....
    }

$routeInfo 应包含如下对象:

{
    "0": 1,
    "1": "route6",
    "2": {
      "name": "loremipsum"
    },
    "request": [
      "POST",
      "http://example.org/loremipsum"
    ]
  }

对于 Slim3,这里有一个例子向您展示如何从中间件中获取路由信息,这实际上是前面答案的组合。

<?php

$slimSettings = array('determineRouteBeforeAppMiddleware' => true);

// This is not necessary for this answer, but very useful
if (ENVIRONMENT == "dev")
{
    $slimSettings['displayErrorDetails'] = true;
}

$slimConfig = array('settings' => $slimSettings);
$app = new \Slim\App($slimConfig);


$myMiddleware = function ($request, $response, $next) {

    $route = $request->getAttribute('route');
    $routeName = $route->getName();
    $groups = $route->getGroups();
    $methods = $route->getMethods();
    $arguments = $route->getArguments();

    print "Route Info: " . print_r($route, true);
    print "Route Name: " . print_r($routeName, true);
    print "Route Groups: " . print_r($groups, true);
    print "Route Methods: " . print_r($methods, true);
    print "Route Arguments: " . print_r($arguments, true);
};

// Define app routes
$app->add($myMiddleware);


$app->get('/', function (\Slim\Http\Request $request, Slim\Http\Response $response, $args) {
    # put some code here....
})

在我的例子中,我想添加中间件来确保用户在某些路由上登录,如果没有,则将他们重定向到登录页面。我发现最简单的方法是在这样的路线上使用 ->setName()

$app->get('/', function (\Slim\Http\Request $request, Slim\Http\Response $response, $args) {
    return $response->withRedirect('/home');
})->setName('index');

那么如果这条路由被匹配,中间件示例中的$routeName将是"index"。然后我定义了不需要身份验证的路由数组列表,并检查当前路由是否在该列表中。例如。

if (!in_array($routeName, $publicRoutesArray))
{
    # @TODO - check user logged in and redirect if not.
}
$request->getUri()->getPath()

获取当前路线,即使在 middleware