我将一些控制器定义为服务,我需要从路由名称获取控制器的类名。
对于非服务控制器,我可以使用路由器服务获取路由集合:
$route = $this->router->getRouteCollection()->get($routeName);
//Retrieve an object like that:
Route {
-path: "/admin/dashboard"
-host: ""
-schemes: []
-methods: []
-defaults: array:1 [
"_controller" => "AppBundle\Controller\Admin\AdminController::dashboardAction"
]
-requirements: []
-options: array:1 []
-compiled: null
-condition: ""
}
我可以使用$route["defaults"]["_controller"]
访问控制器类名,所以这很好。
问题在于我的控制器作为服务,_controller属性是服务的名称,而不是Controller类(如app.controller.admin.user:listAction
)我有服务的名称,但我需要有类名({ {1}})
我提出的唯一解决方案是从Container获取服务并在服务上使用AppBundle\Controller\Admin\UserController
,但它只会对检索控制器/服务的类产生巨大的性能影响。
还有其他解决方案吗?
答案 0 :(得分:0)
根据https://github.com/FriendsOfSymfony/FOSUserBundle/issues/2751的建议,我实现了一个缓存的映射,以便将路由名称解析为控制器类和方法。
<?php
// src/Cache/RouteClassMapWarmer.php
namespace App\Cache;
use Symfony\Component\Cache\Simple\PhpFilesCache;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\Routing\RouterInterface;
class RouteClassMapWarmer implements CacheWarmerInterface
{
/** @var ContainerInterface */
protected $container;
/** @var RouterInterface */
protected $router;
public function __construct(ContainerInterface $container, RouterInterface $router)
{
$this->container = $container;
$this->router = $router;
}
public function warmUp($cacheDirectory)
{
$cache = new PhpFilesCache('route_class_map', 0, $cacheDirectory);
$controllers = [];
foreach ($this->router->getRouteCollection() as $routeName => $route) {
$controller = $route->getDefault('_controller');
if (false === strpos($controller, '::')) {
list($controllerClass, $controllerMethod) = explode(':', $controller, 2);
// service_id gets resolved here
$controllerClass = get_class($this->container->get($controllerClass));
}
else {
list($controllerClass, $controllerMethod) = explode('::', $controller, 2);
}
$controllers[$routeName] = ['class' => $controllerClass, 'method' => $controllerMethod];
}
unset($controller);
unset($route);
$cache->set('route_class_map', $controllers);
}
public function isOptional()
{
return false;
}
}
在我的RouteHelper中,读取它的实现看起来像这样
$cache = new PhpFilesCache('route_class_map', 0, $this->cacheDirectory);
$controllers = $cache->get('route_class_map');
if (!isset($controllers[$routeName])) {
throw new CacheException('No entry for route ' . $routeName . ' forund in RouteClassMap cache, please warmup first.');
}
if (null !== $securityAnnotation = $this->annotationReader->getMethodAnnotation((new \ReflectionClass($controllers[$routeName]['class']))->getMethod($controllers[$routeName]['method']), Security::class))
{
return $this->securityExpressionHelper->evaluate($securityAnnotation->getExpression(), ['myParameter' => $myParameter]);
}
这应该比获取routeCollection快得多,并且在每个请求中针对容器解析service_id:method notated _controller-properties。