Lucas
Lucas

Reputation: 57

Symfony bundle configuration array node default value merge

I have a problem with Symfony4 bundle configuration. I have a configuration class with:

$rootNode
        ->children()
            ->arrayNode('mapping')
                ->useAttributeAsKey('code')
                ->prototype('scalar')->end()
                ->defaultValue(['default' => 'test'])
            ->end()
            .....
        ->end();

This returns a default configuration like:

array(1) {
   ["default"]=> string(4) "test"
}

But when I add a configuration file:

bundle:
    mapping:
        test: newvalue
        test2: newvalue2

Im getting a config:

array(2) {
   ["test"]=> string(8) "newvalue"
   ["test2"]=> string(9) "newvalue2"
}

But I expect to merge these two configs to get:

array(3) {
   ["default"]=> string(4) "test"
   ["test"]=> string(8) "newvalue"
   ["test2"]=> string(9) "newvalue2"
}

How can I set this defaults to be merged with provided configurations? Of course I want to let "default" config to be overridden, but by deafult to be merged.

I cant find any solution on docs https://symfony.com/doc/current/components/config/definition.html#array-node-options

Please help :)

Upvotes: 1

Views: 3055

Answers (2)

VladRia
VladRia

Reputation: 1587

If I understood correctly you want the default entry to be always defined. Applicaions will be able to overwrite the default value DEFAULT of default key.

Ok, there are two solutions :

A bad solution

    $rootNode = $treeBuilder->getRootNode()
        ->children()
            ->arrayNode('mapping')
                ->useAttributeAsKey('code')
                ->prototype('scalar')->end()
                ->beforeNormalization()
                    ->ifArray()
                    ->then(function ($mapping) {
                        return $mapping + ['default' => 'DEFAULT'];
                    })
                ->end()
            ->end();

If default key is not defined it will be added along with default DEFAULT value. It will function for ONE configuration file parsed. BUT you will get the problem if you have two and more configuraion files:

# config.yml
mapping:
    some: value
    default: MY_DEVELOPMENT_DEFAULT

# prod/config.yml
mapping:
    some: value_prod

You will have :

['some' => 'value_prod', 'default' => 'DEFAULT']

This is wrong. Default value replaces MY_DEVELOPMENT_DEFAULT because it was added to prod/config.yml and merged with config.yml.

Unfortunately, tree builder doesn't permit to define callback after merge.

A good solution

You can add your default entries after the configuraion values are merged (e.g. in compiler passes).

Upvotes: 1

Siqu
Siqu

Reputation: 147

For this you have to define the Array Configuration deeper:

$treeBuilder
   ->children()
       ->arrayNode('mapping')
           ->ignoreExtraKeys()
           ->addDefaultsIfNotSet()
           ->children()
               ->scalarNode('default')
                   ->defaultValue('test)
               ->end()
           ->end()
       ->end()
   ->end()

The addDefaultsIfNotSet will add your default values. The ignoreExtraKeys lets you define additional keys like in your example. It would be better to fully configure the keys, because you have better control over them.

Upvotes: 6

Related Questions