How do I work with help properties in form types?

I created a property ( foo

) on my form type. This property aims to pass the value from the method buildForm()

(where it was initialized and on the PRE_SUBMIT

listener where it was changed), to $view->vars

the buildView()

.

This is an example of what I am trying to do (without declaring a service):

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

      

But this always returns the same value foo

for all form fields when I expected the opposite. The screenshot below displays CollectionType

from 3 FooType

:

screenshot

I do not know why! Also, I tried to use options

some more when it doesn't make sense to me (as it is used internally only):

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefault('foo', rand(0, 100));
}

      

but I cannot figure out how to change this parameter in the methods of the current form.

How to do it right?

Thank!

+3


source to share


1 answer


The problem is caused by the natural state of the state of all types of forms (classes) in Symfony. However, if it is not declared as a service, each instance is created only once. So don't use properties for this kind of need unless you want some kind of stateful behavior like caching configuration.

Bypass

However, for each instance of the form type, a new instance of the form builder is created, so for these kinds of internal operations, you can use $builder->setAttribute()

instead.

Note. $builder->setAttribute()

does not apply to all HTML attributes, these are just form configuration attributes.

For example, the inline CollectionType

has an attribute prototype

with a similar situation:



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);
        }
    }
}

      

But for listeners, you don't have access to $builder->setAttribute()

, so you need an object value instead of a scalar one to be able to change the attribute. Something like this should work:

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

    // ...
}

      

Learn more about state or stateless state classes in this article .

+2


source







All Articles