У меня есть встроенные формы с полем сущности. Активность в подформе динамически заполняется данными из модуля модуля, данные которого задаются с помощью запроса 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)