如何为 Symfony 包参数/配置值提供默认值?

How to provide default values for Symfony bundle parameters / config values?

我已经创建了一个 Symfony 5.3+ 包,它应该被用来向不同的项目添加通用代码。该捆绑包包含一些服务,这些服务应该可以使用 Symfony 文档中描述的参数/选项进行配置。

如何为这些选项提供默认值? 捆绑包中设置的默认值 Configuration.php 没有任何效果。


详情:

我使用以下结构创建了一个捆绑项目,并使用 composer 将其添加到我的 Symfony 项目中:

path/to/bundles/XYCommonsBundle/
    config/
        services.yaml
    src/
        Service/
            SomeService.php
        DependencyInjection
            Configuration.php
            XYCommensExtension.php
    XYCommensBundle.php
    composer.json
    ...


// src/DependencyInjection/XYCommensExtension.php
<?php

namespace XY\CommensBundle\DependencyInjection;

use ...

class XYCommensExtension extends Extension {
    public function load(array $configs, ContainerBuilder $container) {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        // make config available as parameters. Necessary?
        foreach ($config as $key => $value) {
            $container->setParameter('xy_commons.' . $key, $value);
        }


        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../config'));
        $loader->load('services.yaml');
    }
}


// src/DependencyInjection/Configuration.php
class Configuration implements ConfigurationInterface {
    public function getConfigTreeBuilder() {
        $treeBuilder = new TreeBuilder('xy_commons');
        
        $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('params')
                    ->children()
                        ->integerNode('paramA')->defaultValue(100)->end()
                        ->integerNode('ParamB')->defaultValue(200)->end()
                    ->end()
                ->end()
            ->end()
        ;
        
        return $treeBuilder;
    }
}


// config/services.yaml
services:
    xy_commons.service.some_service:
        class:  XY\CommonsBundle\Service\SomeService
        arguments:   
            - $paramA: '%xy_commons.params.paramA%'
            - $paramB: '%xy_commons.params.paramB%' 


// src/Service/SomeService.php
<?php

namespace XY\CommensBundle\Service;

use ...

class SomeService {
    public function __construct(LoggerInterface $logger, $paramA, $paramB) {
}    

问题:如何使用参数的默认值?

paramAparamB 在包 Configuration.php 中定义,默认值为 100 和 200。我想在项目中使用这些默认值而不指定自定义值。但是,我没有在项目中创建 config/packages/xy_commons.yaml 文件并明确指定值,我收到以下错误:

You have requested a non-existent parameter "xy_commons.params.paramA".

创建config/packages/xy_commons.yaml文件时,无法使用~使用默认值:

xy_commons:
    params:
        paramA: ~
        paramB: ~

Invalid type for path "xy_commons.params.paramA". Expected "int", but got "null".

只有在明确指定一个值时它才有效:

xy_commons:
    params:
        paramA: 300
        paramB: 400

如何使用Configuration.php中定义的默认值?

这里存在三个问题。第一个是 Symfony 中我最不喜欢的东西 class。可怕的配置对象。特别是在处理数组时需要使用addDefaultsIfNotSet

class Configuration implements ConfigurationInterface 
{
  public function getConfigTreeBuilder() 
  {
      $treeBuilder = new TreeBuilder('my');

      $rootNode = $treeBuilder->getRootNode();

      $rootNode
          ->children()
              ->arrayNode('params')->addDefaultsIfNotSet() # ADD THIS
                  ->children()
                      ->integerNode('paramA')->defaultValue(100)->end()
                      ->integerNode('paramB')->defaultValue(200)->end()
                  ->end()
              ->end()
          ->end()
      ;
      
      return $treeBuilder;
  }
}

第二个问题是您没有正确定义参数。特别是参数将被分组在一个名为 params 的数组中。你几乎成功了:

class MyExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        foreach($config['params'] as $key => $value) {
           $container->setParameter('xy_commons.params.' . $key, $value);
        }

# Use bin/console dump:container --parameters to verify

最后一件事是使用波浪号来表示默认值。我认为这可能是按设计工作的问题。从技术上讲,yaml 上的波浪号表示 null,由处理器来赋予它意义。 ArrayNode 按预期工作,但 IntegerNode 没有。所以这有效:

# config/packages/my.yaml
my:
    params: ~
#        paramA: ~
#        paramB: 666