@Yonel 的回答确实是这类问题最简单的解决方案。然而,如何调整控制器旋转变压器的问题确实经常出现。自从我搞砸了覆盖框架服务以来已经有一段时间了,所以我决定完成 Symfony 3.2 中的步骤。
目标是能够定义如下路线:
// routing.yml
app.home_page:
path: /test
defaults: {_controller: AppBundle:UserInterface\Controller:Default:indexAction}
请注意,_controller 中有四个 :。这个想法是第二个参数将用于确定给定包中的控制器目录。
要实现这一点,我们需要覆盖默认的 ControllerNameParser。通过 FrameworkBundle\Resources\config 搜索,我们发现该服务在 web.xml 中定义,id 为 controller_name_converter。回到过去,所有的框架类都有相关的参数值。我们实际上可以通过简单地为类名提供一个新的参数值来修改服务。现在,我们需要修改需要编译器通过的实际服务定义。接线:
// AppBundle.php
namespace AppBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use AppBundle\DependencyInjection\Compiler\CustomPass;
class AppBundle extends Bundle
{
// http://symfony.com/doc/current/service_container/compiler_passes.html
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new CustomPass());
}
}
// CustomPass.php
namespace AppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
// http://symfony.com/doc/current/bundles/override.html#services-configuration
class CustomPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('controller_name_converter');
$definition->setClass('AppBundle\Controller\ControllerNameParser');
$definition->addArgument('SomeParameter');
}
}
请注意,我向名称解析器添加了一个附加参数,只是为了说明它是如何完成的。所以你实际上可以使用一些参数值来指示在哪里搜索控制器。
自定义名称解析器的实际实现有点混乱,主要是因为任务的性质。它当然可以改进,但基本上任何带有四个冒号的控制器字符串都会被处理。
namespace AppBundle\Controller;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser as ControllerNameParserBase;
class ControllerNameParser extends ControllerNameParserBase
{
public function __construct(KernelInterface $kernel, $someParameter)
{
return parent::__construct($kernel);
}
public function parse($controllerString)
{
$parts = explode(':', $controllerString);
if (4 !== count($parts)) {
return parent::parse($controllerString);
}
list($bundleName, $controllerDir, $controller, $action) = $parts;
$controller = str_replace('/', '\\', $controller);
$bundle = $this->kernel->getBundle($bundleName, false)[0];
$try = $bundle->getNamespace().'\\'.$controllerDir.'\\'.$controller.'Controller';
if (class_exists($try)) {
return $try.'::'.$action;
}
return parent::parse($controllerString);
}
}
因此,即使有更简单的方法可以回答这个特定问题,但如果您确实需要调整解析器的工作方式,那么这个答案或许可以作为参考。