从自定义捆绑包中的控制器获取配置参数

Get config parameters from controller within a custom bundle

提问人:H3lltronik 提问时间:12/3/2019 最后编辑:yiviH3lltronik 更新时间:12/6/2019 访问量:1684

问:

我正在尝试从配置 yaml 文件中获取一些参数,我正在执行以下操作:

namespace ExampleVendor\AdminBundle\Controller;

/**
 * @Route("/", name="_home")
 */
public function index(ParameterBagInterface $params) {
    $menuIcons = $this->getParameter('admin-aside-menu');
    dump($menuIcons);

    return $this->render('@ExampleVendorAdminBundle/index.html.twig');
}

如您所见,它只是一个打印参数的转储函数,问题是,此代码在 App\src\Controller 中的控制器中工作时有效,我的意思是在“main”应用程序 src 文件夹中,但是当我复制此代码并将其粘贴到自定义捆绑包中的控制器中时(类似于 vendor/myVendor/myBundle/src/Controller)重新加载页面时出现错误:admin-aside-menu

无法解决“ExampleVendor\AdminBundle\Controller\AdminController::index()”的参数$params,也许您忘记将控制器注册为服务或错过了用“controller.service_arguments”标记它?

我需要获取这些参数,但我不知道如何将其“注入”到我的控制器中。ParameterBagInterface


好的,所以这篇文章似乎说了如何解决这个问题,但是,由于我需要注入某些东西的控制器位于供应商文件夹的自定义捆绑包中,因此答案对我根本没有帮助

Project
|
+--AdminBundle <- My custom bundle, installed via composer as symlink
|  |
|  +--Controller
|  |  |
|  |  +--AdminController.php <- Heres where I want to get my parameter
|  |
|  +--DependencyInjection
|  +--Entity
|  +--Resources
|     |
|     +--config
|        |
|        +--custom.yaml <- There are my custom params
|        +--services.yaml <- Heres where I should register my controller as service?
|
+--assets
|
+--bin
|
+--config
|
+--public
|
+--src
|
+--templates
|
+--vendor <- Heres my admin bundle as symlink

该文件夹是通过 composer 作为符号链接的安装程序,因此我可以在我的项目中使用它,所以知道这一点,任何人都知道我如何将参数直接注入到我的控制器中?AdminBundleParametersBag


这是我的custom.yaml,它保存了我的捆绑包中的参数

// AdminBundle/Resources/config/custom.yaml
parameters:
  admin-aside-menu:
    items:
      - icon: 'Home/Chair2'
        title: 'Prueba'
      - icon: 'Home/Deer'
        title: 'Prueba Venado'

这是依赖注入中的配置类

// AdminBundle/DependencyInjection/Configuration.php

class Configuration implements ConfigurationInterface {
    public function getConfigTreeBuilder() {
        $treeBuilder = new TreeBuilder('admin-aside-menu');

        $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('items')
                    ->children()
                        ->scalarNode('icon')->end()
                        ->scalarNode('title')->end()
                ->end()
            ->end()
        ;

        return $treeBuilder;
    }
}

这是捆绑包扩展

// AdminBundle/DependencyInjection/ExampleVendorAdminExtension .php
class ExampleVendorAdminExtension extends Extension {

    /**
     * Loads a specific configuration.
     *
     * @throws \InvalidArgumentException When provided tag is not defined in this extension
     */
    public function load(array $configs, ContainerBuilder $container) {
        $loader = new YamlFileLoader( $container, new FileLocator(__DIR__.'/../Resources/config') );
        $loader->load('custom.yaml');
        $loader->load('services.yaml');

        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);
    }
}

我在我的 services.yaml 中写了这个,根据 Florian 的响应将我的参数注入到我的控制器中

// AdminBundle/Resources/config/services.yaml
services:
    admin-bundle.controller.admin-controller:
        class: ExampleVendor\AdminBundle\Controller\AdminController
        arguments:
            - "%admin-aside-menu%"

它似乎在某种程度上起作用,因为当我写得不好(错别字)时,错误页面说"%admin-aside-menu%"

“你是说:'admin-aside-menu'吗?”

所以我认为它实际上正在加载我的参数,但在我的控制器中我无法“注入”它

这是控制器:

/**
 * @Route(name="admin")
 *
 * Class AdminController
 * @package ExampleVendor\AdminBundle\Controller
 */
class AdminController extends AbstractController {
    public function __construct(array $adminAsideMenu) {
        dump($adminAsideMenu);
    }
}

但是当我运行它时,我收到此错误

URI “/admin/” 的控制器不可调用。控制器“ExampleVendor\AdminBundle\Controller\AdminController”具有必需的构造函数参数,并且容器中不存在。您是否忘记将控制器定义为服务?

php symfony symfony4

评论

1赞 Florian Hermann 12/3/2019
捆绑包中的控制器未注册为服务,因此无法使用自动接线。解决方案可能是将控制器声明为服务,并在声明中手动注入参数。
1赞 Florian Hermann 12/3/2019
此外,如果使用前面的解决方案,则可以直接注入参数,而不是注入参数包。
0赞 H3lltronik 12/3/2019
嗨,弗洛里安,非常感谢您的帮助。如何直接注入参数?我正在努力尝试将我的控制器注册为服务,所以如果您能为我提供链接或一些您可以推荐的文档,我将不胜感激
0赞 H3lltronik 12/3/2019
我编辑了我的帖子,希望它能帮到你更多一点,帮助我摆脱这个困境
0赞 Tejas Gosai 12/3/2019
你能分享你的 service.yaml 和主 service.yaml 吗?

答:

1赞 JohnDoe 12/3/2019 #1

打开 service.yaml 然后输入类名并选择一个 ID 以通过自动布线获取它

services:
    ExampleVendor\AdminBundle\Controller = '@adminbundle_thenameyouchoose'

评论

0赞 H3lltronik 12/3/2019
嗨,约翰,我有点困惑,我意识到我需要将我的控制器注册为服务,所以我找到了这篇文章,但在答案的评论中,有人遇到了与我相同的问题,我只是无法让它工作,因为我的控制器是供应商文件夹,所以不知道我应该写哪个命名空间和实际路由
0赞 H3lltronik 12/3/2019
我编辑了我的帖子,希望它能帮到你更多一点,帮助我摆脱这个困境
0赞 JohnDoe 12/3/2019
你能把它声明为 AdminBundle\controller 吗?并从 service.ymal 将他称为 AdminBundle\controller\adminController。请照顾好增量
1赞 rnenciu 12/3/2019 #2

由于任何编码标准和实践,您永远不应该在供应商包中编写代码。vendor 不是您应该推送到 git 存储库中的文件夹,原因之一是静态库的过大大小实际上不属于您的项目,而且当您尝试更新您的 composer 依赖项时,这种做法会造成一团糟。您应该保持清洁并将供应商添加到 .gitignore 中。Symfony为覆盖服务提供了很好的支持,检查一下。

评论

0赞 H3lltronik 12/3/2019
有没有办法覆盖 twig 错误模板,例如错误页面(404、403 等),但来自不同的捆绑包而不是项目本身,就像刚刚安装了捆绑包一样,它会自动覆盖这些页面
1赞 rnenciu 12/3/2019
@H3lltronik symfony.com/doc/3.4/templating/overriding.html 这正是您所需要的,但它适用于 symfony 2 到 3 版本,因为自 symfony 4 以来捆绑包已被弃用,它们不再为此提供支持,但发现了一些解决方法 -> stackoverflow.com/questions/45239350/...此外,您可能还想检查此 symfony.com/doc/4.3/controller/...以覆盖错误页面。
1赞 Florian Hermann 12/3/2019 #3

构建自己的捆绑包并不简单。

从您与我们共享的捆绑包结构中,我可以看到您已经有了 Dependency injection 文件夹。

此文件夹应包含两个文件:

  • 配置:.php
  • 您的捆绑名称扩展名:.php

要注入控制器的参数应在捆绑包的配置中,因此必须完成 Configuration.php 才能添加它。(我不是这方面的专家,所以我让你自己搜索)

此外,为了在捆绑包的代码中访问您的配置,您必须将配置作为参数注入,并为您的捆绑包添加前缀。你可以在这里找到一个例子来了解如何做到这一点:https://github.com/Orbitale/CmsBundle/blob/4.x/DependencyInjection/OrbitaleCmsExtension.php

现在,在 Resources/services.yaml 中,您可以将控制器添加为服务:

services:
    bundle_name.controller.your_controller:
        class: Your\Controller\Namespace
        arguments:
            - '%bundle_key.your_parameter_name%'

这样的事情应该有效,但可能并不完全清楚。所以如果你有更多问题,我会尽力回答你。

不要犹豫,检查现有的捆绑包作为灵感来源。

---------------------- 编辑以回答 编辑 2 ----------------------

据我所知,您的捆绑配置密钥是“admin-aside-menu”?也许它应该是“admin_aside_menu”(以符合惯例)。无论如何:

是的,你快到了,但缺少一些东西。您不能直接在捆绑包的 config 中定义参数。相反,当您从应用程序中使用捆绑包时,您将在 /config/packages/admin-aside-menu.yaml 中拥有如下文件:

admin-aside-menu:
    items:
        - icon: 'Home/Chair2'
          title: 'Prueba'
        - icon: 'Home/Deer'
          title: 'Prueba Venado'

这是您当前使用的捆绑包配置,它应该与您在 AdminBundle/DependencyInjection/Configuration.php 文件中定义的格式匹配。(我帮不了你,因为这不是我经常做的事情)。

您现在可以完全删除文件 AdminBundle/Resources/config/custom.yaml,因为该配置位于您的应用程序中。

然后,在扩展中,您可以获取此配置以将其注入到应用程序参数中,并带有捆绑包的前缀。如果我修改你的代码,它应该是这样的:

// AdminBundle/DependencyInjection/ExampleVendorAdminExtension .php
class ExampleVendorAdminExtension extends Extension {

    /**
     * Loads a specific configuration.
     *
     * @throws \InvalidArgumentException When provided tag is not defined in this extension
     */
    public function load(array $configs, ContainerBuilder $container) {
        $loader = new YamlFileLoader( $container, new FileLocator(__DIR__.'/../Resources/config') );
        // $loader->load('custom.yaml'); not needed anymore
        $loader->load('services.yaml');

        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        // This part inject your config in parameters
        foreach ($config as $key => $value) {
            $container->setParameter('admin-aside-menu.'.$key, $value);
        }
    }
}

现在您的配置参数已设置!

最后一步,将其注入控制器:

// AdminBundle/Resources/config/services.yaml
services:
    admin-bundle.controller.admin-controller:
        class: ExampleVendor\AdminBundle\Controller\AdminController
        arguments:
            - "%admin-aside-menu.items%"

这样可以吗?

评论

0赞 H3lltronik 12/3/2019
嗨,弗洛里安,再次感谢您抽出时间接受采访。我只有一个小问题,“bundle_key”是什么?如何检查?
1赞 Florian Hermann 12/4/2019
“bundle_key”是捆绑包配置的任意前缀。在我给你的捆绑链接中,他使用“orbitale_cms”作为前缀
0赞 H3lltronik 12/4/2019
嗨,弗洛里安,我快到了,我只是最后有点卡住了,我更新了我的帖子