Динамически изменяйте предустановленные формы, чтобы пройти проверку в 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.

предосторожность

При этом каждая существующая отправленная сущность будет действительным значением. Если выбирается только часть объектов, вы также должны добавить ограничение к вашему полю.

Другие вопросы по тегам