Symfony 2.8、3.0以降のbuildForm()にデータを渡す


87

私のアプリケーションは現在、この回答で推奨されているように、コンストラクターを使用してデータをフォームタイプに渡します。ただし、Symfony 2.8アップグレードガイドでは、型インスタンスをcreateForm関数に渡すことは非推奨であるとアドバイスしています。

型インスタンスをForm :: add()、FormBuilder :: add()およびFormFactory :: create *()メソッドに渡すことは非推奨であり、Symfony3.0ではサポートされなくなります。代わりに、そのタイプの完全修飾クラス名を渡します。

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

After:
$form = $this->createForm(MyType::class);

完全修飾クラス名でデータを渡すことができないので、別の方法はありますか?


1
どのような種類のデータを渡す必要がありますか?注射できるものですか?
Cerad 2015

2
うまくいけば、UPGRADE.mdが改善されます:github.com/symfony/symfony/issues/18662
althaus

回答:


133

これは私たちのフォームのいくつかも壊しました。オプションリゾルバーを介してカスタムデータを渡すことで修正しました。

フォームタイプ:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $this->traitChoices = $options['trait_choices'];

    $builder
        ...
        ->add('figure_type', ChoiceType::class, [
            'choices' => $this->traitChoices,
        ])
        ...
    ;
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'trait_choices' => null,
    ]);
}

次に、コントローラーでフォームを作成するときに、コンストラクターではなくオプションとしてフォームを渡します。

$form = $this->createForm(ProfileEditType::class, $profile, [
    'trait_choices' => $traitChoices,
]);

8
この問題にも遭遇し、同様の解決策を実行しました。データが必要であり、コンストラクター定義で通常行うような型ヒントを実行する場合は、configureOptions()のオプションリゾルバーにsetRequired()メソッドとsetAllowedTypes()メソッドを使用する必要があると思います。 、setDefaults()の代わりに。
sarahg 2015

2
それはまさにあなたがすべきことです。:)
Bernhard Schussek 2015

3
@Roubi同じことを行い、configureOptionsメソッドでオプションを定義し、フォームフィールドを追加するときにそれを渡します。
Bart Wesselink 2016年

2
私もこの変更に満足していません。でも答えてくれてありがとう。
アダムビーン2016年

2
FormTypeはファクトリのように機能し、ステートレスである必要があります。コンストラクターを介して(サービスタグメソッドを介して以外に)値を挿入すると、ステートフルになります。このようにして、フォームタイプを作成する1つの統一された方法があります。オプションは常にコンストラクター引数の代わりに使用されることを意図していました。この変更は、DXと使いやすさにとって素晴らしいものです。
誰でも2016年

6

ここでは、別のアプローチ、つまりデータを取得するための注入サービスを使用できます。

  1. フォームをサービスとして説明する(クックブック
  2. 保護されたフィールドとコンストラクターをフォームクラスに追加します
  3. 注入されたオブジェクトを使用して、必要なデータを取得します

例:

services:
    app.any.manager:
        class: AppBundle\Service\AnyManager

    form.my.type:
        class: AppBundle\Form\MyType
        arguments: ["@app.any.manager"]
        tags: [ name: form.type ]

<?php

namespace AppBundle\Form;

use AppBundle\Service\AnyManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class MyType extends AbstractType {

    /**
     * @var AnyManager
     */
    protected $manager;

    /**
     * MyType constructor.
     * @param AnyManager $manager
     */
    public function __construct(AnyManager $manager) {
        $this->manager = $manager;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $choices = $this->manager->getSomeData();

        $builder
            ->add('type', ChoiceType::class, [
                'choices' => $choices
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\MyData'
        ]);
    }

}

これは良いことですが、サービスマネージャーが引数を使用できない場合は機能しません。
demonkoryu 2017年

5

form.factoryサービスの「createNamedBuilder」または「createNamed」関数を使用している場合は、それを使用してデータを設定および保存する方法のスニペットを次に示します。'data'フィールドを使用することはできず(nullのままにする)、渡されたデータ/エンティティを$options値として設定する必要があります。

setAllowedTypes()およびsetRequired()オプションの使用に関する@sarahg命令も組み込みました。これは正常に機能しているようですが、最初にsetDefined()でフィールドを定義する必要があります。

また、データを設定する必要がある場合は、フォーム内で「データ」フィールドに追加することを忘れないでください。

コントローラーでは、getNameが2.8 / 3.0で非推奨になったため、getBlockPrefixを使用しています。

コントローラ:

/*
* @var $builder Symfony\Component\Form\FormBuilderInterface
*/
$formTicket = $this->get('form.factory')->createNamed($tasksPerformedForm->getBlockPrefix(), TaskAddToTicket::class, null, array('ticket'=>$ticket) );

形:

public function configureOptions(OptionsResolver $resolver)    {
    $resolver->setDefined('ticket');
    $resolver->setRequired('ticket');
    $resolver->addAllowedTypes('ticket', Ticket::class);

    $resolver->setDefaults(array(           
        'translation_domain'=>'AcmeForm',
        'validation_groups'=>array('validation_group_001'),
        'tasks' => null,
        'ticket' => null,
    ));
}

 public function buildForm(FormBuilderInterface $builder, array $options)   {

    $this->setTicket($options['ticket']);
    //This is required to set data inside the form!
    $options['data']['ticket']=$options['ticket'];

    $builder

        ->add('ticket',  HiddenType::class, array(
                'data_class'=>'acme\TicketBundle\Entity\Ticket',
            )
        )
...
}

5

Symfony 3を使用している人のために、データを埋め込みフォームに渡す方法は次のとおりです。最初に上記で概説した@seklを正確に実行してから、次のようにします。

プライマリFormTypeで

' entry_options 'を使用してvarを埋め込みフォームに渡します

->add('your_embedded_field', CollectionType::class, array(
          'entry_type' => YourEntityType::class,
          'entry_options' => array(
            'var' => $this->var
          )))

EmbeddedFormTypeで

optionsResolverにオプションを追加します

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Yourbundle\Entity\YourEntity',
        'var' => null
    ));
}

buildForm関数の変数にアクセスします。ビルダー関数の前にこの変数を設定することを忘れないでください。私の場合、特定のIDに基づいてオプションをフィルタリングする必要がありました。

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $this->var = $options['var'];

    $builder
        ->add('your_field', EntityType::class, array(
          'class' => 'YourBundle:YourClass',
          'query_builder' => function ($er) {
              return $er->createQueryBuilder('u')
                ->join('u.entity', 'up')
                ->where('up.id = :var')
                ->setParameter("var", $this->var);
           }))
     ;
}

混乱を少なくするために-$ this-> varは、必ずしもクラス変数からではなく、渡したい値です。
Darius.V
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.