Ошибка проверки Symfony на вложенной форме для динамически модифицированного поля - PullRequest
0 голосов
/ 04 января 2019

У меня есть встроенные формы с полем сущности. Активность в подформе динамически заполняется данными из модуля модуля, данные которого задаются с помощью запроса ajax.

Но когда я отправляю форму, у меня появляется ошибка проверки («это значение недопустимо»), и поле активности остается пустым.

Принцип: основная форма (Session) имеет поле сущности module и содержит коллекцию (Timeslot). В подчиненной форме Таймслота есть поле 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.

Я также пытался изменить свой TimeslotType, следуя этому symfony doc но я сталкиваюсь с проблемой, что в моем случае поле Module не находится в том же formBuilder, что и Activity, поэтому в моем случае нельзя применять обработчик событий 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:

<code>    $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 '
'; echo '
data AFTER=';var_dump($data);echo '
'; echo '
module AFTER';var_dump($moduleId);echo '
'; } );

у меня

form AFTER= NULL
data AFTER= array(
  ["activity"]=>
    string(3) "573"   <= which is the value i selected
...
)
module AFTER  int(0)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...