Как обращаться со свойствами справки в типах форм?
Я создал свойство (foo) в моем типе формы. Это свойство имеет целью передать значение из метода buildForm() (где оно инициализировано и на слушателе PRE_SUBMIT, где оно модифицировано) в $view->vars в buildView().
Вот пример того, что я пытаюсь сделать (без объявления службы):
class FooType extends AbstractType
{
private $foo;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->foo = rand(0, 100);
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$this->foo = rand(0, $event->getData());
});
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['foo'] = $this->foo;
}
public function getParent()
{
return NumberType::class;
}
}
Но это всегда возвращает одно и то же значение foo для всех полей формы, когда я ожидал обратного. На следующем скриншоте показано CollectionType с 3 FooType записи:
Я не знаю, почему! Кроме того, я пытался использовать options еще тогда, когда это не имеет смысла для меня (так как он используется только для внутренних целей):
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('foo', rand(0, 100));
}
Но я не могу понять, как изменить эту опцию в текущих методах формы.
Как добиться этого правильно?
Спасибо!
1 ответ:
Проблема вызвана естественным состоянием всех типов форм (классов) в Symfony. Тем не менее, когда он не объявлен как Служба, каждый экземпляр создается только один раз. Поэтому не используйте свойства для такого рода потребностей, если вы не хотите некоторого поведения с сохранением состояния, такого как конфигурация кэширования.
Обходной путь
Однако для каждого экземпляра типа формы создается новый экземпляр построителя форм, поэтому для этих видов внутренних операций можно использовать
$builder->setAttribute()вместо этого.Примечание:
$builder->setAttribute()речь идет не об атрибутах HTML вообще, а только об атрибутах конфигурации формы.Например, встроенный
CollectionTypeимеет атрибутprototypeс аналогичной ситуацией:namespace Symfony\Component\Form\Extension\Core\Type; // ... class CollectionType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { if ($options['allow_add'] && $options['prototype']) { // ... $builder->setAttribute('prototype', $prototype->getForm()); } } public function buildView(FormView $view, FormInterface $form, array $options) { // ... if ($form->getConfig()->hasAttribute('prototype')) { $prototype = $form->getConfig()->getAttribute('prototype'); $view->vars['prototype'] = $prototype->setParent($form)->createView($view); } } }Но для прослушивателей у вас нет доступа к
$builder->setAttribute(), поэтому требуется значение объекта вместо скалярного, чтобы иметь возможность изменять атрибут. Что-то вроде этого должно сработать:class FooType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->setAttribute('dummy', (object) array( 'foo' => rand(0, 100), )); $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $dummy = $event->getForm()->getConfig()->getAttribute('dummy'); $dummy->foo = rand(0, $event->getData()); }); } public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['foo'] = $form->getConfig()->getAttribute('dummy')->foo; } // ... }Подробнее о классах с сохранением состояния или без сохранения состояния см. статья .
