Truyền dữ liệu đến buildForm () trong Symfony 2.8, 3.0 trở lên


87

Ứng dụng của tôi hiện chuyển dữ liệu đến loại biểu mẫu của tôi bằng cách sử dụng hàm tạo, như được đề xuất trong câu trả lời này . Tuy nhiên, hướng dẫn nâng cấp Symfony 2.8 khuyên rằng việc chuyển một thể hiện kiểu cho createFormhàm không được dùng nữa:

Việc chuyển các thể hiện kiểu cho các phương thức Form :: add (), FormBuilder :: add () và FormFactory :: create * () không được dùng nữa và sẽ không được hỗ trợ nữa trong Symfony 3.0. Thay vào đó, hãy chuyển tên lớp đủ điều kiện của loại.

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

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

Nhìn thấy vì tôi không thể chuyển dữ liệu với tên lớp đủ điều kiện, có giải pháp thay thế không?


1
Bạn cần chuyển loại dữ liệu nào? Nó là thứ có thể được tiêm?
Cerad

2
Hy vọng rằng UPGRADE.md được cải thiện: github.com/symfony/symfony/issues/18662
althaus

Câu trả lời:


133

Điều này cũng phá vỡ một số hình thức của chúng tôi. Tôi đã sửa nó bằng cách chuyển dữ liệu tùy chỉnh qua trình phân giải tùy chọn.

Trong biểu mẫu của bạn, hãy nhập:

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

Sau đó, khi bạn tạo biểu mẫu trong bộ điều khiển của mình, hãy chuyển nó vào dưới dạng một tùy chọn thay vì trong hàm tạo:

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

8
Tôi cũng chỉ gặp vấn đề này và đã thực hiện một giải pháp tương tự. Tôi nghĩ rằng nếu dữ liệu là bắt buộc và nếu bạn muốn thực hiện kiểu gợi ý kiểu mà bạn thường làm trong định nghĩa hàm tạo, bạn nên sử dụng các phương thức setRequired () và setAllowedTypes () cho trình phân giải tùy chọn trong configOptions () , thay vì setDefaults ().
sarahg

2
Đó chính xác là những gì bạn nên làm. :)
Bernhard Schussek

3
@Roubi bạn làm điều tương tự, bạn xác định một tùy chọn trong phương thức configOptions và sau đó chuyển nó khi thêm một trường biểu mẫu.
Bart Wesselink

2
Tôi cũng không hài lòng với sự thay đổi này. Cảm ơn vì câu trả lời.
Adambean

2
FormTypes hoạt động giống như các nhà máy, chúng phải là không trạng thái. Việc đưa các giá trị thông qua phương thức khởi tạo của chúng (không phải thông qua phương thức thẻ dịch vụ) làm cho nó trở nên trạng thái. Bằng cách này, bạn có 1 cách thống nhất để tạo loại biểu mẫu của mình. Các tùy chọn luôn được sử dụng thay vì các đối số của hàm tạo. Sự thay đổi này là rất tốt cho DX và khả năng sử dụng.
Bất cứ ai

6

Ở đây có thể được sử dụng một cách tiếp cận khác - dịch vụ tiêm để lấy dữ liệu.

  1. Mô tả biểu mẫu của bạn dưới dạng dịch vụ ( sách nấu ăn )
  2. Thêm trường được bảo vệ và phương thức khởi tạo để tạo lớp
  3. Sử dụng đối tượng được chèn để nhận bất kỳ dữ liệu nào bạn cần

Thí dụ:

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

}

Điều này là tốt, nhưng sẽ không hoạt động khi đối số không có sẵn cho người quản lý dịch vụ.
devilkoryu

5

Trong trường hợp bất kỳ ai đang sử dụng các chức năng 'createNamedBuilder' hoặc 'createNamed' từ dịch vụ form.factory, đây là đoạn mã về cách đặt và lưu dữ liệu bằng cách sử dụng nó. Bạn không thể sử dụng trường 'dữ liệu' (để trống) và bạn phải đặt dữ liệu / thực thể đã chuyển làm $optionsgiá trị.

Tôi cũng đã kết hợp các hướng dẫn @sarahg về cách sử dụng các tùy chọn setAllowedTypes () và setRequired () và nó có vẻ hoạt động tốt nhưng trước tiên bạn cần xác định trường với setDefined ()

Ngoài ra bên trong biểu mẫu nếu bạn cần đặt dữ liệu, hãy nhớ thêm nó vào trường 'dữ liệu'.

Trong Bộ điều khiển, tôi đang sử dụng getBlockPrefix vì getName không được dùng nữa trong 2.8 / 3.0

Bộ điều khiển:

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

Hình thức:

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

Đây là cách chuyển dữ liệu sang biểu mẫu nhúng cho bất kỳ ai sử dụng Symfony 3. Trước tiên, hãy thực hiện chính xác những gì @sekl đã nêu ở trên và sau đó thực hiện như sau:

Trong FormType chính của bạn

Chuyển var vào biểu mẫu nhúng bằng cách sử dụng ' entry_options '

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

Trong Loại Biểu mẫu Nhúng của bạn

Thêm tùy chọn vào các tùy chọn

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

Truy cập biến trong hàm buildForm của bạn. Hãy nhớ đặt biến này trước hàm trình tạo. Trong trường hợp của tôi, tôi cần lọc các tùy chọn dựa trên một ID cụ thể.

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

Để bớt nhầm lẫn - $ this-> var là giá trị của bạn mà bạn muốn chuyển, không nhất thiết phải từ biến lớp.
Darius.V
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.