Передача данных в buildForm() в Symfony 2.8/3.0


Мое приложение в настоящее время передает данные в мой тип формы с помощью конструктора, как рекомендовано в этом ответе . Однако в Руководстве по обновлению Symfony 2.8 сообщается, что передача экземпляра типа функции createForm не рекомендуется:

Передача экземпляров типов в методы Form::add(), FormBuilder::add() и FormFactory::create*() устарела и больше не будет поддерживаться в Symfony 3.0. Передайте полное имя класса типа вместо.

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

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

Поскольку я не могу передавать данные с полным именем класса, есть ли альтернатива?

 72
Author: Community, 2015-12-01

4 answers

Это также нарушило некоторые из наших форм. Я исправил это, передав пользовательские данные через распознаватель параметров.

В вашей форме введите:

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

Затем, когда вы создадите форму в своем контроллере, передайте ее в качестве опции, а не в конструкторе:

$form = $this->createForm(ProfileEditType::class, $profile, array(
        'action' => $this->generateUrl('profile_update'),
        'method' => 'PUT',
        'trait_choices' => $traitChoices,
    ));
 113
Author: sekl, 2015-12-02 05:38:48

На случай, если кто-то использует функции "createnamedbuilder" или "createnamed" из службы form.factory, вот фрагмент о том, как установить и сохранить данные с его помощью. Вы не можете использовать поле "данные" (оставьте это значение пустым), и вы должны установить переданные данные/сущности в качестве значения $options.

Я также включил инструкции @sarahg об использовании параметров setAllowedTypes() и setrequired(), и, похоже, все работает нормально, но сначала вам нужно определить поле с помощью setdefined()

Также внутри форма если вам нужны данные для установки, не забудьте добавить их в поле "данные".

В контроллере я использую getBlockPrefix, так как getName устарел в 2.8/3.0

Контроллер:

/*
* @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
Author: Ethernal, 2015-12-11 07:23:04

Здесь можно использовать другой подход - внедрить сервис для извлечения данных.

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

}
 5
Author: Denis, 2016-07-06 08:01:17

Вот как передать данные во встроенную форму для всех, кто использует Symfony 3. Сначала сделайте в точности то, что @sekl описал выше, а затем выполните следующее:

В вашем основном типе формы

Передайте var во встроенную форму, используя ' параметры ввода'

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

В вашем встроенном типе формы

Добавьте параметр в решатель параметров

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

Получите доступ к переменной в вашей функции buildForm. Не забудьте установить эту переменную перед функция строителя. В моем случае мне нужно было отфильтровать параметры на основе определенного идентификатора.

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);
           }))
     ;
}
 4
Author: mcriecken, 2016-02-03 18:20:56