web-dev-qa-db-fra.com

Passer des données à buildForm () dans Symfony 2.8, 3.0 et supérieur

Mon application transmet actuellement des données à mon type de formulaire à l'aide du constructeur, comme recommandé dans cette réponse . Toutefois, le Guide de mise à niveau de Symfony 2.8 indique que le passage d'une instance de type à la fonction createForm est obsolète:

Passer des occurrences de types à Form :: add (), FormBuilder :: add () et aux méthodes FormFactory :: create * () est obsolète et ne sera plus pris en charge dans Symfony 3.0. Passez plutôt le nom de classe qualifié complet du type.

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

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

Étant donné que je ne peux pas transmettre de données avec le nom de classe complet, existe-t-il une alternative?

83
Jonathan

Cela a également cassé certaines de nos formes. Je l'ai corrigé en passant les données personnalisées via le résolveur d'options.

Dans votre type de formulaire:

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

    $builder
        ->add('name', TextType::class, ['label' => 'L_PROFILE_EDIT_NAME', 'required' => false])
        ...
        ->add('figure_type', ChoiceType::class, [
            'label' => 'L_PROFILE_EDIT_FIGURETYPE',
            'mapped' => false,
            'choices' => $this->traitChoices['figure_type']
        ])
        ...
    ;
}

/**
 * {@inheritdoc}
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Foo\BarBundle\Entity\Profile',
        'trait_choices' => null,
    ));
}

Ensuite, lorsque vous créez le formulaire dans votre contrôleur, transmettez-le sous forme d'option plutôt que dans le constructeur:

$form = $this->createForm(ProfileEditType::class, $profile, array(
        'action' => $this->generateUrl('profile_update'),
        'method' => 'PUT',
        'trait_choices' => $traitChoices,
    ));
128
sekl

Ici, vous pouvez utiliser une autre approche - injecter un service pour récupérer des données.

  1. Décrivez votre formulaire en tant que service ( livre de recettes )
  2. Ajouter un champ protégé et un constructeur pour former une classe
  3. Utilisez un objet injecté pour obtenir les données dont vous avez besoin

Exemple:

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'
        ]);
    }

}
6
Denis

Voici comment transférer les données dans un formulaire incorporé pour toute personne utilisant Symfony 3. Commencez par faire exactement ce que @sekl a décrit ci-dessus, puis procédez comme suit:

dans votre type de formulaire principal

Passez la variable à la forme incorporée en utilisant ' entry_options '

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

dans votre type de formulaire incorporé

Ajouter l'option aux optionsResolver

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

Accédez à la variable dans votre fonction buildForm. N'oubliez pas de définir cette variable avant la fonction de générateur. Dans mon cas, je devais filtrer les options en fonction d'un identifiant spécifique.

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);
           }))
     ;
}
5
mcriecken

Si quelqu'un utilise les fonctions 'createNamedBuilder' ou 'createNamed' du service form.factory, voici l'extrait qui explique comment définir et enregistrer les données à l'aide de celui-ci. Vous ne pouvez pas utiliser le champ 'data' (laissez cette valeur nulle) et vous devez définir les données/entités transmises en tant que valeur $options.

J'ai également incorporé les instructions @sarahg sur l'utilisation des options setAllowedTypes () et setRequired () et cela semble fonctionner correctement, mais vous devez d'abord définir le champ avec setDefined ().

Également à l'intérieur du formulaire, si vous souhaitez que les données soient définies, n'oubliez pas de les ajouter au champ 'data'.

Dans Controller, j'utilise getBlockPrefix car getName est obsolète en 2.8/3.0.

Manette:

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

Forme:

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
Ethernal