Symfony中的多级动态形式

Symfony中的多级动态形式,symfony,doctrine,symfony5,Symfony,Doctrine,Symfony5,我需要创建一个表单,将教员添加到数据库中。首先,用户从列表(/ChoiceType)中选择一个地区,然后从下面的列表中选择该地区的城市,即大学,最后输入教员的姓名。默认值是数据库中的第一个区域、第一个城市和第一所大学。 发送带有默认数据的页面时,区域的选择有效,但城市的选择返回到500状态 表格: Twig和ajax: 控制器: 我邀请您使用Symfony调试工具栏。它将允许您查看与代码相关的不同问题,并提供有关出现的问题的更多信息 关于您的问题,我认为有必要在表单发送到应用程序的级别进行调

我需要创建一个表单,将教员添加到数据库中。首先,用户从列表(/ChoiceType)中选择一个地区,然后从下面的列表中选择该地区的城市,即大学,最后输入教员的姓名。默认值是数据库中的第一个区域、第一个城市和第一所大学。 发送带有默认数据的页面时,区域的选择有效,但城市的选择返回到500状态

表格:

Twig和ajax: 控制器:
我邀请您使用Symfony调试工具栏。它将允许您查看与代码相关的不同问题,并提供有关出现的问题的更多信息


关于您的问题,我认为有必要在表单发送到应用程序的级别进行调试。但是,如果需要更多帮助,则必须提供500错误附带的错误消息。

在面板中找到了错误说明。选择城市时,程序不参考“城市”字段,而是参考位于代码中较高位置的“地区”字段。在这方面,问题是:“事件列表是挂在整个表单上还是只挂在一个字段上?”因为我在get(‘区域’)调用后挂起事件列表,我以为它在听那个特定字段。好吧,我仔细看了一下你的表单,允许城市水合的静态函数会不会有问题?您确定,
$city=$event->getForm()->getData()
是您想要给
$city
?我想要得到在城市列表中选择的城市。您所指的行取自symfony文档中的示例。区域事件侦听器的编写方式与此类似。好的,你能分享错误的完整跟踪吗?我认为只有这样才能帮助理解你的问题。而且,仅仅为了测试,如果您对所有关于
$city
的行进行注释,它是否工作正常?问题是它正在将城市数据传递给$builder->get('region')->addEventListener(…);,但是它应该是$builder->get('city')->addEventListener(…);
{% extends 'admin/insert/insert.html.twig' %}

{% block title %}Add Faculty{% endblock %}

{% block body %}
    <div class="insert">

        <h1 class="insert__title">Add Faculty</h1>

        {{ form_start(insert_faculty, { 'attr' : {'class' : 'insert__form'} }) }}

        {% for message in app.flashes('success') %}
            <div class="insert__success">
                {{ message }}
            </div>
        {% endfor %}

        <div class="insert__errors">
            {{ form_errors(insert_faculty) }}
        </div>

        {{ form_label(insert_faculty.region, 'Region:', { 'label_attr' : {'class' : 'insert__label'} }) }}
        {{ form_widget(insert_faculty.region, { 'attr' : {'class' : 'insert__input'} }) }}

        {{ form_label(insert_faculty.city, 'City:', { 'label_attr' : {'class' : 'insert__label'} }) }}
        {{ form_widget(insert_faculty.city, { 'attr' : {'class' : 'insert__input'} }) }}

        {{ form_label(insert_faculty.university, 'University:', { 'label_attr' : {'class' : 'insert__label'} }) }}
        {{ form_widget(insert_faculty.university, { 'attr' : {'class' : 'insert__input'} }) }}

        {{ form_label(insert_faculty.name, 'Name:', { 'label_attr' : {'class' : 'insert__label'} }) }}
        {{ form_widget(insert_faculty.name, { 'attr' : {'class' : 'insert__input insert__input_name'} }) }}

        <button type="submit" class="insert__button">Save</button>

        {{ form_end(insert_faculty) }}

        <div class="insert__buttons">
            <a href="{{ path('insert') }}" class="insert__button">Back</a>
        </div>
    </div>

    {%  block javascripts_footer %}
        {{ parent() }}
        <script>
            let $region = $('#insert_faculty_region');
            $region.change(function() {
                let $form = $(this).closest('form');
                let data = {};
                data[$region.attr('name')] = $region.val();
                $.ajax({
                    url : $form.attr('action'),
                    type: $form.attr('method'),
                    data : data,
                    success: function(get) {
                        $('#insert_faculty_city').html(
                            $(get).find('#insert_faculty_city').html()
                        );
                        $('#insert_faculty_university').html(
                            $(get).find('#insert_faculty_university').html()
                        );
                    }
                });
            });

            let $city = $('#insert_faculty_city');
            $city.change(function() {
                let $form = $(this).closest('form');
                let data = {};
                data[$city.attr('name')] = $city.val();
                $.ajax({
                    url : $form.attr('action'),
                    type: $form.attr('method'),
                    data : data,
                    success: function(get) {
                        $('#insert_faculty_university').html(
                            $(get).find('#insert_faculty_university').html()
                        );
                    }
                });
            });
        </script>
    {% endblock %}
{% endblock %}
class InsertFacultyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('region', ChoiceType::class, [
                'choices'  => $options['regions_array'],
                'mapped' => false,
            ])
            ->add('city', ChoiceType::class, [
                'choices'  => null,
                'mapped' => false,
            ])
            ->add('university', ChoiceType::class, [
                'choices'  => null,
            ])
            ->add('name')
        ;

        $formModifier = function (FormInterface $form, $entity_parent) {

            if (get_class($entity_parent) === 'App\Entity\Region') {
                if (!$entity_parent->getCities()->count()) {

                    $form->add('city', ChoiceType::class, [
                        'choices' => null,
                        'mapped' => false,
                    ]);
                }
                else {
                    $cities_in_database = $entity_parent->getCities();
                    foreach ($cities_in_database as $city) {
                        $cities[$city->getName()] = $city;
                    }

                    $form->add('city', ChoiceType::class, [
                        'choices' => $cities,
                        'mapped' => false,
                    ]);
                }
            }
            else if (get_class($entity_parent) === 'App\Entity\City') {
                if (!$entity_parent->getUniversities()->count()) {

                    $form->add('university', ChoiceType::class, [
                        'choices' => null,
                    ]);
                }
                else {
                    $university_in_database = $entity_parent->getUniversities();
                    foreach ($university_in_database as $university) {
                        $universities[$university->getName()] = $university;
                    }

                    $form->add('university', ChoiceType::class, [
                        'choices' => $universities,
                    ]);
                }
            }
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($options, $formModifier, $builder) {
                $region = $options['regions_array'][array_key_first($options['regions_array'])];
                $city = $region->getCities()[0];
                $formModifier($event->getForm(), $region);
                $formModifier($event->getForm(), $city);
            }
        );

        $builder->get('region')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                $region = $event->getForm()->getData();
                $city = $region->getCities()[0];

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

        $builder->get('city')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                $city = $event->getForm()->getData();

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

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

        $resolver->setAllowedTypes('regions_array', 'array');
    }
}
/**
* @Route("/admin/insert/faculty", name="faculty")
*/
public function faculty(Request $request)
{
    $regions_in_database = $this->getDoctrine()->getRepository(Region::class)->findAll();

    $regions = [];
    foreach ($regions_in_database as $region) {
        $regions[(string)$region->getName()] = $region;
    }

    $faculty = new Faculty();
    $insert_faculty = $this->createForm(InsertFacultyType::class, $faculty, [
        'regions_array' => $regions,
    ]);

    if (!$regions_in_database) {
        $insert_faculty->addError(new FormError("There are no regions!"));
    }

    $insert_faculty->handleRequest($request);
    if ($insert_faculty->isSubmitted() && $insert_faculty->isValid()) {

        $repository = $this->getDoctrine()->getRepository(University::class);
        $faculty_in_database = $repository->findOneBy(
            [
                'name' => $faculty->getName(),
                'university' => $faculty->getUniversity(),
            ]
        );

        if ($faculty_in_database) {
            $insert_faculty->addError(new FormError('Such a faculty is already in the database!'));
        }
        else {
            $faculty->setRating(0);
            if(!$faculty->getUniversity()) {
                $insert_faculty->addError(new FormError("Select the university!"));
            }
            else {
                $entity_manager = $this->getDoctrine()->getManager();
                $entity_manager->persist($faculty);
                $entity_manager->flush();
                $this->addFlash(
                    'success',
                    'Faculty "' . $faculty->getName() . '" successfully saved!'
                );
            }
        }
    }

    return $this->render('admin/insert/faculty/faculty.html.twig', [
        'insert_faculty' => $insert_faculty->createView(),
    ]);
}