首页 > 解决方案 > 根据另一个字段中的选择将实体加载到字段中 Symfony PRE_SET_DATA 事件监听器

问题描述

嗨,我收到了 OrderType 表格。

这是我的代码:

public function buildForm(FormBuilderInterface $builder, array $options)
{
   $builder
              ->add('client', EntityType::class, array(
              'data' => $options['client'],
              'mapped' => false,
              'attr' => ['class' => 'chosen-select','data-placeholder'=>'Wybierz klienta'],
              'class' => UserDetails::class,
              'choice_label' => function ($client) {
              return  ''.$firma.' '.$client->getJson()["client"]["imie"] .' '. $client->getJson()["client"]["nazwisko"].'';
               },
              'label' => 'Wybierz klienta'))


               ->add('save', SubmitType::class, [
               'label' => 'Zapisz',
               'attr' => ['class' => 'btn btn-primary pull-right']]) ;

    $builder->addEventListener( 
              FormEvents::PRE_SET_DATA,
                function (FormEvent $event) {
                       $form = $event->getForm();
                       $client =$form->get('client')->getData();
                       $shipping = null === $client ? array() : $client->getClientsShippings()->getJson()["clients_shippings"]["name"];

           $form->add('shipping', EntityType::class, array(
               'class' => ClientsShippings::class,
               'placeholder' => '',
               'choices' => $shipping));
             }
           );
}

没有错误,但也没有任何反应。我不知道如何实现这一点,在选择 EventListener 客户端后,PRE_SET_DATA 根据所选客户端在 ClientsShippings 实体中加载分配给客户端的送货地址。我在 symfony.com 上读了几次,但我无法完全理解这些事件。

有人可以帮我运行它,让我举个例子说明它是如何工作的。也许我以完全不同的方式思考它。


  public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
                ->add('client', EntityType::class, array(
    'data' => $options['client'],
    'mapped' => false,
    'attr' => ['class' => 'chosen-select','data-placeholder'=>'Wybierz klienta'],
    'class' => UserDetails::class,
    'choice_label' => function ($client) {
      if(isset($client->getJson()["client"]["firma"]))
      {
        $firma = $client->getJson()["client"]["imie"];
        }
        else {
          $firma = "";
          }
    return  ''.$firma.' '.$client->getJson()["client"]["imie"] .' '. $client->getJson()["client"]["nazwisko"].'';
      },
    'label' => 'Wybierz klienta'

                ))

        ->add('product', EntityType::class, array(
    'data' => $options['product'],
    'mapped' => false,
    'multiple' => true,
    'class' => Products::class,
    'attr' => ['class' => 'chosen-select','data-placeholder'=>'Wybierz produkt'],
    'choice_label' => function ($product) {
        return  ''.$product->getJson()["products"]["name"] .' | Stan Magazynowy: '.$product->getJson()["products"]["stock"].'';
      },
  'label' => 'Wybierz produkty'

        ))

            ->add('save', SubmitType::class, [
            'label' => 'Zapisz',
            'attr' => ['class' => 'btn btn-primary pull-right']])
        ;

    $builder->get('client')->addEventListener(
      FormEvents::POST_SUBMIT,
      function (FormEvent $event)
      {
        $form = $event->getForm();

        $form->getParent()->add('shipping', EntityType::class, [
          'class' => ClientsShippings::class,
          'placeholder' => 'Wybierz adres dostawy',
          'choices' => $form->getData()->getclientsShippings()
        ]);
      }
    );


    }

标签: phpformssymfonyentity

解决方案


Symfony 表单有两个主要用途:

  1. 创建一个新实体(Form::submit()被称为)
  2. 编辑现有实体(Form::setData()并被Form::Submit()调用)

注意:在这两种情况下,Form::handleRequest()都会调用之前Form::submit()检查请求是否可以提交。

我们有 2 类主要的表单事件:

  • 预填充表单期间的事件(仅用于编辑实体表单)
  • 表单提交期间的事件(用于新建和编辑实体表单)

1. 使用模型数据预填充表单

PRE_SET_DATA

PRE_SET_DATA事件获取您开始使用的数据的值(Order在您的情况下为 object),并在表单被实体对象的数据填充之前被调度。

您可以使用此活动来:

  • 在填充期间修改表单数据
  • 添加或删除表单域

POST_SET_DATA

此事件在Form::setData()方法被调用后立即触发,可用于:

  • 预填充表单后读取数据

POST_SET_DATA和事件都POST_SET_DATA在预填充表单数据期间调度。

2. 表格提交

预提交

Form::submit()这在或Form::handleRequest()被调用时被触发。此事件可用于:

  • 更改从请求中捕获的数据
  • 在提交数据之前添加或删除字段

提交

此事件在之后PRE_SUBMIT和期间Form::submit(模型和视图数据规范化之后,非规范化之前)调度。您可以使用此活动来:

  • 标准化后更改数据。

POST_SUBMIT 这个事件在Form::submit(). 您可以使用此活动来:

  • 非规范化后获取数据。

回答你的问题

您应该使用 2 个事件侦听器,一个用于PRE_SET_DATA,一个用于POST_SUBMIT

订单类型

class OrderType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('client', EntityType::class, array(
                'class' => UserDetails::class
            ))
            ->add('save', SubmitType::class)
        ;
    
        $modifier = function (FormInterface $form, Client $client = null) {
            $shippings = null === $client ? array() : $client->getClientsShippings();

            $form->add('shipping', EntityType::class, array(
                'class' => ClientsShippings::class,
                'choices' => $shippings,
            ));
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($modifier) {
                $orderData = $event->getData();
                $modifier($event->getForm(), $orderData->getClient());
            }
        );

        $builder->get('client')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($modifier) {
                $client = $event->getForm()->getData();
                $modifier($event->getForm()->getParent(), $client);
            }
        );
    }
}

您还应该shipping根据所选客户端进行 AJAX 调用(一些 JavaScript)来更新列表。


推荐阅读