21

シナリオ: 2 つの選択があるフォームがあります。ユーザーが最初の選択から何かを選択すると、2 番目の選択に新しい値が入力されます。この部分は正常に動作します。

ただし、初期フォームでは許可されていない選択肢がいくつか含まれているため、フォームは検証されません。

形:

<?php

class MyType extends AbstractType
{
    private $category;

    public function __construct($category = null)
    {
        $this->category = $category;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('category', 'choice', array(
            'choices' => array(
                'foo' => 'foo',
                'bar' => 'bar'
            )
        );

        $builder->add('template', 'choice', array(
            'choices' => $this->loadChoices()
        );
    }

    private function loadChoices()
    {
        // load them from DB depending on the $this->category
    }
}

最初のカテゴリはfooです。したがって、foo のテンプレートが読み込まれ、選択肢として設定されます。しかし、ユーザーが を選択barすると、バー テンプレートが読み込まれます。しかし、フォームにはまだ foo の選択肢があり、検証されません。

これを解決する最善の方法は何ですか?

私が見つけた 1 つの方法は、コントローラーでフォームを再起動することでした。

<?php

$form = $this->createForm(new MyType());

if ($request->getMethod() === 'POST') {
    if ($request->request->has($form->getName())
        && isset($request->request->get($form->getName())['category'])) {
            $form = $this->createForm(new MyType($request->request->get($form->getName())['category']));
    }

    // ...
}

IllegalArgumentExceptionこれは機能しますが、値を設定するとスローされ、デフォルトを想定しているため、テストできません。これに対するより良い解決策はありますか?前もって感謝します!

4

1 に答える 1

22

これを管理するにはイベントを使用する必要があると思いますが、これはより正しい方法です

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('category', 'choice', array(
        'choices' => array(
            'foo' => 'foo',
            'bar' => 'bar'
        )
    ));

    $ff = $builder->getFormFactory();

    // function to add 'template' choice field dynamically 
    $func = function (FormEvent $e) use ($ff) {
        $data = $e->getData();
        $form = $e->getForm();
        if ($form->has('template')) {
            $form->remove('template');
        }

        $cat = isset($data['category'])?$data['category']:null;

        // here u can populate ur choices in a manner u do it in loadChoices
        $choices = array('1' => '1', '2' => '2');
        if ($cat == 'bar') {
            $choices = array('3' => '3', '4' => '4');
        }

        $form->add($ff->createNamed('template', 'choice', null, compact('choices')));
    };

    // Register the function above as EventListener on PreSet and PreBind
    $builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
    $builder->addEventListener(FormEvents::PRE_BIND, $func);
}
于 2012-11-14T07:51:31.727 に答える