使用EventSubscriber动态添加选项到Symfony2表单

时间:2015-11-04 21:47:44

标签: php symfony

我正在尝试动态选择表单,因为选项来自服务调用。但是,当表单在视图中呈现时,选择不存在。

我在FormType

中执行了以下操作
<?php

namespace My\Form\Customer;

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

class ItemReturnRequestForm extends AbstractType
{

    /**
     * @var EventSubscriberInterface
     */
    protected $reasonsSubscriber;

    /**
     * Returns the name of this type.
     *
     * @return string The name of this type
     */
    public function getName()
    {
        return 'item_return_request';
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('reason', 'choice', [
            'label' => 'order.returns.reason_for_return',
            'required' => true,
            'multiple' => false,
            'expanded' => false,
            'placeholder' => 'order.returns.reasons.empty',
            'empty_data' => null,
        ]);

        $builder->addEventSubscriber($this->reasonsSubscriber);
    }

    /**
     * @param EventSubscriberInterface $reasonsSubscriber
     */
    public function setReasonsSubscriber(EventSubscriberInterface $reasonsSubscriber)
    {
        $this->reasonsSubscriber = $reasonsSubscriber;
    }
}

FormType有一个服务定义,它注入EventSubscriber实例,因为它也是一个服务定义,它有自己的依赖项。

EventSubscrbier看起来像

<?php

namespace My\Form\EventSubscriber;

use My\Customer\ItemReturnAware;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class ReturnReasonEventSubscriber implements EventSubscriberInterface
{
    use ItemReturnAware;

    public static function getSubscribedEvents()
    {
        return [
            FormEvents::PRE_SET_DATA => 'getReturnReasons',
        ];
    }

    public function getReturnReasons(FormEvent $event)
    {
        $form = $event->getForm();

        if ($form->has('reason')) {
            $options = $form->get('reason')->getConfig()->getOptions();
            $options['choices'] = $this->itemReturnService->getReasons();

            $form->add('reason', 'choice', $options);
        }
    }
}

到目前为止,一切似乎都很好。使用XDEBUG我可以看到EventSubscriber正在被触发。服务呼叫将$option['choices']设置为预期的数组值&amp;该字段已成功添加。

然而,当表单被渲染时。好像EventSubscriber从未被调用过。

如果它有所不同,options数组是一个无序的数字列表。

$options = [
    10 => 'First choice',
    15 => 'Second choice',
    20 => 'Third choice',
];

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

这是一个古老的问题,但是今天我在搜索事件监听器以修改表单选择的最佳结果中找到了它。

在我的上下文中,我有一个以编程方式创建的实体,然后将用户重定向到editAction以完成填写字段。 我只能在这种情况下应用一种选择,我不想让我的用户在它之外使用它。

这就是为什么我使用POST_SET_DATA事件的原因,因为我已经有一个包含填充字段的实体。

此事件侦听器是在

内的formType中设置的
public function buildForm(FormBuilderInterface $builder, array $options)
{

这是symfony 3.4的可行解决方案:

$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
// get the form from the event
$form = $event->getForm();

if ('myParticularMode' == $form->get('mode')->getData()) {
    // get the field options
    $options = $form->get('mode')->getConfig()->getOptions();
    // add the mode to the choices array
    $options['choices']['MY_PARTICULAR_MODE'] = 'myParticularMode_display_name';
    $form->add('mode', ChoiceType::class, $options);
}

});

如果要替换选项,可以删除此选项:

$options = $form->get('mode')->getConfig()->getOptions();

并为选择设置新的数组。