Дважды визуализируйте прототип типа коллекции в форме Symfony

#php #symfony #symfony-forms

Вопрос:

В форме Symfony для типа коллекции с add опцией есть ли способ дважды отобразить прототип? Или чистый (см. Ниже) способ задать полный путь к полям в представлении формы, чтобы я мог дважды отобразить строку прототипа с соответствующими ключами и __name__ заполнителем.

Пример использования:

У меня есть коллекция предметов нескольких типов (т. е. видео слайд, текстовый слайд и т.д.), разделяющие один и тот же тип, но сильно различающиеся в представлении HTML-формы. Поэтому у меня есть отдельные кнопки «Добавить xxxx» для добавления новых полей определенных типов (добавить текстовый слайд, добавить видео слайд и т. Д.), Связывающие отдельные строки прототипа. Проблема в том, что когда я пытаюсь использовать общий прототип в качестве источника визуализации, я не могу отобразить одно и то же поле дважды, поэтому на второй кнопке строка прототипа содержит только поля, не отображенные для первого.

Опробованные решения:

Я попытался вручную установить full_name для полей, но я не знаю чистого, не взломанного способа сделать это (я знаю, что могу установить blockPrefix, но этого недостаточно).

Самый простой способ сделать это-создать новое представление формы и поменять местами ключи вот так. Это работает, но смешно:

 
// EDIT: For nested fields (eg. radio buttons) you need to make 
// the swap recursive, hence copyFields method was added. 
// ALSO: I know it's not generalized in any way but it's a hack 
// and I hope to get rid of it. ;-) 

   private function getTimelinePrototypes(FormView $sourceFormView, int $num) {
        /** @var FormView */
        $timelinesFormView = $sourceFormView->children['timelines'];
        /** @var FormView */
        $tlProto = $timelinesFormView->vars['prototype'];
        
        $protoForms = []; 
        // GET FORM VIEWS FOR MULTI PROTOYPES:
        for ($i = 0; $i < $num; $i  ) {
            $targetForm = $this->createForm(TimelineType::class, null, [])->createView();
            $this->copyFields($tlProto, $targetForm);
            $protoForms[] = $targetForm;
        }
        return $protoForms;
    }

    private function copyFields (FormView $sourceForm, FormView $targetForm) {
        foreach($targetForm->children as $fieldKey => $targetField) {
            $sourceField = $sourceForm->children[$fieldKey];
            foreach(['full_name', 'id', 'name', 'cache_key', 'unique_block_prefix', 'block_prefixes', ] as $key) {
                $targetField->vars[$key] = $sourceField->vars[$key];
            }
            if (count($sourceField->children) > 0) {
                $this->copyFields($sourceField, $targetField);
            }
        }
    }