Search code examples
phpsymfonyconfigurationyamlbundle

Symfony3 tree builder generic node value


How can you define a bundle configuration for which you don't know the entire structure?

For example, I have a bundle handling file upload, and I would like to create constraints using a "slot" system. You define a name for your slot, and a configuration associated (for example adding constraints), like so:

my_bundle:
    slots:
        avatar:
            constraints:
                image:
                    max_width: 200
        cv:
            constraints:
                 pdf: 
                     max_size: 2M
                     other_option_specific_to_pdf: [1, 2, 3]

The bundle will then create the constraints and validate your upload. The bundle has no idea of what options could be passed to a constraint, so I cannot define it in the tree builder.

Constraints can be added using services tags, so I have no way of knowing what constraint will exist when defining the tree builder configuration as well.

Right now, I have the following configuration:

$rootNode
        ->addDefaultsIfNotSet()
        ->performNoDeepMerging()
        ->children()
            ->arrayNode('slots')
                ->prototype('array')
                    ->children()
                        ->arrayNode('constraints')
                            ->prototype('array')
                                ->prototype('scalar') # Here a constraint may need an array or a more complex object. A "prototype('mixed')" would be handy..
                                ->end()
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end()
        ->end();

Is there a "wildcard" node taking everything below it as a generic array with no processing at all? I could not find it.

Thanks for your help!

EDIT

Thanks to Mawcel's answer, the corrected configuration looks like this :

$rootNode
        ->addDefaultsIfNotSet()
        ->performNoDeepMerging()
        ->children()
            ->arrayNode('slots')
                ->prototype('array')
                    ->children()
                        ->arrayNode('constraints')
                            ->prototype('array')
                                ->prototype('variable') # The wildcard I was looking for..
                                ->end()
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end()
        ->end();

Solution

  • Hi you need to use arrayNode with useAttributeAsKey, it will allow you to have config parameters with dynamic name:

    $rootNode
        ->arrayNode('slots')
             ->useAttributeAsKey('name')
             ->prototype('array')
             //
    

    http://symfony.com/doc/current/components/config/definition.html#array-node-options

    Else you can also use ->variableNode() to define arbitrary config values.

    http://api.symfony.com/2.3/Symfony/Component/Config/Definition/VariableNode.html