Динамически изменяйте предустановленные формы, чтобы пройти проверку в symfony2
Я хочу иметь возможность динамически добавлять объекты без предварительной установки их в опции выбора для типа формы EntityType. Мне нужно изменить доступные варианты, потому что в противном случае invalid value
ошибка выскакивает.
class MyImageType extends AbstractType {
public function __construct($em) {
$this->em = $em;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'class' => 'stuff/MyImage',
'choice_label' => 'id',
'multiple' => true,
'choices' => [],
));
}
public function buildForm(FormBuilderInterface $builder, array $options) {
//
}
public function getParent() {
return EntityType::class;
}
}
и я использую это так:
$builder->add('images', 'stuff\MyImage\Form\Type\MyImageType')
сгенерированный HTML выглядит так:
<select id="product_images" name="product[images][]" required="required" class="form-control" multiple="multiple">
</select>
Я выполняю несколько вызовов ajax, чтобы создать сущность и добавить идентификатор в раскрывающийся список следующим образом:
<select id="product_images" name="product[images][]" required="required" class="form-control" multiple="multiple">
<option value="88" selected="selected">88</option>
</select>
88
это существующий идентификатор для существующего объекта.
Если я отправлю форму после этого, invalid value
ошибка появляется, потому что 88
не в предустановке choices
для этого типа объекта. Так что мне нужно добавить 88
в доступных вариантах.
Если бы это был дочерний элемент формы (Symfony\Component\Form\Form), я мог бы сделать это на FormEvents::PRE_SUBMIT
//..
$img = $em->findOneById(88);
$form->add('images', [
'class' => 'stuff/MyImage',
'choice_label' => 'id',
'multiple' => true,
'choices' => [$img],
]);
но в моем случае я хочу сделать это внутри MyImageType
класс для инкапсуляции класса. Можете ли вы дать мне указания, как это сделать? Благодарю.
РЕДАКТИРОВАТЬ:
В процессе написания этого вопроса я нашел решение для этого. В случае, если я могу обновить поле следующим образом:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use($em) {
$form = $$event->getForm();
$form->getParent()->add('images', EntityType::class, $options);
}
Тем не менее, я не хочу отвечать на свой вопрос, потому что, возможно, есть лучший способ сделать это. Благодарю.
1 ответ
Я знаю, что это старый вопрос, и я видел ваше последнее изменение, но я думаю, что ваше решение должно выглядеть примерно так (чтобы также сохранить имя "встроенной" формы и ее класс, потому что это не EntityType, а настраиваемый тип.
Я добавил этот фрагмент кода в свой собственный тип формы:
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options): void {
$data = $event->getData();
if ($data === null || $data === []) {
return;
}
// The following works with both "multiple" true and false.
$entityIds = is_array($data) ? $data : [$data];
$entities = $this->yourInjectedRepository->findByIds($entityIds);
// Self-replace this form in its parent with a clone (same name and options) that has the needed choices.
$options['choices'] = $entities;
$event->getForm()->getParent()->add(
$event->getForm()->getName(),
self::class,
$options
);
});
}
Посмотрите на мой FormBundle.
Чтобы решить эту проблему, я подключаю PRE_SUBMIT FormEvent и воссоздаю дочерний элемент, внедряя отправленные варианты в новую опцию 'выборы'.
Если вы хотите, чтобы ваше поле заполнялось при редактировании сущности, вы должны сделать то же самое в PRE_SET_DATA.
предосторожность
При этом каждая существующая отправленная сущность будет действительным значением. Если выбирается только часть объектов, вы также должны добавить ограничение к вашему полю.