acubens
acubens

Reputation: 472

How to change option dynamically for a symfony2 form field?

In symfony 2.5.6, how to change options dynamically in symfony2 form, by example:

// src/AppBundle/Form/Type/TaskType.php
namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('task')
            ->add('dueDate', null, array('widget' => 'single_text'))
            ->add('save', 'submit');

       if (condition) {
          //how to change option of 'task' or 'dueDate' by example
          //something like this, but addOption doesn't exist and i don't find any usefull method
          $builder->get('dueDate')->addOption('read_only', true) 
       }

    }

    public function getName()
    {
        return 'task';
    }
}

Need to use event ?

http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Or this

foreach($builder->all() as $key => $field) {
    if ($key == 'dueDate')) {
         $options = $field->getOptions();
         $options = array_merge_recursive($options, array('read_only' => true));
         $builder->remove($key);
         $builder->add($key, $field->getName(), $options);
    }
}

#with 'Could not load type "dueDate"' error when i display my form in a browser!

How to to do? Best practice?

Thanks!

Upvotes: 2

Views: 9253

Answers (2)

Julesezaar
Julesezaar

Reputation: 3396

I use this function to update options after a field has been added to a form. It basically means to regenerate the field with the data that we have, add something to the options and re-add the field, re-add its transformers and so

Put this helper function somewhere in a FormHelper class, or wherever you like

/**
 * @param FormBuilderInterface $builder
 * @param string $fieldName
 * @param string $optionName
 * @param $optionData
 */
public static function setOptionToExistingFormField(
    FormBuilderInterface $builder,
    string $fieldName,
    string $optionName,
    $optionData
): void {
    if (!$builder->has($fieldName)) {
        // return or throw exception as you wish
        return;
    }

    $field = $builder->get($fieldName);

    // Get some things from the old field that we also need on the new field
    $modelTransformers = $field->getModelTransformers();
    $viewTransformers = $field->getViewTransformers();
    $options = $field->getOptions();
    $fieldType = get_class($field->getType()->getInnerType());

    // Now set the new option value
    $options[$optionName] = $optionData;

    /**
     * Just use "add" again, if it already exists the existing field is overwritten.
     * See the documentation of the add() function
     * Even the position of the field is preserved
     */
    $builder->add($fieldName, $fieldType, $options);

    // Reconfigure the transformers (if any), first remove them or we get some double
    $newField = $builder->get($fieldName);
    $newField->resetModelTransformers();
    $newField->resetViewTransformers();
    foreach($modelTransformers as $transformer) {
        $newField->addModelTransformer($transformer);
    }
    foreach($viewTransformers as $transformer) {
        $newField->addViewTransformer($transformer);
    }
}

And then use it like this

$builder
    ->add('someField', SomeSpecialType::class, [
        'label' => false,
    ])
;

FormHelper::setOptionToExistingFormField($builder, 'someField', 'label', true);

Upvotes: 1

xurshid29
xurshid29

Reputation: 4210

I dont't know what do you mean by 'best practice', but why not to do it like this:

$builder
    ->add('dueDate', null, array('widget' => 'single_text'))
    ->add('save', 'submit');

$options = [
    KEY => VALUE,
    ....
];

if (condition) {
    $options = [
        ANOTHER_KEY => ANOTHER_VALUE,
        ....
    ];
}

$builder->add('task', TYPE, $options);

Another approach would be to use PRE_SUBMIT event, something like this..

$builder
    ->add('task')
    ->add('dueDate', null, array('widget' => 'single_text'))
    ->add('save', 'submit');

$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'preSubmit']);

....    

public function preSubmit(FormEvent $event)
{
    if (CONDITION) {
        $builder->remove('task');
        $builder->add('task', TYPE, $NEW_OPTIONS_ARRAY);
    }

}

Upvotes: 2

Related Questions