Могу ли я получить текущую информацию о маршруте в промежуточном программном обеспечении с помощью 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'];

Но это не работает при посещении URI типа app/role/1, потому что $allRoutes имеет только индекс app/role/{id} вместо app/role/1.

Есть ли обходной путь по этому поводу?


person JasonW    schedule 01.06.2015    source источник
comment
Какая информация вам нужна?   -  person peterm    schedule 03.06.2015
comment
@peterm Мне нужно получить информацию о согласованном маршруте, включая имя контроллера, имя действия, в промежуточном программном обеспечении, прежде чем действие будет вызвано.   -  person JasonW    schedule 03.06.2015
comment
Я отправил запрос на Lumen 5.0 и жду слияния.   -  person JasonW    schedule 03.06.2015


Ответы (2)


После некоторых исследований я получил решение. Вот они:

Создать собственный диспетчер

Во-первых, вам нужно сделать свой собственный диспетчер, мой:

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']);

ПО промежуточного слоя для вызова (ОБНОВЛЕНИЕ)

ПРИМЕЧАНИЕ: я понимаю, что это не элегантно, поскольку dispatch вызывается после выполнения промежуточного программного обеспечения, вы должны отправить диспетчер вручную.

В вашем промежуточном программном обеспечении внутри вашего метода 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;

PoC

person krisanalfa    schedule 04.06.2015
comment
Я не пробовал это, но это выглядит великолепно. Я думаю, это должно сработать. Я обновлю это в ближайшее время. - person JasonW; 05.06.2015
comment
Извините, это не работает. Пожалуйста, проверьте этот src-код. Промежуточное программное обеспечение вызывается перед отправкой. Таким образом, $current в Dispatcher всегда имеет значение null, если не изменен порядок вызова. - person JasonW; 05.06.2015
comment
Это действительно получает текущий маршрут. Однако в вашем решении отправка произошла дважды, см. здесь . Спасибо, в любом случае. - person JasonW; 05.06.2015
comment
Как я уже сказал, это не очень элегантный способ, потому что диспетчеризация будет вызвана дважды. Чтобы избежать этого, вы можете изменить способ отправки в Application. Проверить, был ли диспетчер отправлен или нет, если нет, выполнить отправку и наоборот. - person krisanalfa; 05.06.2015

Я нашел правильный ответ на эту проблему. Я пропустил один метод с именем routeMiddleware() из Application. Этот метод регистрирует ПО промежуточного слоя для конкретного маршрута, которое вызывается после отправки. Так что просто используйте $app->routeMiddleware() для регистрации вашего промежуточного программного обеспечения. И получите информацию о совпадающем маршруте с помощью $request->route() в промежуточном программном обеспечении.

person JasonW    schedule 08.06.2015
comment
Не могли бы вы объяснить больше, пожалуйста, потому что я не понимаю, как получить текущий маршрут - person w3spi; 06.11.2015