【问题标题】:Change Symfony 3 controllers folder更改 Symfony 3 控制器文件夹
【发布时间】:2016-12-01 13:55:19
【问题描述】:

我正在使用 Symfony 3 开发一个项目,我想让我的 AppBundle 文件夹如下所示:

  • AppBundle/
    • 域/
    • 应用/
    • 基础设施/
    • 用户界面/
      • 控制器/
        • 默认控制器/

我想将“Controller”文件夹放在 UserInterface 层中。问题是 Symfony 加载控制器的魔术方法是在“AppBundle/Controller”路径上搜索它们。

是否有任何选项可以像这样在我的 routing.yml 文件中指定控制器路径?

app.home_page:
  path: /test
  defaults: {_controller: AppBundle:UserInterface\Default:indexAction}

【问题讨论】:

标签: symfony path controller


【解决方案1】:

您还可以使用其完全限定的类名和方法 (Ref.) 来引用此控制器:

app.home_page:
    path: /test
    defaults: { _controller: AppBundle\UserInterface\Controller\DefaultController::indexA‌​ction }

【讨论】:

    【解决方案2】:

    @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);
        }
    }
    

    因此,即使有更简单的方法可以回答这个特定问题,但如果您确实需要调整解析器的工作方式,那么这个答案或许可以作为参考。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-09
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多