【问题标题】:How to change option dynamically for a symfony2 form field?如何动态更改 symfony2 表单字段的选项?
【发布时间】:2015-01-08 18:09:35
【问题描述】:

在 symfony 2.5.6 中, 如何以 symfony2 形式动态更改选项,例如:

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

需要使用事件吗?

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

或者这个

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!

怎么办?最佳做法?

谢谢!

【问题讨论】:

    标签: symfony


    【解决方案1】:

    我不知道“最佳实践”是什么意思,但为什么不这样做:

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

    另一种方法是使用PRE_SUBMIT 事件,类似这样..

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

    【讨论】:

    • 这种方法曾经对我有用,直到我在 2.7 天前升级到 symfony。它现在说“你不能从提交的表单中删除子项”,即使文档说你可以从 PRE_SUBMIT 中添加/删除字段
    • 你最后选择了什么方案?
    • 我选择第一种方案!
    • 一旦进入事件订阅者,就无法访​​问表单构建器,因此“另一种”方法无效。
    【解决方案2】:

    在将字段添加到表单后,我使用此功能更新选项。它基本上意味着使用我们拥有的数据重新生成字段,向选项添加一些内容并重新添加字段,重新添加其转换器等等

    把这个辅助函数放在 FormHelper 类的某个地方,或者任何你喜欢的地方

    /**
     * @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);
        }
    }
    

    然后像这样使用它

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      • 2017-06-06
      • 1970-01-01
      • 2022-06-10
      • 2011-08-31
      • 1970-01-01
      相关资源
      最近更新 更多