2015-12-01 4 views
71

Мое приложение в настоящее время передает данные в мой тип формы с использованием конструктора, как рекомендовано в this answer. Однако Symfony 2.8 upgrade guide советует, что передача экземпляра типа функции createForm осуждается:Передача данных в buildForm() в Symfony 2.8/3.0

экземпляры типа Passing в форму :: добавить(), FormBuilder :: добавить() и FormFactory :: создать *() методы устарел и не будет поддерживаться в Symfony 3.0. Вместо этого передайте полное имя класса .

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

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

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

+0

Какие данные необходимо передать? Это что-то, что можно вводить? – Cerad

+2

Надеемся, что UPGRADE.md улучшится: https://github.com/symfony/symfony/issues/18662 – althaus

ответ

108

Это сломало некоторые наши формы. Я исправил его, передав пользовательские данные через опцию resolver.

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

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, 
    )); 
+1

Рад слышать, что я не единственный! Великолепное решение, спасибо. – Jonathan

+8

Только что столкнулся с этой проблемой и сделал аналогичное решение. Я думаю, что если данные необходимы, и если вы хотите сделать тип намека типа, который вы обычно делаете в определении конструктора, вы должны использовать методы setRequired() и setAllowedTypes() для параметра resolver в вашем configureOptions() , а не setDefaults(). – sarahg

+2

Это именно то, что вы должны делать. :) –

5

В случае, если кто использует функции «createNamedBuilder» или «createNamed» из сервиса form.factory - это фрагмент, посвященный тому, как установить и сохранить данные, используя это. Вы не можете использовать поле data (оставить это значение null), и вам необходимо установить переданные данные/сущности как значение $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', 
      ) 
     ) 
... 
} 
3

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

В вашей основной FormType

Пропустите вар к встраиваемой форме с помощью 'entry_options'

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

В вашем Embedded FormType

Добавить вариант в optionsResolver

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

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

  1. Опишите форму, как сервис (cookbook)
  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' 
     ]); 
    } 

} 
+0

Это хорошо, но не будет работать, если аргумент недоступен менеджеру службы. – demonkoryu

Смежные вопросы