2

I have created a Symfony 5.3+ bundle which should be used to add common code to different projects. The bundle contains some services which should be configurable using parameters / options as described in the Symfony docs.

How to provide default values for these options? Defaults set in the bundles Configuration.php do not have any effect.


Details:

I have created a bundle project using the following structure and added it to my Symfony project using composer:

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) {
}    

Problem: How to use default values of parameters?

paramA and paramB are defined in the bundles Configuration.php with default values of 100 and 200. I would like to use these defaults in the project without specifying custom values. However, I do not create a config/packages/xy_commons.yaml file in the project and explicitly specify values, I get the following error:

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

When creating a config/packages/xy_commons.yaml file, I cannot use ~ to use the default value:

xy_commons:
    params:
        paramA: ~
        paramB: ~

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

Only when explicitly specifying a value it works:

xy_commons:
    params:
        paramA: 300
        paramB: 400

How to use the default values defined in Configuration.php?

3
  • Please do not ask multiple questions in a single question. Also, why not ship a configuration file with your bundle that contains these parameters, like many other bundles do? Commented Aug 3, 2021 at 15:09
  • @Cerad the Configuration class is already in the question... Or do you mean something different? Commented Aug 4, 2021 at 12:56
  • Just for info, I deleted my comments and posted an answer. I did not notice that the Configuration object was in the question. Scrolling issues. So my comments did not make much sense. Commented Aug 4, 2021 at 14:02

1 Answer 1

4

There are three problems here. The first deals with what is possibly my least favorite class in Symfony. The dreaded configuration object. In particular, you need to use addDefaultsIfNotSet when dealing with arrays:

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

The second problem is that you are not defining your parameters correctly. In particular the parameters will be grouped in an array called params. You almost had it:

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

The final thing is the use of tilde to indicate default values. I think this might be a works as designed issue. Technically, tilde on yaml means null and it is up to the processor to get it a meaning. The ArrayNode works as expected but the IntegerNode does not. So this works:

# config/packages/my.yaml
my:
    params: ~
#        paramA: ~
#        paramB: 666
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.