Symfony4 CollectionType в форме возвращает массив вместо сущности

#php #symfony #symfony4 #php-7

#php #symfony #symfony4 #php-7

Вопрос:

Я работаю над проектом symfony 4. У меня есть форма, которая содержит CollectionType сущностей. Моя цель — добавить записи в эту коллекцию. Но когда я пытаюсь отправить форму, я получаю эту ошибку:

     Expected argument of type "AppEntitySessionLevels", "array" given at property path "session_levels"
 

Я следовал этой документации: https://symfony.com/doc/4.4/form/form_collections.html
и еще : https://symfony.com/doc/current/reference/forms/types/collection.html#allow-add

Когда я сбрасываю то, что отправляется через отправку, я получаю исходные записи как объекты SessionLevels, но новая запись отправляется как массив, который не может быть обработан. Как я могу отправить свою новую запись в коллекцию как сущность, а не как массив?

Вот моя основная форма :

 class ModifySessionForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('date', DateType::class, [
                'label' => 'Date de la session',
                'attr' => [
                    'class' => 'w-100'
                ]
            ])
            ->add('circuit', EntityType::class, [
                'choice_label' => 'name',
                'class' => Circuit::class,
                'label'=>false,
                'attr' => ['class' => 'd-none'],
            ])
            ->add('session_levels', CollectionType::class, [
                'entry_type' => SessionLevelType::class,
                'entry_options' => [
                    'label' => false
                ], 
                'label' => 'Niveaux',
                'allow_add'=> true,
                'by_reference' => false,
                'allow_delete' => true,
                'attr' => [
                    'class' => 'w-100'
                ]
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'Valider',
                'attr' => [
                    'class' => 'btn btn-lrt w-100 mt-3'
                ]
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => SessionDetails::class
        ]);

    }
}
 

Вот моя встроенная форма: SessionLevelType.php

 class SessionLevelType extends AbstractType
{
        public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('level', TextType::class, [
                'label' => false,
                'attr' => [
                    'class' => 'w-100'
                ]
            ])
            ->add('duration', TextType::class, [
                'label' => false,
                'attr' => [
                    'class' => 'w-100'
                ]
            ])
            ->add('number_of_participants', NumberType::class, [
                'label' => false,
                'html5' => true,
                'attr' => [
                    'class' => 'w-100',
                    'min' => '0'
                ]
            ])
            ->add('price', NumberType::class, [
                'label' => false,
                'html5' => true,
                'attr' => [
                    'class' => 'w-100',
                    'min' => '0',
                    'step' => '0.01'
                ]
            ])
        ;
    }
}
 

И вот мой метод контроллера :

     /**
    * @Route("/session/modify/{id}", name="admin_session_modify", requirements={"id": "d "})
    * @param Request $request
    * @param SessionDetails $sessionInModif
    * @param CircuitRepository $circuitRepo
    * @param AdminSessionService $SessionService
    * @return Response
    * @IsGranted("IS_AUTHENTICATED_REMEMBERED")
    */
    public function modifySession(Request $request,SessionDetails $sessionInModif,CircuitRepository $circuitRepo,AdminSessionService $SessionService)
    {
        $form = $this->createForm(ModifySessionForm::class, $sessionInModif);
        $form->handleRequest($request);
        //handle form submition
        if($form->isSubmitted() amp;amp; $form->isValid()) {
                    $entityManager = $this->getDoctrine()->getManager();
                    $entityManager->persist($sessionInModif);
                    $entityManager->flush();
        }   
        
        return $this->render('admin/sessions/modifSession.html.twig',[
            'form' => $form->createView(),
            'session' =>$sessionInModif,
            'circuits' => $circuitRepo->findAll()
        ]);
    }
 

Наконец, вот HTML и JS, которые связаны с материалом коллекции:

 <tbody  class="session_levels" data-prototype="{{ form_widget(form.session_levels.vars.prototype)|e('html_attr') }}">
                {% for lvl in form.session_levels %}
                    <tr>
                        <td>{{ form_row(lvl.level) }}</td>
                        <td>{{ form_row(lvl.duration) }}</td>
                        <td>{{ form_row(lvl.number_of_participants) }}</td>
                        <td>{{ form_row(lvl.price) }}</td>
                        <td><button type="button" style="border:none;" onClick="handleDeleteLvlEntry()"><i class="fas fa-trash-alt"></i></button></td>
                    </tr>
                    <script>levelsIdx  ;</script>
                {% endfor %}
                
                <tr id="inserterRow">
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td><button type="button" class="add_item_link" data-collection-holder-class="session_levels" style="border:none"><i class="fas fa-plus-square"></i></button></td>
                </tr>
            </tbody>
        </table>

        {{ form_row(form.session_levels) }}
    </div>
    
    {{ form_row(form.submit) }}
    {{ form_end(form) }}
{% endblock %}

{% block javascripts %}
    {{ parent() }}
    <script>
        
        $(document).ready(function() {
             
            var $levelsCollectionHolder = $('tr.session_levels');
            // count the current form inputs we have (e.g. 2), use that as the new
            // index when inserting a new item (e.g. 2)
            $levelsCollectionHolder.data('index', levelsIdx);

            $('body').on('click', '.add_item_link', function(e) {
                var $collectionHolderClass = $(e.currentTarget).data('collectionHolderClass');
                // add a new tag form (see next code block)
                addFormToCollection($collectionHolderClass);
            });
        });

        function addFormToCollection($collectionHolderClass) {
            // Get the ul that holds the collection of tags
            var $collectionHolder = $('.'   $collectionHolderClass);

            // Get the data-prototype explained earlier
            var prototype = $collectionHolder.data('prototype');

            // get the new index
            var index = $collectionHolder.data('index');
            if(index == undefined)
                index = levelsIdx;
            console.log(index)
            var newForm = prototype;
            // You need this only if you didn't set 'label' => false in your tags field in TaskType
            // Replace '__name__label__' in the prototype's HTML to
            // instead be a number based on how many items we have
             //newForm = newForm.replace(/__name__label__/g, levelsIdx);

            // Replace '__name__' in the prototype's HTML to
            // instead be a number based on how many items we have
            newForm = newForm.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 a tag" link li
            var $newFormLi = $('<tr></tr>').append(newForm.replace(/div/g,'td') '<td><button type="button" style="border:none;" onClick="handleDeleteLvlEntry()"><i class="fas fa-trash-alt"></i></button></td>');
            // Add the new form at the end of the list
            /*
            */
            $collectionHolder.append($newFormLi);
            $('#modify_session_form_session_levels_' index).addClass('d-none');
            levelsIdx  ;
            index  ;
            //move the inserting row to the bottom

            $("#inserterRow").clone().appendTo("#levelsTable");
             $("#inserterRow").remove(); 
        }
 

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

1. добавьте configureOptions с data_class SessionLevel(s) к вашему типу SessionLevelType, в противном случае этот тип формы будет создавать массивы

2. @Jakumi спасибо, что это было так. Это выдавало мне ошибку, но я просто забыл добавить оператор use для sessionLevels в SessionLevelType . В любом случае спасибо!