SYMFONY FormTypeCollection с различными полями

#forms #symfony

#формы #symfony

Вопрос:

В моем проекте я хотел бы иметь возможность добавлять коллекцию в форму. Я думал о FormTypeCollection. Но дело в том, что мне нужно что-то подобное: кнопка «Создать» в конце формы, и каждый раз, когда вы нажимаете на новую, добавляется «мини-форма», и у вас есть три ввода для заполнения: «имя, текст, ссылка». Я бы хотел, чтобы он сохранялся в базе данных, например, как artists = [name,text,link]. Я понятия не имею, как это сделать. я не хочу добавлять исполнителя сущности, потому что мне это нужно только для отображения, и мне не нужно, чтобы он сохранялся как объект в базе данных. Мой код сейчас такой:

 protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->with('Contenu')
            ->add('published', CheckboxType::class, ['required' => false, 'label' => 'Publier'])
            ->add('title', TextType::class, ['required' => true, 'label' => 'Titre'])
            ->add('marketingEtiquette', TextType::class, ['required' => false, 'label' => 'Etiquette Marketing'])
            ->add('textLink', TextType::class, ['required' => true, 'label' => 'Texte du lien'])
            ->add('shoppingLink', TextType::class, ['required' => true, 'label' => 'Lien'])
            ->add('media', ElFinderType::class, array(
                'label' => 'Photo',
                'instance' => 'form',
                'enable' => true,
                'required' => true,
                'attr' => array('class' => 'form-control')
                )
            )
            ->add('position',ChoiceType::class, array(
                'label' => 'Position dans la page',
                'choices' => array(
                    'Bloc Artistes' => 'artists',
                    'Bloc haut de page' => 'top',
                    'Bloc bas de page' => 'bottom'
                )
            ))
            ->add('artists',CollectionType::class,array(
                'label' => 'Les artistes',
                'allow_add' => true,
            ))
            ->end();
    }
  

Я не знаю, как добавить 3 поля к исполнителям полей и сгенерировать их при нажатии кнопки добавления. я даже не знаю, возможно ли это на самом деле. Я также не знаю, каким должен быть тип «исполнители» в базе данных.

РЕДАКТИРОВАТЬ: я хотел бы сделать что-то подобное, поэтому мне не нужно создавать объект или FormType:

 ->add('artists',CollectionType::class,array(
                'entry_type' => TextType::class ,
                'entry_options' => [
                    'artistName' => TextType::class,
                    'artistText' => TextType::class,
                    'artistLink' => TextType::class,
                ],
                'label' => 'Les artistes',
                'allow_add' => true,
                'allow_delete' => true,
                'delete_empty' => true,
                'by_reference' => false
            ))
  

Но это не работает, поэтому, я думаю, я не могу. Ошибка:

 The current field `artists` is not linked to an admin. Please create one for the target entity : ``
  

РЕДАКТИРОВАТЬ 2:
Я создал свой ArtistFormType:

 class ArtistFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('artistName', TextType::class, array(
                'label' => 'Nom de l'artiste'
            ))
            ->add('artistText', TextType::class, array(
                'label' => 'Texte sous l'artiste'
            ))
            ->add('artistLink', TextType::class, array(
                'label' => 'Lien vers l'artiste'
            ))
            ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
           'data_class' => null,
       ]);
    }
}
  

Я назвал это так:

 ->add('artists',CollectionType::class,array(
                'entry_type' => ArtistFormType::class,
                'label' => 'Les artistes',
                'allow_add' => true,
                'allow_delete' => true,
                'delete_empty' => true,
                'by_reference' => false
            ))
  

Но я получаю ту же ошибку:

 The current field `artists` is not linked to an admin. Please create one for the target entity : ``
  

Ответ №1:

РЕДАКТИРОВАТЬ: это решение ограничено Symfony Component Form Extension Core Type CollectionType, оно может отличаться от решения от Sonata Admin.

Вы можете найти некоторую информацию об этом в документации.

«Самый простой» способ сделать это — создать другую форму (например, ArtistFormType) с полями, которые вы хотите добавить. Затем в вашей родительской форме вы добавляете CollectionType :

 $formMapper
        // ...
        ->add('artists', CollectionType::class, [
            'entry_type' => ArtistFormType::class,
            'label' => 'Artists',
            'allow_add' => true,
            'allow_delete' => true,
            'delete_empty' => true,
            'by_reference' => false
        ])
    ;
  

Затем, если у вас уже есть несколько исполнителей в вашей сущности, он будет отображать ArtistFormType один раз для каждого исполнителя.

Если вы хотите добавить новых исполнителей, это немного сложнее и требует некоторого Javascript.

Сначала отобразите коллекцию внутри <ul></ul> тега :

 <ul class="artists">
    {{ form_row(form.artists) }}
</ul>
  

Следуя этому jsfiddle :
Найдите коллекцию и добавьте к ней кнопку «добавить исполнителя»

 <script>
var $addArtistLink = $('<a href="#" class="add_artist_link">Add an artist</a>');
var $newLinkLi = $('<li></li>').append($addArtistLink);

jQuery(document).ready(function() {
    // Get the ul that holds the collection of artists
    var $collectionHolder = $('ul.artists');

    // add the "add a tag" anchor and li to the tags ul
    $collectionHolder.append($newLinkLi);
    
    // ...
}
</script>
  

Добавьте событие «click» с некоторыми манипуляциями с dom, чтобы добавить новых исполнителей :

 jQuery(document).ready(function() {
    // ...
    
    // count the current form inputs we have (e.g. 2), use that as the new
    // index when inserting a new item (e.g. 2)
    $collectionHolder.data('index', $collectionHolder.find(':input').length);

    $addArtistLink.on('click', function(e) {
        // prevent the link from creating a "#" on the URL
        e.preventDefault();
    
        // add a new artist form
        addArtistForm($collectionHolder, $newLinkLi);
    });


});

function addArtistForm($collectionHolder, $newLinkLi) {
    // Get the data-prototype explained earlier
    var prototype = $collectionHolder.data('prototype');

    // get the new index
    var index = $collectionHolder.data('index');

    // Replace '$$name$$' in the prototype's HTML to
    // instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // increase the index with one for the next item
    $collectionHolder.data('index', index   1);

    // Display the form in the page in an li, before the "Add an artist" link li
    var $newFormLi = $('<li></li>').append(newForm);

    // also add a remove button
    $newFormLi.append('<a href="#" class="remove-artist">x</a>');

    $newLinkLi.before($newFormLi);

    // handle the removal
    $('.remove-artist').click(function(e) {
        e.preventDefault();
    
        $(this).parent().remove();
    
        return false;
   });
  

}

Тогда все должно работать нормально. Конечно, некоторые изменения могут быть внесены в соответствии с вашим проектом (имена полей, добавить кнопку удаления для существующих исполнителей, …).

Комментарии:

1. Большое спасибо за ваш ответ! Я пытаюсь, но для этого мне нужно создать объект Artist? Дело в том, что я бы не хотел создавать объект Artist. Возможно ли это? Или мне нужно создать объект?

2. Я думаю, что будет проще (и лучше) создать объект Artist с отношением ManyToOne к объекту основной формы. Если вы действительно не хотите создавать эту сущность, вы можете указать «‘data_class’ => null» в вашем ArtistFormType, и тогда данные будут нормализованы как массив, а не как объект.

3. Хорошо, потому что я думал, что смогу сделать что-то вроде того, что я сделал в своем редактировании, тогда это невозможно?

4. Так не получится. Я думаю, вам, по крайней мере, придется создать ArtistFormType . Кроме того, «entry_options» используется для установки параметров FormType в «entry_type», а не полей, как вы сделали в своем редактировании.

5. Хорошо, я сделал это, но не работает, я отредактировал свой вопрос ^^