我正在使用Symfony 3进行一个项目,我想让我的AppBundle文件夹像这样:
我想将“Controller”文件夹放在UserInterface图层中。问题是加载控制器的Symfony魔术方法是在“AppBundle / Controller”路径上搜索它们。
是否可以选择在我的routing.yml文件中指定控制器路径?
app.home_page:
path: /test
defaults: {_controller: AppBundle:UserInterface\Default:indexAction}
答案 0 :(得分:4)
您也可以使用其完全限定的类名称和方法(Ref.)来引用此控制器:
app.home_page:
path: /test
defaults: { _controller: AppBundle\UserInterface\Controller\DefaultController::indexAction }
答案 1 :(得分:4)
目标是能够定义如下路线:
// routing.yml
app.home_page:
path: /test
defaults: {_controller: AppBundle:UserInterface\Controller:Default:indexAction}
请注意_controller中有四个:' s。我们的想法是第二个参数将用于确定给定包中的控制器目录。
要实现这一点,我们需要覆盖默认的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);
}
}
所以即使有更简单的方法来回答这个问题,如果你真的需要调整解析器的工作方式,那么这个答案也许可以作为参考。