动态修改字段的嵌套表单上的symfony验证错误

时间:2019-01-04 10:43:59

标签: forms symfony

我有一个嵌入的表单,其中的实体字段Activity是子表单,动态填充了来自字段模块的数据,该字段的数据是通过ajax请求设置的。

但是当我提交表单时,我遇到验证错误(“此值无效”),并且活动字段为空白。

原理: 主表单(会话)具有一个实体字段module,并包含一个集合(时隙)。 “时间段”子表单具有字段activity,其内容取决于模块值。

我的表格:

class SessionType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder
      ->add('module', EntityType::class, [
        'label' => 'module.name',
        'required' => true,
        'class' => Module::class,
        'placeholder' => 'choose',
      ])
      ->add('timeslots', CollectionType::class, [
        'required' => true,
        'constraints' => new Valid(),
        'prototype_name' => '__timeslot_prot__',
        'entry_type' => TimeslotType::class,
        'entry_options' => ['module' => isset($module) ? $module->getId() : 0],
        'by_reference' => false,
        'allow_add' => true,
        'allow_delete' => true,
      ]);
  }
  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults([
      'data_class' => Session::class,
      'module' => null,
    ]);
  }
}

And the Timeslot

class TimeslotType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $module = $options['module'];

    $builder
      ->add('activity', EntityType::class, [
      'class' => Activity::class,
      'multiple' => false,
      'required' => true,
      'constraints' => new NotBlank(),
      'query_builder' => function (ActivityRepository $activity) use ($module) {
        if (null !== $module) {
          $qb = $activity->createQueryBuilder('a')
            ->join('a.activityGroups', 'ag')
            ->join('ag.module', 'm')
            ->where('m.id = :mid')
            ->setParameter('mid', $module)
            ->orderBy('a.name', 'ASC');
          return $qb;
        } else {
          $qb = $activity->createQueryBuilder('a')
            ->where('a.id = 0');
          return $qb;
        }
      },
    ]);
  }
  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults([
      'data_class' => Timeslot::class,
      'module' => null,
    ]);
  }
}

我还有一个JavaScript脚本,可通过ajax调用用查询填充“活动选择”选项。

我还尝试遵循此symfony doc修改我的TimeslotType 但是我偶然发现了一个问题,就我而言,Module字段与Activity不在同一formBuilder中,因此POST_SUBMIT事件侦听器无法应用于我的情况。

class TimeslotType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $module = $options['module'];

    $formModifier = function (FormInterface $form, Module $module = null) {
      $activities = [];
      if (null !== $module){
        foreach($module->getActivityGroups() as $ag){
          foreach($ag->getActivities() as $activity){
            $activities[] = $activity;
          }
        }
      }

      $form->add('activity', EntityType::class, [
        'label' => 'timeslot.activity',
        'label_attr' => ['class' => 'mandatory', 'data-extrainfo' => 'panel_timeslot'],
        'attr' => [
          'class' => 'activitieslist',
        ],
        'class' => Activity::class,
        'multiple' => false,
        'required' => true,
        'constraints' => new NotBlank(),
        'choices' => $activities,
        'choices_as_values' => true,
      ]);
    };

    $builder->addEventListener(
      FormEvents::PRE_SET_DATA,
      function (FormEvent $event) use ($formModifier) {
        // the entity : Timeslot
        $data = $event->getData();

        $formModifier($event->getForm(), $module);
      }
    );

    //$builder->get('module') ... Makes no sense here since the module attribute is not a Timeslot, but belongs to Session
    /*
    $builder->get('module')->addEventListener(FormEvents::PRE_SUBMIT,
      function (FormEvent $event) use ($formModifier) {
        $module = $event->getForm()->getData();

        $formModifier($event->getForm()->getParent(), $module);
      }
    );
    */
  }

  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults([
      'data_class' => Timeslot::class,
      'module' => null,
    ]);
  }
}

如何解决我的问题并验证我的表格?

===

编辑

更改模块字段时将调用ajax请求

function updateActivities(block) {
    var module = $('#session_module').val();
    if (module != ''){
        $.ajax({
            url: Routing.generate('project_module_activities_ajax', {}),
            data: { 'module': module },
            method: 'POST',
            success: function (activities) {
              var sel = '';
              for (var i = 0; i < activities.length; i++) {
                sel += '<option value="' + activities[i].id + '">' + activities[i].name + '</option>'
              }
              $('#litimeslot'+block).find('.activitieslist').each(function () {
                $(this).html(sel);
              })
            }
        });
    }
}

并且路由project_module_activities_ajax只是从查询中返回模块的活动数组 像这样:

[
    ['id' : 1, 'name' : 'activity 1'],
    ['id' : 2, 'name' : 'activity 2'],
}

编辑2

如果我将此事件监听器添加到TimeslotType中:

    $builder->addEventListener(FormEvents::PRE_SUBMIT,
      function (FormEvent $event) use ($moduleId) {
        $form = $event->getForm();
        $data = $event->getData();
echo '<pre>form AFTER=';var_dump($form->getData());echo '</pre>';
echo '<pre>data AFTER=';var_dump($data);echo '</pre>';
echo '<pre>module AFTER';var_dump($moduleId);echo '</pre>';
      }
    );

我有

form AFTER= NULL
data AFTER= array(
  ["activity"]=>
    string(3) "573"   <= which is the value i selected
...
)
module AFTER  int(0)

0 个答案:

没有答案