首页 > 解决方案 > Symfony 中的多级动态表单

问题描述

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

形式:

在此处输入图像描述

树枝和阿贾克斯:

{% 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(),
    ]);
}

标签: symfonydoctrinesymfony5

解决方案


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

探查器 Symfony

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


推荐阅读