我真的必须解决这个问题.我错过了什么吗?Symfony2 的表单引擎是不是不能处理两层动态表单域依赖?有什么建议吗? 解决方案 感谢 dmnptr 从他的第一条评论中提供的链接 (http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/),我可以解决我的问题.诀窍是,将事件绑定到整个表单而不是某些字段(并且绑定到 PRE_SUBMIT 而不是 POST_SUBMIT).所以我的表单类现在看起来像这样:'识别名称','标签' =>'公园','必需' =>真的,'invalid_message' =>'选择一个公园','占位符' =>'请选择',))//其他字段;$addFacilityForm = function (FormInterface $form, $park_id) {//在这里使用 Park 实体会更容易,//但在 PRE_SUBMIT 事件中获取它并非易事$form->add('设施', '实体', 数组('类' =>'AppBundle:设施','财产' =>'识别名称','标签' =>'设施','必需' =>真的,'invalid_message' =>'选择设施','占位符' =>null === $park_id ?'请先选择一个公园' : '请选择','query_builder' =>功能(FacilityRepository $repository)使用($park_id){//这是获得正确选项的诀窍返回 $repository->createQueryBuilder('f')->innerJoin('f.park', 'p')->where('p.id = :park')->setParameter('park', $park_id);}));};$builder->addEventListener(FormEvents::PRE_SET_DATA,函数 (FormEvent $event) 使用 ($addFacilityForm) {$park = $event->getData()->getPark();$park_id = $park ?$park->getId() : null;$addFacilityForm($event->getForm(), $park_id);});$builder->addEventListener(FormEvents::PRE_SUBMIT,函数 (FormEvent $event) 使用 ($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('类' =>'AppBundle:FacilityStatuscode','财产' =>'识别名称','标签' =>'状态码','必需' =>真的,'invalid_message' =>'选择一个状态码','占位符' =>null === $facility_id ?'请先选择一个设施' : '请选择','query_builder' =>功能 (FacilityStatuscodeRepository $repository) 使用 ($facility_id) {//有点复杂,这就是这个模型的工作原理返回 $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,函数 (FormEvent $event) 使用 ($addFacilityStatuscodeForm) {$facility = $event->getData()->getFacility();$facility_id = $facility ?$facility->getId() : null;$addFacilityStatuscodeForm($event->getForm(), $facility_id);});$builder->addEventListener(FormEvents::PRE_SUBMIT,函数 (FormEvent $event) 使用 ($addFacilityStatuscodeForm) {$data = $event->getData();$facility_id = array_key_exists('facility', $data) ?$数据['设施']:空;$addFacilityStatuscodeForm($event->getForm(), $facility_id);});}//更多代码}AJAX 的东西然后像上面文章链接中建议的那样工作I have a Symfony2 Form with two layered dynamic fields. The first Layer is no problem implementing the documented way with form events: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#dynamic-generation-for-submitted-formsBut then comes a third field, which depends on the second field, which is already a dynamic field.To demonstrate the problem, here is my stripped code:<?phpclass 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}The problem is now:The event-listener set with $builder->get('facility')->addEventListener(FormEvents::POST_SUBMIT,… gets lost at the moment, the facility-field is overwritten by the other event-listener.I tried several workarounds, but it turns out, that form field options cannot be overridden and form later added fields don't accept new event listeners, once the builder is ready (i.e. when added inside an event listener).I really have to solve this. Am I missing something? Is Symfony2's Form engine not able to handle two layered dynamic form field dependencies?Any suggestions? 解决方案 Thanks to dmnptr's link from his first comment (http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/), I could solve the problem for my case. The trick is, to bind the events to the whole form and not to certain fields (and to PRE_SUBMIT instead of POST_SUBMIT). So my form class now looks like this:<?phpclass 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}The AJAX-stuff then works like suggested in the article link above 这篇关于Symfony2 双嵌套动态表单字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-12 12:23