Symfony 5 динамических c разрешение маршрутизации - PullRequest
0 голосов
/ 29 апреля 2020

Я переношу устаревшую маршрутизацию проекта (Yii1) на Symfony 5

Сейчас мой config/routing.yaml выглядит примерно так:

- {path: '/login', methods: ['GET'], controller: 'App\Controller\RestController::actionLogin'}
- {path: '/logout', methods: ['GET'], controller: 'App\Controller\RestController::actionLogout'}
# [...]
- {path: '/readme', methods: ['GET'], controller: 'App\Controller\RestController::actionReadme'}

Как вы можете видеть, есть много повторного преобразования url в action.

Возможно ли динамическое разрешение метода контроллера в зависимости от какого-либо параметра. Например,

- {path: '/{action<login|logout|...|readme>}', methods: ['GET'], controller: 'App\Controller\RestController::action<action>'}

Один из вариантов - написать аннотации, но это как-то не работает для меня и выдает Route.php not found

1 Ответ

1 голос
/ 29 апреля 2020

Контроллер определяется RequestListener, а именно маршрутизатором RouterListener. Это, в свою очередь, использует UrlMatcher для проверки URI против RouteCollection. Вы могли бы реализовать Matcher, который разрешает контроллер на основе маршрута. Все, что вам нужно сделать, это вернуть массив с ключом _controller.

Обратите внимание, что это решение не позволит вам генерировать URL-адрес из имени маршрута, поскольку это отличается Interface, но вы можете соединить его вместе.

// src/Routing/NaiveRequestMatcher
namespace App\Routing;

use App\Controller\RestController;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\RequestContext;

class NaiveRequestMatcher implements UrlMatcherInterface
{
    private $matcher;

    /**
     * @param $matcher The original 'router' service (implements UrlMatcher)
     */
    public function __construct($matcher)
    {
        $this->matcher = $matcher;
    }

    public function setContext(RequestContext $context)
    {
        return $this->matcher->setContext($context);
    }

    public function getContext()
    {
        return $this->matcher->getContext();
    }

    public function match(string $pathinfo)
    {
        try {
            // Check if the route is already defined
            return $this->matcher->match($pathinfo);
        } catch (ResourceNotFoundException $resourceNotFoundException) {
            // Allow only GET requests
            if ('GET' != $this->getContext()->getMethod()) {
                throw $resourceNotFoundException;
            }

            // Get the first component of the uri
            $routeName = current(explode('/', ltrim($pathinfo, '/')));

            // Check that the method is available...
            $baseControllerClass = RestController::class;
            $controller = $baseControllerClass.'::action'.ucfirst($routeName);
            if (is_callable($controller)) {
              return [
                '_controller' => $controller,
              ];
            }
            // Or bail
            throw $resourceNotFoundException;
        }
    }
}

Теперь вам нужно переопределить конфигурацию Listener:

// config/services.yaml
Symfony\Component\HttpKernel\EventListener\RouterListener:
    arguments:
        - '@App\Routing\NaiveRequestMatcher'

App\Routing\NaiveRequestMatcher:
     arguments:
       - '@router.default'

Не уверен, что это лучший подход, но кажется более простым. Другой вариант, который приходит на ум, - это подключиться к самому RouteCompiler.

...