允许Symfony 2 Bundle语义配置中的键值对

时间:2012-06-07 01:23:20

标签: symfony dependency-injection bundle

基本上我想在billings节点下的配置中允许任意(但非空)数量的键值对定义关联数组

我在Configurator.php(部分):

中有这个
->arrayNode('billings')
    ->isRequired()
    ->requiresAtLeastOneElement()
    ->prototype('scalar')
    ->end()
->end()

然后,在我的config.yml

my_bundle:
    billings:
        monthly : Monthly
        bimonthly : Bimonthly

但是,输出$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();
    }

}

...我得到的是数字索引,而不是关联数据:

 'billings' => 
     array (size=2)
         0 => string 'Monthly' (length=7)
         1 => string 'Bimonthly' (length=9)

出于好奇(如果这可以帮助),我正在尝试将此数组作为服务参数注入(来自这个伟大的包的注释: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;
    }
} 

4 个答案:

答案 0 :(得分:24)

您应该在useAttributeAsKey('name')

中将Configurator.php添加到您的结算节点配置中

有关useAttributeAsKey()的更多信息,请参阅Symfony API Documentation

更改结算节点配置后,它应该是:

->arrayNode('billings')
    ->isRequired()
    ->requiresAtLeastOneElement()
    ->useAttributeAsKey('name')
    ->prototype('scalar')->end()
->end()

答案 1 :(得分:2)

您可以添加以下内容:

->arrayNode('billings')
    ->useAttributeAsKey('whatever')
    ->prototype('scalar')->end()

之后,键会神奇地出现。

请参阅:https://github.com/symfony/symfony/issues/12304

答案 2 :(得分:2)

我最近不得不设置一些嵌套数组配置。

需求

  • 带有自定义键的第一级数组(描述实体路径)
  • 每个数组都必须有一个或多个任意标记作为键,具有布尔值。

要实现这样的配置,您必须使用prototype()方法。

所以,以下配置:

my_bundle:
    some_scalar: my_scalar_value
    first_level:
        "AppBundle:User":
            first_tag: false
        "AppBundle:Admin":
            second_tag: true
            third_tag: false

可以使用以下配置获得:

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

从扩展类中转储$ config会得到以下输出:

Array
(
    [some_scalar] => my_scalar_value
    [first_level] => Array
        (
            [AppBundle:User] => Array
                (
                    [first_tag] => 
                )

            [AppBundle:Admin] => Array
                (
                    [second_tag] => 1
                    [third_tag] => 
                )
        )
)

瞧!

答案 3 :(得分:0)

useAttributeAsKey实际上是这样做的:

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