Разрешение пар ключ-значение в семантической конфигурации 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;
}
}
Ответы
Ответ 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;
}