【问题标题】:Symfony 5 dynamic routing resolveSymfony 5 动态路由解析
【发布时间】:2020-08-13 17:01:48
【问题描述】:

我正在将遗留项目路由 (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'}

如您所见,有大量重复的 urlaction 转换。

是否可以根据某些参数动态解析控制器方法。例如

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

一种选择是编写注释,但这对我不起作用并抛出Route.php not found

【问题讨论】:

    标签: symfony url-routing fosrestbundle symfony5


    【解决方案1】:

    控制器由RequestListener 确定,特别是路由器RouterListener。这又使用UrlMatcher 对照RouteCollection 检查uri。您可以实现一个Matcher,它根据路由解析控制器。您所要做的就是返回一个带有_controller 键的数组。

    请注意,此解决方案不允许您从路由名称生成 url,因为那是 different 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 本身。

    【讨论】:

      猜你喜欢
      • 2016-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-13
      相关资源
      最近更新 更多