我正在将旧项目路由(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
[控制器由RequestListener
,特别是路由器RouterListener
确定。依次使用RouterListener
来对照UrlMatcher
检查uri。您可以实现一个RouteCollection
来根据路由解析控制器。您要做的就是用Matcher
键返回一个数组。
请注意,此解决方案不允许您从路由名称生成网址,因为它是_controller
,但您可以将其连接在一起。
different Interface
现在您需要覆盖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 $resourceNotFoundHttpException) {
// Allow only GET requests
if ('GET' != $this->getContext()->getMethod()) {
throw $resourceNotFoundHttpException;
}
// 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 $resourceNotFoundHttpException;
}
}
}
不确定这是否是最好的方法,但似乎更简单。我想到的另一个选择是插入Listener
本身。