Symfony 动态表单:"string"、"NULL" 类型的预期参数在 属性 路径 "civilite" 处给出

Symfony Dynamic Form : Expected argument of type "string", "NULL" given at property path "civilite"

我尝试编写一个动态表单来编辑用户。

里面有邮政编码(codePostal)。如果有人更改邮政编码,它应该更改城市列表(公社)。 我使用 Symfony 推荐的动态形式。这适用于我的 RegisterForm,但不适用于此 editForm。

我想,我想念从用户那里获取信息的东西? 因此,每次我更改邮政编码时,它都无法获取动态表单并在我的控制台中创建此异常(ajax):"string"、"NULL" 类型的预期参数在 属性路径"civilite".

这个异常是在$form->handleRequest($request); 上产生的;我的控制器,但就在我更改邮政编码时,而不是在第一次加载表单时。

这是我的代码:


//Form/EditUserFormType.php

class EditUserFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $user = $options['data'];

        $builder
            ->add('civilite',ChoiceType::class, array(
                'choices' => array('M.' => '1', 'Mme'  => '2'),
                'required' => true,
                'expanded' => true,
                'multiple' => false,
                'data' => $user->getCivilite()
            ))
            ->add('nom')
            ->add('prenom')
            ->add('societe')
            ->add('telephone')
            ->add('adresse')


            ->add("codePostalAutoComplete", TextType::class, [
                "mapped"=>false, 
                'required' => false,
                "label"=>"Code postal",
                ])

            ->add('codePostal', EntityType::class, [
                'class'       => 'App\Entity\CodePostal',
                'placeholder' => ''/

            ])

            ->add('email');

        $formModifier = function (FormInterface $form, CodePostal $codePostal = null) {
            $communes = null === $codePostal ? [] : $codePostal->getCommunes();

            $form->add('commune', EntityType::class, [
                'class' => 'App\Entity\Commune',
                'placeholder' => 'Choisir une commune',
                'choices' => $communes,  
            ]); 
        };




        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                // this would be your entity, i.e. SportMeetup
                $data = $event->getData();

                $formModifier($event->getForm(), $data->getCodePostal());
            }
        );




        $builder->get('codePostal')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {

                $codePostal = $event->getForm()->getData();


                $formModifier($event->getForm()->getParent(), $codePostal);
            }
        );
} 



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

//Controller/AccountController.php

public function edit(Request $request): Response
    {

        $em = $this->getDoctrine()->getManager();
        $user = $this->getUser();
        $form = $this->createForm(EditUserFormType::class,$user);



        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

                $em = $this->getDoctrine()->getManager();       
                $em->persist($user);
                $em->flush();

                $this->addFlash('notice', 'Vos modifications on bien été prises en compte !');

                return $this->redirectToRoute('app_account_dashboard');

        }

        return $this->render('account/edit.html.twig', array(
            'user' => $user,
            'form' => $form->createView(),
        ));
    }

//templates/account/edit.html.twig

{% extends 'base.html.twig' %}


{% block stylesheets %}

    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

    <script>
        $(document).ready(function () {

            var $codePostalAutoComplete = $('#edit_user_form_codePostalAutoComplete');
            var $codePostal = $('#edit_user_form_codePostal');

            $codePostalAutoComplete.change(function () {

                $newValue = $codePostalAutoComplete.val();
                $('#edit_user_form_codePostal option').filter(function () {
                    return($(this).text() == $newValue); // To select Blue
                }).prop('selected', true);

                // ... retrieve the corresponding form.
                var $form = $(this).closest('form');
                // Simulate form data, but only include the selected codepostal value.
                console.log($form); 
                var data = {};
                data[$codePostal.attr('name')] = $codePostal.val();
                // Submit data via AJAX to the form's action path.
                $.ajax({
                    url: $form.attr('action'),
                    type: $form.attr('method'),
                    data: data,
                    success: function (html) { // Replace current position field ...
                        $('#edit_user_form_commune').replaceWith(
                            // ... with the returned one from the AJAX response.
                                $(html).find('#edit_user_form_commune')
                        );
                        // Position field now displays the appropriate positions.
                    }
                });
            })


        });
    </script>
{% endblock %}

{% block title %}Modifier mon compte
{% endblock %}

{% block body %}

    <h1>Modifier mon compte</h1>

    {{ form_start(form) }}

    {{ form_row(form.civilite) }}
    {{ form_row(form.nom) }}
    {{ form_row(form.prenom) }}
    {{ form_row(form.societe) }}
    {{ form_row(form.adresse) }}
    {{ form_row(form.codePostalAutoComplete) }}
    <div style="none;">{{ form_row(form.codePostal) }}</div>
    {{ form_row(form.commune) }}
    {{ form_row(form.telephone) }}
    {{ form_row(form.email) }}
</p>


<button class="btn" type="submit">Valider</button>
{{ form_end(form) }}{% endblock %}

有什么想法吗?谢谢

正如@msg 在评论中所说,我需要使用另一个控制器来获取我需要的子表单;

//AccountController.php


public function editCommunesFieldByCodePostal(Request $request, CodePostalRepository $codePostalRepository)
    {
        $codePostal = $codePostalRepository->find($request->query->get('codePostalId'));

        if (isset($codePostal)){


            $user = new User();
            $user->setCodePostal($codePostal);

            $form = $this->createForm(EditUserFormType::class, $user);

            //dump($form);
            //die();

            if (!$form->has('user')) {
                return new Response(null, 204);
            }
            return $this->render('account/_specific_commune.html.twig', [
                'form' => $form->createView(),
            ]);
        }
    }
//account/edit.html.twig


{% block body %}

    <h1>Modifier mon compte</h1>

    {{ form_start(form) }}

    {{ form_row(form.civilite) }}
    {{ form_row(form.nom) }}
    {{ form_row(form.prenom) }}
    {{ form_row(form.societe) }}
    {{ form_row(form.adresse) }}
    {{ form_row(form.codePostalAutoComplete) }}
    <div style="display:none;">
    {{ form_row(form.codePostal, {
                attr: {
                    'data-specific-location-url': path('app_account_edit_communes_by_codepostal'),
                    'class': 'js-user-form-codePostal'
                }
            }) }}
    </div>

    <div class="js-specific-commune-target">
        {%  if form.commune is defined %}
            {{ form_row(form.commune, {
                attr: {
                    'class': 'js-user-form-commune'
                }
            }) }}
     {% endif %}
    </div>

    {{ form_row(form.telephone) }}
    {{ form_row(form.email) }}
</p>


<button class="btn" type="submit">Valider</button>
{{ form_end(form) }}


{% endblock %}


{% block javascripts %}
{{ parent() }}
 <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
$(document).ready(function() {




    $('#edit_user_form_codePostalAutoComplete').on('change', function(e) {


        $newValue = $('#edit_user_form_codePostalAutoComplete').val();
        $('#edit_user_form_codePostal option').filter(function() { 
            return ($(this).text() == $newValue); //To select Blue
        }).prop('selected', true);


        var $codePostalSelect = $('.js-user-form-codePostal');
        var $specificLocationTarget = $('.js-specific-commune-target');


            $.ajax({
                url: $codePostalSelect.data('specific-location-url'),
                data: {
                    codePostalId: $codePostalSelect.val()
                },
                success: function (html) {
                    if (!html) {
                        $specificLocationTarget.find('select').remove();
                        $specificLocationTarget.addClass('d-none');
                        return;
                    }
                    // Replace the current field and show
                    $specificLocationTarget
                        .html(html)
                        .removeClass('d-none')
                }
            });

    });
});
</script>

{% endblock %}