Symfony中的多级动态表单

问题描述

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

表格:

enter image description here

树枝和ajax:

{% 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'),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',[
                'choices'  => null,])
            ->add('university',])
            ->add('name')
        ;

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

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

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

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

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

                    $form->add('university',[
                        '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(),]);
}

解决方法

我邀请您使用Symfony调试工具栏。它将使您看到与代码相关的各种问题,并提供有关出现的问题的更多信息。

Profiler Symfony

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