2017-04-26 54 views
0

我需要在其父窗体中嵌入一个实体窗体。我跟着官方documentation将表格嵌入到另一个表格中,并有一对多的关系。Symfony 2.8:表单集合和一对多关系没有正确保存

问题是,虽然我设法正确显示窗体,当需要保留另一个子实体时,它可以与第2个对象正常工作,当我尝试创建第三个对象时,它会删除第二个对象数组并创建第三个。

:我有了一个一对多的关系,WorkExperience实体

代码简历实体:

实体:

class Curriculum 
    { 
     /** 
     * @ORM\OneToMany(targetEntity="appBundle\Entity\WorkExperience", mappedBy="curriculum", cascade={"persist", "remove"}, orphanRemoval=true) 
     */ 
     private $workExperience; 

     public function __construct() 
     { 
      $this->workExperience = new \Doctrine\Common\Collections\ArrayCollection(); 
     } 


    /** 
    * Add workExperience 
    * 
    * @param appBundle\Entity\WorkExperience $workExperience 
    * @return Curriculum 
    */ 
    public function addWorkExperience(appBundle\Entity\WorkExperience $workExperience) 
    { 
     $this->workExperience->add($workExperience); 
     $workExperience->setCurriculum($this); 

     return $this; 
    } 

    /** 
    * Remove workExperience 
    * 
    * @param appBundle\Entity\WorkExperience $workExperience 
    */ 
    public function removeWorkExperience(appBundle\Entity\WorkExperience $workExperience) 
    { 
     $this->workExperience->removeElement($workExperience); 
    } 

    /** 
    * Get workExperience 
    * 
    * @return \Doctrine\Common\Collections\Collection 
    */ 
     public function getWorkExperience() 
     { 
      return $this->workExperience; 
     } 
} 

WorkExperience:

class WorkExperience 
{ 
    /** 
    * @ORM\ManyToOne(targetEntity="appBundle\Entity\Curriculum", inversedBy="workExperience") 
    * @ORM\JoinColumn(name="curriculum", referencedColumnName="id") 
    */ 
    private $curriculum; 

    /** 
    * Set curriculum 
    * 
    * @param string $curriculum 
    * @return WorkExperience 
    */ 
    public function setCurriculum($curriculum) 
    { 
     $this->curriculum = $curriculum; 

     return $this; 
    } 

    /** 
    * Get curriculum 
    * 
    * @return string 
    */ 
    public function getCurriculum() 
    { 
     return $this->curriculum; 
    } 
} 

然后,formType(我只创造了workExperience形式,因为它是我需要在我collectionType场)

WorkExperienceType:

<?php 

namespace appBundle\Form\Type; 

use Symfony\Component\Form\AbstractType; 
use appBundle\Entity\WorkExperience; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Bridge\Doctrine\Form\Type\EntityType; 
use Doctrine\ORM\EntityRepository; 
use Symfony\Component\Intl\Intl; 
use Symfony\Component\Form\Extension\Core\Type\DateType; 

class WorkExperienceType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 

     $builder 
      ->add('fromDate', DateType::class, array(
       'widget' => 'single_text', 
       'html5' => false, 
       'attr' => ['class' => 'form-control js-datepicker'], 
       'format' => 'dd-MM-yyyy', 
       'label' => 'From') 
      ) 
      ->add('toDate', DateType::class, array(
       'widget' => 'single_text', 
       'html5' => false, 
       'attr' => ['class' => 'form-control js-datepicker'], 
       'format' => 'dd-MM-yyyy', 
       'label' => 'To', 
       'required' => false, 
       ) 
      ) 
      ->add('ongoing', 'checkbox', array('required' => false,)) 
      ->add('jobProfile', EntityType::class, array(
       'class' => 'appBundle:JobProfile', 
       'query_builder' => function (EntityRepository $er) use ($options) { 
        return $er->createQueryBuilder('j') 
         ->where('j.company = :company') 
         ->setParameter('company', $options['company']); 
       }, 
       'choice_label' => 'name', 
       'required' => false, 
       'placeholder' => 'Job Profile' 
      )) 
      ->add('employerName', 'text', array('label' => "Name")) 
      ->add('employerCity', 'text', array('label' => "City")) 
      ->add('activities', 'textarea', array('label' => "Activities and responsibilities")); 
    } 

    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefined('company'); 
     $resolver->setDefaults(array(
      'data_class' => WorkExperience::class, 
     )); 
    } 
} 

课程控制器:

我只告诉你表单管理因为它在哪里我有问题(如果你想知道我不通过一个ID,因为连接的用户只能有一个课程)

模板:

{% form_theme formCurriculum _self %} 

{% block work_experience_widget %} 
    <div class="form-group row"> 
     <div class="col-sm-6"> 
      <label for="">Nombre Empresa</label> 
      {{ form_widget(form.employerName, {'attr': {'class': 'form-control'}}) }} 
     </div> 
     <div class="col-sm-5"> 
      <label for="">Categoría Profesional</label> 

      {{ form_widget(form.jobProfile, {'attr': {'class': 'form-control'}}) }} 
     </div> 
     <div class="col-sm-1"> 
      <a href="#" class="btn btn-danger btn-xs text-center remove-tag"><i class="glyphicon glyphicon-remove"></i></a> 
     </div> 
    </div> 
    <div class="form-group row"> 
     <div class="col-sm-3"> 
      <label for="">Fecha desde</label> 
      <div class="input-group"> 
       {{ form_widget(form.fromDate) }} 
       <span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span> 
      </div> 
     </div> 
     <div class="col-sm-5"> 
      <label for="">Fecha hasta</label> 
      <div class="input-group"> 
       <span class="input-group-addon"> 
        {{ form_widget(form.ongoing) }} 
        </span> 
       {{ form_widget(form.toDate) }} 
       <span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span> 
      </div> 
     </div> 
     <div class="col-sm-4"> 
      <label for="">Ciudad</label> 
      {{ form_widget(form.employerCity, {'attr': {'class': 'form-control'}}) }} 
     </div> 
    </div> 
    <div class="form-group"> 
     <label for="">Actividades y Responsabilidades</label> 
     {{ form_widget(form.activities, {'attr': {'class': 'form-control'}}) }} 
     {{ form_rest(form) }} 
     {{ form_errors(form)}} 
    </div> 
    <hr /> 
{% endblock %} 

{{ form_start(formCurriculum) }} 

         <div class="col-lg-8 col-xs-12"> 
          <h3>Experiencia Laboral</h3> 

          <div class="workExperience" data-prototype="{{ form_widget(formCurriculum.workExperience.vars.prototype)|e('html_attr') }}"> 
           {% for workExperience in formCurriculum.workExperience %} 
            <div class="workExperienceUnit"> 
             {{ form(workExperience)}} 
            </div> 
           {% endfor %} 
          </div> 


          <div class="form-group text-right"> 
           {{ form_widget(formCurriculum.save, {'attr': {'class': 'btn btn-blue'}}) }} 
          </div> 
          <div class="clearfix"></div> 
         </div> 
        {{ form_rest(formCurriculum) }} 
        {{ form_end(formCurriculum) }} 

Ajax和JS的形式收集:

{% block javascripts %} 
    {{ parent() }}  
    <script type="text/javascript"> 
     var $collectionHolder; 

     // setup an "add a tag" link 
     var $addWorkExperienceLink = $('<button type="button" class="btn btn-primary width100x100 add_workexperience_link"><span class="badge"><i class="glyphicon glyphicon-plus"></i></span> Agregar nueva experiencia laboral</button>'); 

     var $newLinkLi = $('<div class="form-group row"><div class="col-sm-12"></div></div>').append($addWorkExperienceLink); 

     jQuery(document).ready(function() { 

      $collectionHolder = $('div.workExperience'); 

      // add the "add a tag" anchor and li to the tags ul 
      $collectionHolder.append($newLinkLi); 

      // count the current form inputs we have (e.g. 2), use that as the new 
      // index when inserting a new item (e.g. 2) 


      $collectionHolder.data('index', $collectionHolder.find(':input').length); 

      $addWorkExperienceLink.on('click', function(e) { 
       // prevent the link from creating a "#" on the URL 
       e.preventDefault(); 

       // add a new tag form (see next code block) 
       addWorkExperienceForm($collectionHolder, $newLinkLi); 
      }); 

     }); 

     function addWorkExperienceForm($collectionHolder, $newLinkLi) { 
      // Get the data-prototype explained earlier 
      var prototype = $collectionHolder.data('prototype'); 

      // get the new index 
      var index = $collectionHolder.data('index'); 

      $collectionHolder.data('index', index + 1); 

      // Replace '$$name$$' in the prototype's HTML to 
      // instead be a number based on how many items we have 
      var newForm = prototype.replace(/__name__/g, index); 

      // Display the form in the page in an li, before the "Add a tag" link li 
      var $newFormLi = $('<div class="workExperienceUnit"></div>').append(newForm); 

      $newLinkLi.before($newFormLi); 

      $('.remove-tag').click(function(e) { 
       e.preventDefault(); 

       $(this).parent().parent().parent().remove(); 

       return false; 
      }); 
     } 

     // handle the removal, just for this example 
     $('.remove-tag').click(function(e) { 
      e.preventDefault(); 

      $(this).parent().parent().parent().remove(); 

      return false; 
     }); 

    </script> 
{% endblock %} 

这里是截图,事情是,它正确地删除对象,该onlye问题是创建新对象

enter image description here

回答

0

几件事情似乎很奇怪。

  1. 使用$ form-> handleRequest($ request);而不是绑定()
  2. 为什么你使用'type'=> new WorkExperience()?我认为你不必在CollectionType字段中使用Thois,因为实体的类型是在WorkexperienceTpe中定义的。
  3. 当您发布带有handlerequest功能的表单时,您无需从表单中检索所有数据,因为所有工作经验已自动添加到$ formCurriculum中