2016-04-30 95 views
0

我得到了一个名为'Activity'的实体,它定义了两个实体'Service'和'Location'之间的关系。Symfony 2:动态表单事件仅在编辑时返回InvalidArgumentException

“服务”和“位置”都使用另一个名为“分配”的实体来定义可以在具体位置使用哪些服务。

当我创建一个新的活动,选择一个服务后,我希望位置选择字段更新与分配定义的值。

我遵循symfony文档在窗体中创建这个'位置'依赖选择字段。

Dynamic Form Modification

所有工作在创建/新形式很好,但是当我尝试编辑已创建活动服务字段值,位置字段不更新和symfony的探查显示我以下消息:

未捕获的PHP异常Symfony \ Component \ PropertyAccess \ Exception \ InvalidArgumentException:“在F:\ xampp \ htdocs \ gcd \ vendor \ symfony \ symfony \中给出”AppBundle \ Entity \ Location“类型的预期参数, src \ Symfony \ Component \ PropertyAccess \ PropertyAccessor.php第253行上下文:{“exception”:“Object(Symfony \ Component \ PropertyAccess \ Exception \ InvalidArgumentException)”}

这是我的活动实体

/** 
* Activity 
* 
* @ORM\Table(name="activity") 
* @ORM\Entity(repositoryClass="AppBundle\Repository\ActivityRepository") 
*/ 
class Activity 
{ 
    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var Service 
    * 
    * @ORM\ManyToOne(targetEntity="Service", fetch="EAGER") 
    * @ORM\JoinColumn(name="service_id", referencedColumnName="id", nullable=false) 
    */ 
    private $service; 

    /** 
    * @var Location 
    * 
    * @ORM\ManyToOne(targetEntity="Location", fetch="EAGER") 
    * @ORM\JoinColumn(name="location_id", referencedColumnName="id", nullable=false) 
    */ 
    private $location; 

我的控制器的一个部分。

/** 
* Creates a new Activity entity. 
* 
* @Route("/new", name="core_admin_activity_new") 
* @Method({"GET", "POST"}) 
*/ 
public function newAction(Request $request) 
{ 
    $activity = new Activity(); 
    $form = $this->createForm('AppBundle\Form\ActivityType', $activity); 
    $form->handleRequest($request); 

    if($form->isSubmitted() && $form->isValid()){ 

     $locationAvailable = $this->isLocationAvailable($activity); 
     $activityOverlap = $this->hasOverlap($activity); 

     if($locationAvailable && !$activityOverlap){ 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($activity); 
      $em->flush(); 

      return $this->redirectToRoute('core_admin_activity_show', array('id' => $activity->getId())); 
     } 
    } 

    return $this->render('activity/new.html.twig', array(
     'activity' => $activity, 
     'form' => $form->createView(), 
    )); 
} 


/** 
* Displays a form to edit an existing Activity entity. 
* 
* @Route("/{id}/edit", name="core_admin_activity_edit") 
* @Method({"GET", "POST"}) 
*/ 
public function editAction(Request $request, Activity $activity) 
{ 
    $deleteForm = $this->createDeleteForm($activity); 
    $editForm = $this->createForm('AppBundle\Form\ActivityType', $activity); 
    $editForm->handleRequest($request); 

    if ($editForm->isSubmitted() && $editForm->isValid()) { 

     $locationAvailable = $this->isLocationAvailable($activity); 
     $activityOverlap = $this->hasOverlap($activity); 

     if($locationAvailable && !$activityOverlap){ 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($activity); 
      $em->flush(); 

      return $this->redirectToRoute('core_admin_activity_show', array('id' => $activity->getId())); 
     } 
    } 

    return $this->render('activity/edit.html.twig', array(
     'activity' => $activity, 
     'edit_form' => $editForm->createView(), 
     'delete_form' => $deleteForm->createView(), 
    )); 
} 

我FormType

class ActivityType extends AbstractType 

{

private $em; 

public function __construct(EntityManager $entityManager) 
{ 
    $this->em = $entityManager; 
} 

/** 
* @param FormBuilderInterface $builder 
* @param array $options 
*/ 
public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder 
     ->add('service', EntityType::class, array(
      'class' => 'AppBundle:Service', 
      'placeholder' => 'elige servicio', 
     )) 
     ->add('location', EntityType::class, array(
      'class' => 'AppBundle:Location', 
      'choices' => array(), 
        )) 
     ->add('name') 
     ->add('virtual') 
     ->add('customerSeats') 
     ->add('customerVacants') 
     ->add('employeeSeats') 
     ->add('firstDate', 'date') 
     ->add('lastDate', 'date') 
     ->add('weekday') 
     ->add('beginTime', 'time') 
     ->add('endTime', 'time') 
     ->add('admissionType') 
     ->add('status'); 



    $formModifier = function (FormInterface $form, Service $service = null) { 
     $locations = null === $service ? array() : $this->em->getRepository('AppBundle:Allocation')->findLocationsByService($service); 

     $form->add('location', EntityType::class, array(
      'class' => 'AppBundle:Location', 
      'choices' => $locations, 
     )); 
    }; 


    $builder->addEventListener(
     FormEvents::PRE_SET_DATA, 
     function (FormEvent $event) use ($formModifier) { 
      $data = $event->getData(); 
      $formModifier($event->getForm(), $data->getService()); 
     } 
    ); 

    $builder->get('service')->addEventListener(
     FormEvents::POST_SUBMIT, 
     function (FormEvent $event) use ($formModifier) { 
      // It's important here to fetch $event->getForm()->getData(), as 
      // $event->getData() will get you the client data (that is, the ID) 
      $service = $event->getForm()->getData(); 

      // since we've added the listener to the child, we'll have to pass on 
      // the parent to the callback functions! 
      $formModifier($event->getForm()->getParent(), $service); 
     } 
    ); 
} 

/** 
* @param OptionsResolver $resolver 
*/ 
public function configureOptions(OptionsResolver $resolver) 
{ 
    $resolver->setDefaults(array(
     'data_class' => 'AppBundle\Entity\Activity' 
    )); 
} 

}

JavaScript函数

<script> 
    var $service = $('#activity_service'); 
    // When sport gets selected ... 
    $service.change(function() { 
     // ... retrieve the corresponding form. 
     var $form = $(this).closest('form'); 
     // Simulate form data, but only include the selected service value. 
     var data = {}; 
     data[$service.attr('name')] = $service.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) { 
       // Replace current position field ... 
       $('#activity_location').replaceWith(
         // ... with the returned one from the AJAX response. 
         $(html).find('#activity_location') 
       ); 
      } 
     }); 
    }); 
</script> 

任何帮助将是伟大的,谢谢。

回答