我可以使用 Lumen 在中间件中获取当前路线信息吗?
Can I get current route information in middleware with Lumen?
我需要在中间件中包含当前找到的控制器和操作,以便我可以进行一些身份验证。但我发现这是不可能的,因为管道就像 Middleware1 -> Middleware2-> 执行调度 -> controller@action() -> Middleware2 -> Middleware1。
因此在调度之前,我无法获取路线信息。在 $controller->action() 之后做肯定是不对的。
我做了一些研究并发现了这个。
$allRoutes = $this->app->getRoutes();
$method = \Request::getMethod();
$pathInfo = \Request::getPathInfo();
$currentRoute = $allRoutes[$method.$pathInfo]['action']['uses'];
但这在访问像 app/role/1
这样的 URI 时不起作用,因为 $allRoutes
只有 app/role/{id}
的索引而不是 app/role/1
。
有什么解决方法吗?
经过一些研究,我得到了解决方案。他们开始了:
创建自定义调度程序
首先,您必须制作自己的自定义调度程序,我的是:
App\Dispatcher\GroupCountBased
存储为:
app/Dispatcher/GroupCountBased.php
这里是GroupCountBased
的内容:
<?php namespace App\Dispatcher;
use FastRoute\Dispatcher\GroupCountBased as BaseGroupCountBased;
class GroupCountBased extends BaseGroupCountBased
{
public $current;
protected function dispatchVariableRoute($routeData, $uri) {
foreach ($routeData as $data) {
if (!preg_match($data['regex'], $uri, $matches)) continue;
list($handler, $varNames) = $data['routeMap'][count($matches)];
$vars = [];
$i = 0;
foreach ($varNames as $varName) {
$vars[$varName] = $matches[++$i];
}
// HERE WE SET OUR CURRENT ROUTE INFORMATION
$this->current = [
'handler' => $handler,
'args' => $vars,
];
return [self::FOUND, $handler, $vars];
}
return [self::NOT_FOUND];
}
}
在 Laravel 容器中注册您的自定义调度程序
然后,通过 singleton()
方法注册您自己的自定义调度程序。在注册所有路线后执行此操作!就我而言,我在此行之后的 bootstrap/app.php
中添加了自定义调度程序:
require __DIR__.'/../app/Http/routes.php';
这是它的样子:
/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/
require __DIR__.'/../app/Http/routes.php';
// REGISTER YOUR CUSTOM DISPATCHER IN LARAVEL CONTAINER VIA SINGLETON METHOD
$app->singleton('dispatcher', function () use ($app) {
return FastRoute\simpleDispatcher(function ($r) use ($app) {
foreach ($app->getRoutes() as $route) {
$r->addRoute($route['method'], $route['uri'], $route['action']);
}
}, [
'dispatcher' => 'App\Dispatcher\GroupCountBased',
]);
});
// SET YOUR CUSTOM DISPATCHER IN APPLICATION CONTEXT
$app->setDispatcher($app['dispatcher']);
调用中间件(更新)
NOTE: I understand it's not elegant, since dispatch
called after middleware executed, you must dispatch your dispatcher manually.
在你的中间件中,在你的 handle
方法中,这样做:
app('dispatcher')->dispatch($request->getMethod(), $request->getPathInfo());
示例:
public function handle($request, Closure $next)
{
app('dispatcher')->dispatch($request->getMethod(), $request->getPathInfo());
dd(app('dispatcher')->current);
return $next($request);
}
用法
获取当前路线:
app('dispatcher')->current;
我找到了这个问题的正确答案。我错过了一种名为 routeMiddleware()
的方法 Application
。此方法注册在调度后调用的特定于路由的中间件。所以只需使用 $app->routeMiddleware()
来注册你的中间件。并在你的中间件中通过 $request->route()
获取匹配的路由信息。
$methodName = $request->getMethod();
$pathInfo = $request->getPathInfo();
$route = app()->router->getRoutes()[$methodName . $pathInfo]['action']['uses'];
$classNameAndAction = class_basename($route);
$className = explode('@', $classNameAndAction)[0];
我需要在中间件中包含当前找到的控制器和操作,以便我可以进行一些身份验证。但我发现这是不可能的,因为管道就像 Middleware1 -> Middleware2-> 执行调度 -> controller@action() -> Middleware2 -> Middleware1。
因此在调度之前,我无法获取路线信息。在 $controller->action() 之后做肯定是不对的。
我做了一些研究并发现了这个。
$allRoutes = $this->app->getRoutes();
$method = \Request::getMethod();
$pathInfo = \Request::getPathInfo();
$currentRoute = $allRoutes[$method.$pathInfo]['action']['uses'];
但这在访问像 app/role/1
这样的 URI 时不起作用,因为 $allRoutes
只有 app/role/{id}
的索引而不是 app/role/1
。
有什么解决方法吗?
经过一些研究,我得到了解决方案。他们开始了:
创建自定义调度程序
首先,您必须制作自己的自定义调度程序,我的是:
App\Dispatcher\GroupCountBased
存储为:
app/Dispatcher/GroupCountBased.php
这里是GroupCountBased
的内容:
<?php namespace App\Dispatcher;
use FastRoute\Dispatcher\GroupCountBased as BaseGroupCountBased;
class GroupCountBased extends BaseGroupCountBased
{
public $current;
protected function dispatchVariableRoute($routeData, $uri) {
foreach ($routeData as $data) {
if (!preg_match($data['regex'], $uri, $matches)) continue;
list($handler, $varNames) = $data['routeMap'][count($matches)];
$vars = [];
$i = 0;
foreach ($varNames as $varName) {
$vars[$varName] = $matches[++$i];
}
// HERE WE SET OUR CURRENT ROUTE INFORMATION
$this->current = [
'handler' => $handler,
'args' => $vars,
];
return [self::FOUND, $handler, $vars];
}
return [self::NOT_FOUND];
}
}
在 Laravel 容器中注册您的自定义调度程序
然后,通过 singleton()
方法注册您自己的自定义调度程序。在注册所有路线后执行此操作!就我而言,我在此行之后的 bootstrap/app.php
中添加了自定义调度程序:
require __DIR__.'/../app/Http/routes.php';
这是它的样子:
/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/
require __DIR__.'/../app/Http/routes.php';
// REGISTER YOUR CUSTOM DISPATCHER IN LARAVEL CONTAINER VIA SINGLETON METHOD
$app->singleton('dispatcher', function () use ($app) {
return FastRoute\simpleDispatcher(function ($r) use ($app) {
foreach ($app->getRoutes() as $route) {
$r->addRoute($route['method'], $route['uri'], $route['action']);
}
}, [
'dispatcher' => 'App\Dispatcher\GroupCountBased',
]);
});
// SET YOUR CUSTOM DISPATCHER IN APPLICATION CONTEXT
$app->setDispatcher($app['dispatcher']);
调用中间件(更新)
NOTE: I understand it's not elegant, since
dispatch
called after middleware executed, you must dispatch your dispatcher manually.
在你的中间件中,在你的 handle
方法中,这样做:
app('dispatcher')->dispatch($request->getMethod(), $request->getPathInfo());
示例:
public function handle($request, Closure $next)
{
app('dispatcher')->dispatch($request->getMethod(), $request->getPathInfo());
dd(app('dispatcher')->current);
return $next($request);
}
用法
获取当前路线:
app('dispatcher')->current;
我找到了这个问题的正确答案。我错过了一种名为 routeMiddleware()
的方法 Application
。此方法注册在调度后调用的特定于路由的中间件。所以只需使用 $app->routeMiddleware()
来注册你的中间件。并在你的中间件中通过 $request->route()
获取匹配的路由信息。
$methodName = $request->getMethod();
$pathInfo = $request->getPathInfo();
$route = app()->router->getRoutes()[$methodName . $pathInfo]['action']['uses'];
$classNameAndAction = class_basename($route);
$className = explode('@', $classNameAndAction)[0];