Подтвердить что ты не робот

Разрешение пар ключ-значение в семантической конфигурации Symbony 2 Bundle

В принципе, я хотел бы разрешить произвольное (но не пустое) число пар ключ-значение в моей конфигурации под billings node, что определяет ассоциативный массив.

У меня это в моей 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;
    }
} 
4b9b3361

Ответ 1

Вы должны добавить useAttributeAsKey('name') в свою конфигурацию биллинга node в Configurator.php.

Дополнительная информация о useAttributeAsKey() вы можете прочитать в Документация по API Symfony

После изменения биллинга node конфигурация должна выглядеть так:

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

Ответ 2

Вы можете добавить что-то вроде:

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

После этого появятся волшебные клавиши.

Смотрите: https://github.com/symfony/symfony/issues/12304

Ответ 3

Мне недавно пришлось настроить некоторые вложенные массивы.

Потребности были

  • Массив первого уровня с настраиваемыми ключами (указание пути сущности)
  • Каждый из этих массивов должен иметь один или несколько произвольных тегов в качестве ключей с логическим значением.

Чтобы достичь такой конфигурации, вам необходимо выполнить каскадный метод 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;

Dumping $config изнутри класса расширения дает следующий результат:

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

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

И вуаля!

Ответ 4

Это то, что на самом деле делает 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;
}