动态表单 Symfony 上的约束冲突

Constraint Violation on dynamic form Symfony

我在 Symfony3.4 上工作 我有一个动态形式的国家->地区->城市(3 个不同的实体)。 我可以根据用户选择更改字段,没有任何问题。

但是我无法在数据库中持久化,因为 city 字段(而且只有这个字段)违反了约束

我真的不知道为什么,因为我用同样的方式称呼它们(地区和城市)...

欢迎任何帮助。

这是表格:

public function buildForm(FormBuilderInterface $builder, array $options)
{

    $em = $options['entityManager'];

    $builder
        ->add('rue', TextType::class, array(
            'label' => 'votre rue',
            'required' => true,
        ))

        ->add('pays', EntityType::class, array(
            'class' => 'AppBundle\Entity\Pays',
            'placeholder' => '--choisir--',
            'choice_label' => 'nom',
            'required' => true
        ))
    ;

    $addRegion = function (FormInterface $form, Pays $pays = null) {
        $regions = null === $pays ? array() : $pays->getRegions();

        $form->add('region', EntityType::class, array(
            'class' => 'AppBundle\Entity\Region',
            'placeholder' => '--choisir une région--',
            'choices' => $regions,
            'choice_label' => 'nom',
            'required' => true
        ));

    };

    $addVille = function (FormInterface $form, Region $region = null) {
        $villes = null === $region ? array() : $region->getVilles();

        $form->add('ville', EntityType::class, array(
            'class' => 'AppBundle\Entity\Ville',
            'placeholder' => '--choisir une ville--',
            'choices' => $villes,
            'choice_label' => 'nom',
            'required' => true
        ));


        $form->add('submit', SubmitType::class
        );

    };

    $builder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function (FormEvent $event) use ($addRegion, $addVille){
            $form = $event->getForm();
            $addVille($form, null);
            $addRegion($form, null);
        }
    );

    $builder->addEventListener(
        FormEvents::PRE_SUBMIT,
        function (FormEvent $event) use ($addRegion, $addVille, $em) {
            $form = $event->getForm();
            $data = $event->getData();
            if(isset($data['pays'])){
                $paysId = $data['pays'];

                $repo = $em->getRepository('AppBundle\Entity\Pays');
                $pays = $repo->find($paysId);

                $addRegion($form, $pays);
                $addVille($form, null);
            }
            else if(isset($data['region'])){
                $regionId = $data['region'];

                $repo = $em->getRepository('AppBundle\Entity\Region');
                $region = $repo->find($regionId);

                $addVille($form, $region);
            }
        }
    );
}

这是模板:

{% block body %}

{% form_theme form 'bootstrap_4_layout.html.twig' %}

{% for message in app.flashes('notice') %}
    <div style="color:green;">
        {{ message }}
    </div>
{% endfor %}

{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_end(form) }}

{% 端块 %}

{% 阻止 javascript %}

<script>
    var $pays = $('#adresse_pays');
    var $region = $('#adresse_region');
    var $ville = $('#adresse_ville');

    $pays.change(function() {
        var $form = $(this).closest('form');
        var data = {};
        data[$pays.attr('name')] = $pays.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) {
                $ville.empty()
                var select = $(html).find('#adresse_ville > option')
                $ville.append(select)

                $region.empty()
                var select = $(html).find('#adresse_region > option')
                $region.append(select)
                $region.val($("#adresse_region option:first").val());
                console.log('regions')
                console.log(select)
            }
        });
    });


    $region.change(function() {
        var $form = $(this).closest('form');
        var data = {};
        data[$region.attr('name')] = $region.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) {
                $ville.empty()
                var select = $(html).find('#adresse_ville > option')
                $ville.append(select)
                $ville.val($("#adresse_ville option:first").val());
                console.log('villes')
                console.log(select)
            }
        });
    });


</script>

{% 端块 %}

这是表单上的警告(在城市字段旁边): 错误此值无效

多亏了调试栏,我走得更远,好像这个字段发送的不是一个对象,而是一个整数。

我发现另一个字段的不同之处在于城市字段:

Normalized Format submitted is null

而在另一个字段中,例如地区:

Normalized Format   

Region {#6035 ▼
  -id: 3
  -nom: "Catalogne"
  -villes: PersistentCollection {#6039 …}
  -pays: Pays {#5802 ▶}
  -adresses: PersistentCollection {#6041 …}

}

有效!

我拆分函数

$builder->addEventListener( FormEvents::PRE_SUBMIT, ... in half => 我删除了 else if 并在 "region" 更改时创建了另一个类似的函数来监听。

困扰我的是我不明白为什么它以这种方式工作而不是另一种方式...

$builder->addEventListener(
    FormEvents::PRE_SUBMIT,
    function (FormEvent $event) use ($addRegion, $addVille, $em) {
        $form = $event->getForm();
        $data = $event->getData();
        if(isset($data['pays'])){
            $paysId = $data['pays'];
            $repo = $em->getRepository('AppBundle\Entity\Pays');
            $pays = $repo->find($paysId);
            $addRegion($form, $pays);
            $addVille($form, null); 
        }
    }        
);

$builder->addEventListener(
    FormEvents::PRE_SUBMIT,
    function(FormEvent $event) use ($addVille, $em) {
        $form = $event->getForm();
        $data = $event->getData();
        if(isset($data['region'])){
            $regionId = $data['region'];
            $repo = $em->getRepository('AppBundle\Entity\Region');
            $region = $repo->find($regionId);
            $addVille($form, $region); 
        }           
    }
);