Symfony2双嵌套动态表单字段

pack

我有一个带有两个分层动态字段的Symfony2 Form。第一层在表单事件中实现记录方式没有问题:http : //symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#dynamic-generation-for-submitted-forms

但是接着是第三个字段,该字段取决于第二个字段,该字段已经是动态字段。

为了演示该问题,这是我的剥离代码:

<?php
class ServiceeventType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('park', 'entity', array(
                'class' => 'AppBundle:Park',
                'property' => 'identifyingName',
                'label' => 'Park',
                'required' => true,
                'invalid_message' => 'Choose a Park',
                'placeholder' => 'Please choose',
            ))
            // just a placeholder for the $builder->get('facility')->addEventListener to have something to bind to
            // I'm aware, that this is just a symptom of my problem
            ->add('facility', 'choice', array(
                'choices' => array(),
                'expanded' => true,
                'multiple' => false,
                'label' => 'Facility',
                'required' => false,
                'invalid_message' => 'Choose a Park first',
                'placeholder' => 'Please choose a Park first',
            ))
            // other fields
        ;

        $formModifierPark = function (FormInterface $form, Park $park = null) {
            // overwrite the facility field with the desired entity type
            $form->add('facility', 'entity', array(
                'class' => 'AppBundle:Facility',
                'property' => 'identifyingName',
                'choices' => null === $park ? array() : $park->getFacilities(),
                'label' => 'Facility',
                'required' => true,
                'invalid_message' => 'Choose a Facility',
                'placeholder' => null === $park ? 'Please choose a Park first' : 'Please choose',
            ));
        };

        $formModifierFacility = function (FormInterface $form, Facility $facility = null) {
            $form->add('facilityStatuscode', 'entity', array(
                'class' => 'AppBundle:FacilityStatuscode',
                'property' => 'identifyingName',
                'choices' => null === $facility ? array() : $facility->getFacilityStatuscodeType()->getFacilityStatuscodes(),
                'label' => 'Statuscode',
                'required' => null === $facility ? false : true,
                'invalid_message' => 'Choose a Statuscode',
                'placeholder' => null === $facility ? 'Please choose a Facility first' : 'Please choose',
            ));
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifierPark) {
                $formModifierPark($event->getForm(), $event->getData()->getPark());
            }
        );
        $builder->get('park')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifierPark) {
                $formModifierPark($event->getForm()->getParent(), $event->getForm()->getData());
            }
        );

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifierFacility) {
                $formModifierFacility($event->getForm(), $event->getData()->getFacility());
            }
        );
        $builder->get('facility')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifierFacility) {
                $formModifierFacility($event->getForm()->getParent(), $event->getForm()->getData());
            }
        );
    }

    // more code
}

现在的问题是:

$builder->get('facility')->addEventListener(FormEvents::POST_SUBMIT,…此刻设置的事件侦听器迷路了,设施字段被其他事件侦听器覆盖。

我尝试了几种解决方法,但事实证明,一旦构建器准备就绪(即,添加到事件侦听器中),就不能覆盖表单字段选项,并且以后添加的表单字段不接受新的事件侦听器。

我真的必须解决这个问题。我想念什么吗?Symfony2的表单引擎是否不能处理两层动态表单字段依赖项?

有什么建议么?

pack

感谢dmnptr在他的第一条评论中的链接(http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/),我可以为我的案例解决问题。诀窍是,将事件绑定到整个表单,而不是绑定到某些字段(而PRE_SUBMIT不是POST_SUBMIT)。所以我的表单类现在看起来像这样:

<?php
class ServiceeventType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('park', 'entity', array(
                'class' => 'AppBundle:Park',
                'property' => 'identifyingName',
                'label' => 'Park',
                'required' => true,
                'invalid_message' => 'Choose a Park',
                'placeholder' => 'Please choose',
            ))
            // other fields
        ;

        $addFacilityForm = function (FormInterface $form, $park_id) {
            // it would be easier to use a Park entity here,
            // but it's not trivial to get it in the PRE_SUBMIT events
            $form->add('facility', 'entity', array(
                'class' => 'AppBundle:Facility',
                'property' => 'identifyingName',
                'label' => 'Facility',
                'required' => true,
                'invalid_message' => 'Choose a Facility',
                'placeholder' => null === $park_id ? 'Please choose a Park first' : 'Please Choose',
                'query_builder' => function (FacilityRepository $repository) use ($park_id) {
                    // this does the trick to get the right options
                    return $repository->createQueryBuilder('f')
                        ->innerJoin('f.park', 'p')
                        ->where('p.id = :park')
                        ->setParameter('park', $park_id)
                    ;
                }
            ));
        };
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($addFacilityForm) {
                $park = $event->getData()->getPark();
                $park_id = $park ? $park->getId() : null;
                $addFacilityForm($event->getForm(), $park_id);
            }
        );
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) use ($addFacilityForm) {
                $data = $event->getData();
                $park_id = array_key_exists('park', $data) ? $data['park'] : null;
                $addFacilityForm($event->getForm(), $park_id);
            }
        );

        $addFacilityStatuscodeForm = function (FormInterface $form, $facility_id) {
            $form->add('facilityStatuscode', 'entity', array(
                'class' => 'AppBundle:FacilityStatuscode',
                'property' => 'identifyingName',
                'label' => 'Statuscode',
                'required' => true,
                'invalid_message' => 'Choose a Statuscode',
                'placeholder' => null === $facility_id ? 'Please choose a Facility first' : 'Please Chosse',
                'query_builder' => function (FacilityStatuscodeRepository $repository) use ($facility_id) {
                    // a bit more complicated, that's how this model works
                    return $repository->createQueryBuilder('fs')
                        ->innerJoin('fs.facilityStatuscodeType', 'fst')
                        ->innerJoin('AppBundle:Facility', 'f', 'WITH', 'f.facilityStatuscodeType = fst.id')
                        ->where('f.id = :facility_id')
                        ->setParameter('facility_id', $facility_id)
                    ;
                }
            ));
        };
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($addFacilityStatuscodeForm) {
                $facility = $event->getData()->getFacility();
                $facility_id = $facility ? $facility->getId() : null;
                $addFacilityStatuscodeForm($event->getForm(), $facility_id);
            }
        );
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) use ($addFacilityStatuscodeForm) {
                $data = $event->getData();
                $facility_id = array_key_exists('facility', $data) ? $data['facility'] : null;
                $addFacilityStatuscodeForm($event->getForm(), $facility_id);
            }
        );


    }

    // more code
}

然后,AJAX的工作方式就像上面文章链接中建议的那样

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章