2013-12-12 267 views
9

我建立一个Symfony的应用程序,并使用表单事件与一些jQuery的/ AJAX做全“国家/地区”的东西添加的元素。尽管我有一个小问题,我正在使用格式省 - >城市 - >郊区。现在,据我可以告诉我的代码是好的,但在执行打,我一个监听器添加到“城”的部分选择,它抛出一个错误说以下内容:添加事件侦听器,以形成由事件监听器

The child with the name "physicalCity" does not exist.

这显然当我尝试将事件侦听器添加到新创建的字段时,会发生这种情况,因此将事件侦听器添加到由事件侦听器创建的元素中?

的代码段是低于...我在做什么错?任何帮助将非常感谢!

public function buildForm(FormBuilderInterface $builder, array $options) { 
     $builder 
      ->add('schoolName') 
      ->add('physicalProvince', 'entity', array(
       'mapped' => false, 
       'class' => 'MY\MainBundle\Entity\Province', 
       'empty_value' => 'Select a province', 
       'attr' => array(
        'class' => 'province', 
        'data-show' => 'physical-city', 
       ) 
      )); 

     /* 
     * For the physical cities 
     */ 
     $physicalCityModifier = function(FormInterface $form, Province $province = null) { 
      if (null !== $province) 
       $cities = $province->getCities(); 
      else 
       $cities = array(); 

      $form->add('physicalCity', 'entity', array(
       'mapped' => false, 
       'class' => 'MY\MainBundle\Entity\City', 
       'empty_value' => 'Select a province first', 
       'choices' => $cities, 
       'attr' => array(
        'class' => 'city physical-city', 
        'data-show' => 'physical-suburb' 
       ) 
      )); 
     }; 

     $builder->addEventListener(
      FormEvents::PRE_SET_DATA, 
      function(FormEvent $event) use ($physicalCityModifier) { 
       $data = $event->getData(); 
       if (is_object($data->getPhysicalSuburb())) 
        $province = $data->getPhysicalSuburb()->getCity()->getProvince(); 
       else 
        $province = null; 

       $physicalCityModifier($event->getForm(), $province); 
      } 
     ); 

     $builder->get('physicalProvince')->addEventListener(
      FormEvents::POST_SUBMIT, 
      function (FormEvent $event) use ($physicalCityModifier) { 
       $province = $event->getForm()->getData(); 
       $physicalCityModifier($event->getForm()->getParent(), $province); 
      } 
     ); 

     /* 
     * For the physical suburbs 
     */ 
     $physicalSuburbModifier = function(FormInterface $form, City $city = null) { 
      if (null !== $city) 
       $suburbs = $city->getSuburbs(); 
      else 
       $suburbs = array(); 

      $form->add('physicalSuburb', null, array(
       'choices' => $suburbs, 
       'empty_value' => 'Select a city first', 
       'attr' => array(
        'class' => 'physical-suburb' 
       ), 
      )); 
     }; 

     $builder->addEventListener(
      FormEvents::PRE_SET_DATA, 
      function(FormEvent $event) use ($physicalSuburbModifier) { 
       $data = $event->getData(); 
       if (is_object($data->getCity())) 
        $city = $data->getCity(); 
       else 
        $city = null; 

       $physicalSuburbModifier($event->getForm(), $city); 
      } 
     ); 

     $builder->get('physicalCity')->addEventListener(
      FormEvents::POST_SUBMIT, 
      function(FormEvent $event) use ($physicalSuburbModifier) { 
       $city = $event->getForm()->getData(); 

       $physicalSuburbModifier($event->getForm()->getParent(), $city); 
      } 
     ); 
} 

回答

14

如果其他人也有类似的问题,我最终得到了它的权利与每场活动的用户,从this site帮助(对我们中的那些非讲西班牙语的翻译民谣的话)。

Bascially,我所做的就是创建一个新的Subscriber类的每个领域,包括省,然后刚刚创建内部每个人的查询构建器与来自先前场来填充他们的价值观。代码如下所示。

AddProvinceFieldSubscriber.php

class AddProvinceFieldSubscriber implements EventSubscriberInterface { 
    private $factory; 
    private $fieldName; 
    private $type; 

    public function __construct(FormFactoryInterface $factory, $fieldName) { 
     $this->factory = $factory; 
     $this->fieldName = $fieldName . 'Province'; 
     $this->type = $fieldName; 
    } 

    public static function getSubscribedEvents() { 
     return array(
      FormEvents::PRE_SET_DATA => 'preSetData', 
      FormEvents::PRE_SUBMIT => 'preSubmit', 
     ); 
    } 

    private function addProvinceForm(FormInterface $form, $province) { 
     $form->add($this->factory->createNamed($this->fieldName, 'entity', $province, array(
      'class' => 'MyThing\MainBundle\Entity\Province', 
      'mapped' => false, 
      'empty_value' => 'Select a province', 
      'query_builder' => function (EntityRepository $repository) { 
       $qb = $repository->createQueryBuilder('p'); 
       return $qb; 
      }, 
      'auto_initialize' => false, 
      'attr' => array(
       'class' => 'province ' . $this->type .'-province', 
       'data-show' => $this->type . '-city', 
      ) 
     ))); 
    } 

    public function preSetData(FormEvent $event) { 
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if (null === $data) 
      return; 

     $fieldName = 'get' . ucwords($this->type) . 'Suburb'; 
     $province = ($data->$fieldName()) ? $data->$fieldName()->getCity()->getProvince() : null; 
     $this->addProvinceForm($form, $province); 
    } 

    public function preSubmit(FormEvent $event) { 
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if (null === $data) 
      return; 

     $province = array_key_exists($this->fieldName, $data) ? $data[$this->fieldName] : null; 
     $this->addProvinceForm($form, $province); 
    } 
} 

AddCityFieldSubscriber.php

class AddCityFieldSubscriber implements EventSubscriberInterface { 
    private $factory; 
    private $fieldName; 
    private $provinceName; 
    private $suburbName; 
    private $type; 

    public function __construct(FormFactoryInterface $factory, $fieldName) { 
     $this->factory = $factory; 
     $this->fieldName = $fieldName . 'City'; 
     $this->provinceName = $fieldName . 'Province'; 
     $this->suburbName = $fieldName . 'Suburb'; 
     $this->type = $fieldName; 
    } 

    public static function getSubscribedEvents() { 
     return array(
      FormEvents::PRE_SET_DATA => 'preSetData', 
      FormEvents::PRE_SUBMIT => 'preSubmit', 
     ); 
    } 

    private function addCityForm(FormInterface $form, $city, $province) { 
     $form->add($this->factory->createNamed($this->fieldName, 'entity', $city, array(
      'class' => 'MyThing\MainBundle\Entity\City', 
      'empty_value' => 'Select a city', 
      'mapped' => false, 
      'query_builder' => function (EntityRepository $repository) use ($province) { 
       $qb = $repository->createQueryBuilder('c') 
           ->innerJoin('c.province', 'province'); 
       if ($province instanceof Province) { 
        $qb->where('c.province = :province') 
         ->setParameter('province', $province); 
       } elseif (is_numeric($province)) { 
        $qb->where('province.id = :province') 
         ->setParameter('province', $province); 
       } else { 
        $qb->where('province.provinceName = :province') 
         ->setParameter('province', null); 
       } 

       return $qb; 
      }, 
      'auto_initialize' => false, 
      'attr' => array(
       'class' => 'city ' . $this->type . '-city', 
       'data-show' => $this->type . '-suburb', 
      ) 
     ))); 
    } 

    public function preSetData(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) { 
      return; 
     } 

     $fieldName = 'get' . ucwords($this->suburbName); 
     $city = ($data->$fieldName()) ? $data->$fieldName()->getCity() : null; 
     $province = ($city) ? $city->getProvince() : null; 
     $this->addCityForm($form, $city, $province); 
    } 

    public function preSubmit(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) 
      return; 

     $city = array_key_exists($this->fieldName, $data) ? $data[$this->fieldName] : null; 
     $province = array_key_exists($this->provinceName, $data) ? $data[$this->provinceName] : null; 
     $this->addCityForm($form, $city, $province); 
    } 
} 

最后AddSuburbFieldSubscriber.php

class AddSuburbFieldSubscriber implements EventSubscriberInterface { 
    private $factory; 
    private $fieldName; 
    private $type; 

    public function __construct(FormFactoryInterface $factory, $fieldName) { 
     $this->factory = $factory; 
     $this->fieldName = $fieldName . 'Suburb'; 
     $this->type = $fieldName; 
    } 

    public static function getSubscribedEvents() { 
     return array(
      FormEvents::PRE_SET_DATA => 'preSetData', 
      FormEvents::PRE_SUBMIT => 'preSubmit', 
     ); 
    } 

    private function addSuburbForm(FormInterface $form, $city) { 
     $form->add($this->factory->createNamed($this->fieldName, 'entity', null, array(
      'class' => 'MyThing\MainBundle\Entity\Suburb', 
      'empty_value' => 'Select a suburb', 
      'query_builder' => function (EntityRepository $repository) use ($city) { 
       $qb = $repository->createQueryBuilder('s') 
           ->innerJoin('s.city', 'city'); 

       if ($city instanceof City) { 
        $qb->where('s.city = :city') 
         ->setParameter('city', $city); 
       } elseif (is_numeric($city)) { 
        $qb->where('city.id = :city') 
         ->setParameter('city', $city); 
       } else { 
        $qb->where('city.cityName = :city') 
         ->setParameter('city', null); 
       } 
        $sql = $qb->getQuery()->getSQL(); 

       return $qb; 
      }, 
      'auto_initialize' => false, 
      'attr' => array(
       'class' => 'suburb ' . $this->type . '-suburb', 
      ), 
     ))); 
    } 

    public function preSetData(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) 
      return; 

     $fieldName = 'get' . ucwords($this->fieldName); 
     $city = ($data->$fieldName()) ? $data->$fieldName()->getCity() : null; 
     $this->addSuburbForm($form, $city); 
    } 

    public function preSubmit(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) 
      return; 

     $city = array_key_exists($this->type . 'City', $data) ? $data[$this->type . 'City'] : null; 
     $this->addSuburbForm($form, $city); 
    } 
} 

我不得不添加一些额外的东西在里面,但你的它的要点。

在我的表单类型我只是增加了以下内容:

$builder 
    ->addEventSubscriber(new AddProvinceFieldSubscriber($factory, 'postal')) 
    ->addEventSubscriber(new AddCityFieldSubscriber($factory, 'postal')) 
    ->addEventSubscriber(new AddSuburbFieldSubscriber($factory, 'postal')) 
//... 

和幸福的日子!希望这有助于某人。

而且,我加入了data-show属性来简化AJAX我的过程,以防万一有人不知道。

+2

伟大的工作!你救了我的一天,谢谢你! :) – Gianluca78

+0

当您编辑此内容时,此功能是否正常工作?对我来说它没有。你也可以回答你使用Symfony的哪个版本吗? – Jeet

+0

是的,它为我工作。这是2.4我相信,记不清了。试着玩查询构建器的决策案例。你的情况可能有些奇怪。并安装XDebug!帮助很多。 – iLikeBreakfast