Как обращаться со свойствами справки в типах форм?
Я создал свойство (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; } // ... }
Подробнее о классах с сохранением состояния или без сохранения состояния см. статья .