Reputation: 48439
Basically i'd like to allow an arbitrary (but not empty) number of key-value pairs in my configuration, under billings
node, that is define an associative array.
I've this in my Configurator.php
(part of):
->arrayNode('billings')
->isRequired()
->requiresAtLeastOneElement()
->prototype('scalar')
->end()
->end()
And then, in my config.yml
:
my_bundle:
billings:
monthly : Monthly
bimonthly : Bimonthly
However, outputting $config
:
class MyBundleExtension extends Extension
{
/**
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader($container,
new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$processor = new Processor();
$configuration = new Configuration();
$config = $processor->processConfiguration($configuration, $configs);
$container->setParameter('my_bundle.billings', $config['billings']);
var_dump($config);
die();
}
}
... what i get is array index by numbers, not an associative one:
'billings' =>
array (size=2)
0 => string 'Monthly' (length=7)
1 => string 'Bimonthly' (length=9)
Out of curiosity (and if this can help), i'm trying to inject this array as a service parameter (annotations from this great bundle: JMSDiExtraBundle):
class BillingType extends \Symfony\Component\Form\AbstractType
{
/**
* @var array
*/
private $billingChoices;
/**
* @InjectParams({"billingChoices" = @Inject("%billings%")})
*
* @param array $billingChoices
*/
public function __construct(array $billingChoices)
{
$this->billingChoices = $billingChoices;
}
}
Upvotes: 21
Views: 9745
Reputation: 17030
This is what useAttributeAsKey
actually does:
/**
* Sets the attribute which value is to be used as key.
*
* This is useful when you have an indexed array that should be an
* associative array. You can select an item from within the array
* to be the key of the particular item. For example, if "id" is the
* "key", then:
*
* array(
* array('id' => 'my_name', 'foo' => 'bar'),
* );
*
* becomes
*
* array(
* 'my_name' => array('foo' => 'bar'),
* );
*
* If you'd like "'id' => 'my_name'" to still be present in the resulting
* array, then you can set the second argument of this method to false.
*
* This method is applicable to prototype nodes only.
*
* @param string $name The name of the key
* @param bool $removeKeyItem Whether or not the key item should be removed
*
* @return ArrayNodeDefinition
*/
public function useAttributeAsKey($name, $removeKeyItem = true)
{
$this->key = $name;
$this->removeKeyItem = $removeKeyItem;
return $this;
}
Upvotes: 0
Reputation: 3466
I recently had to setup some nested arrays configuration.
Needs were
To achieve such a configuration, you have to casacade prototype()
method.
So, the following configuration:
my_bundle:
some_scalar: my_scalar_value
first_level:
"AppBundle:User":
first_tag: false
"AppBundle:Admin":
second_tag: true
third_tag: false
can be obtained using the following configuration:
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('my_bundle');
$rootNode
->addDefaultsIfNotSet() # may or may not apply to your needs
->performNoDeepMerging() # may or may not apply to your needs
->children()
->scalarNode('some_scalar')
->info("Some useful tips ..")
->defaultValue('default')
->end()
->arrayNode('first_level')
->info('Useful tips here..')
# first_level expects its children to be arrays
# with arbitrary key names
->prototype('array')
# Those arrays are expected to hold one or more boolean entr(y|ies)
# with arbitrary key names
->prototype('boolean')
->defaultFalse()->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
Dumping $config from inside the extension class gives the following output:
Array
(
[some_scalar] => my_scalar_value
[first_level] => Array
(
[AppBundle:User] => Array
(
[first_tag] =>
)
[AppBundle:Admin] => Array
(
[second_tag] => 1
[third_tag] =>
)
)
)
And voilà !
Upvotes: 2
Reputation: 923
You should add useAttributeAsKey('name')
to your billing node configuration in Configurator.php
.
More information about useAttributeAsKey()
you can read at Symfony API Documentation
After changes billing node configuration it should be like:
->arrayNode('billings')
->isRequired()
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->prototype('scalar')->end()
->end()
Upvotes: 25
Reputation: 31
You may add something like:
->arrayNode('billings')
->useAttributeAsKey('whatever')
->prototype('scalar')->end()
After that keys will magically appear.
See: https://github.com/symfony/symfony/issues/12304
Upvotes: 2