2017-07-11 34 views
1

我是Symfony的新手,所以我開始使用官方教程,安裝了Symfony框架3.3.2,並在定製實體,控制器,形式和對我的具體需求的看法。Symfony 3.3:無法添加和刪除與收集表單類型相同的實體的項目

所以基本上我有一個名爲BasePreset的實體,在數據庫中已經有了幾行,並且我最終設法創建了一個表單集合類型,該類型使用'add'和''來呈現可編輯BasePreset實體字段的列表。刪除'鏈接:第一個將新的空白字段添加到列表中,並且每個「刪除」鏈接都會從DOM中刪除相應的字段。根據文檔的一切。

所以,我成功地更新了現有的字段(我看到在重新加載後,以及在數據庫中的HTML格式正確的更改)。

問題是,添加/刪除不起作用。沒有錯誤給出。檢入Chrome開發工具:按預期發送參數。

我以前關於表單生成以下文件(和很多課程的谷歌搜索):現在

http://symfony.com/doc/current/forms.html

https://symfony.com/doc/current/best_practices/forms.html

https://symfony.com/doc/current/form/form_collections.html

https://symfony.com/doc/current/reference/forms/types/collection.html

,在this doc陳述爲:

您必須同時創建addTag()和removeTag()方法,否則 即使by_reference爲false,表單仍將使用setTag()。您將在本文後面的章節中詳細瞭解removeTag()方法。

在這一刻我沒有任何引用子實例,因爲它在示例中描述。我只希望能夠編輯相同的普通實體,包括添加新項目和刪除現有項目。也許我錯了,但這在我看來似乎是一個微不足道的基本目標。我不明白如何正確添加'setBasePreset'和'removeBasePreset'方法到'BasePreset'實體本身。

當然,我可以跳過使用表單生成器,但我想利用它的力量作爲框架的一部分。任何建議,例如,可能指向我錯過了一些相關的文檔/教程 - 將不勝感激。

張貼例如(具有一個加法和一個去除):

base_presets[base_presets][5][name]:new_preset 
base_presets[base_presets][5][description]:new, not really added 
base_presets[base_presets][0][name]:ffffas44432df 
base_presets[base_presets][0][description]:asdfffff2333 
base_presets[base_presets][2][name]:ffffasdf2222 
base_presets[base_presets][2][description]:asdff3fff2333 
base_presets[base_presets][3][name]:yoyoshka 
base_presets[base_presets][3][description]:nananaf 
base_presets[base_presets][4][name]:123fffdsaasdf 
base_presets[base_presets][4][description]:pop123 
base_presets[_token]:H2QwRHdvZW1WAdc6VTONnspxvH1U-oC8rCEEprDdMCQ 

的 'BasePresetsType' 類:

<?php 
namespace AppBundle\Form; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\CollectionType; 

class BasePresetsType extends AbstractType { 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder->add('base_presets', CollectionType::class, array(
      'entry_type' => BasePresetType::class, 
      'allow_add' => true, 
      'allow_delete' => true, 
      'by_reference' => false // also tried 'true' but without any success 
     )); 
    } 

    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => null, 
     )); 
    } 
} 

的 'BasePresetType' 類:

<?php 
namespace AppBundle\Form; 

use AppBundle\Entity\BasePreset; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\TextType; 
use Symfony\Component\Form\Extension\Core\Type\TextareaType; 

class BasePresetType extends AbstractType { 
    public function buildForm(FormBuilderInterface $builder, array $options) { 
     $builder 
      ->add('name', TextType::class) 
      ->add('description', TextareaType::class); 
    } 

    public function configureOptions(OptionsResolver $resolver) { 
     $resolver->setDefaults([ 
      'data_class' => BasePreset::class, 
     ]); 
    } 
} 

控制器方法:

​​

的觀點:

{% extends "base.html.twig" %} 

{% block body %} 
    {{ form_start(form) }} 
    {{ form_label(form.base_presets) }} 
    {{ form_errors(form.base_presets) }} 
    <ul class="base-presets" data-prototype="{{ form_widget(form.base_presets.vars.prototype)|e('html_attr') }}"> 
     {% for base_preset in form.base_presets %} 
      <li class="base-preset-item"> 
       {{ form_errors(base_preset) }} 
       {{ form_widget(base_preset) }} 
      </li> 
     {% endfor %} 
     <li class="form-submit"> 
      <input type="submit" value="Submit" class="btn btn-default pull-right" /> 
     </li> 
    </ul> 
    {{ form_end(form) }} 
{% endblock %} 
{% block javascripts %} 
    <script> 
     var $collection_holder; 
     // Setup an "add a base preset" link 
     var $add_base_preset_link = $('<a href="#" class="add_base_preset_link">Add a base preset</a>'); 
     var $new_link_li = $('<li></li>').append($add_base_preset_link); 
     $(document).ready(function() { 
      // Get the ul that holds the collection of base presets 
      $collection_holder = $('ul.base-presets'); 
      // add the "add a base preset" anchor and li to the tags ul 
      $collection_holder.prepend($new_link_li); 
      // count the current form inputs we have, use that as the new index when inserting a new item 
      $collection_holder.data('index', $collection_holder.find('li.base-preset-item').length); 

      $add_base_preset_link.on('click', function (e) { 
       e.preventDefault(); 
       addBasePresetForm($collection_holder, $new_link_li); 
      }); 

      // add a delete link to all of the existing base presets form li elements 
      $collection_holder.find('li.base-preset-item').each(function() { 
       addBasePresetFormDeleteLink($(this)); 
      }); 
     }); 

     function addBasePresetForm($collection_holder, $new_link_li) { 
      // Get the data-prototype 
      var prototype = $collection_holder.data('prototype'); 
      // Get the new index 
      var index = $collection_holder.data('index'); 
      // Replace '__name__' in the prototype's HTML to instead be a number based on how many items we have 
      var new_form = prototype.replace(/__name__/g, index); 
      // increment the index for the next item 
      $collection_holder.data('index', index + 1); 
      // Display the form in the page in an li, before the "Add a base preset" link li 
      var $new_form_li = $('<li class="base-preset-item"></li>').append(new_form); 
      $new_link_li.after($new_form_li); 
      addBasePresetFormDeleteLink($new_form_li); 
     } 

     function addBasePresetFormDeleteLink($base_preset_form_li) { 
      var $remove_form_a = $('<a href="#">Delete this base preset</a>'); 
      $base_preset_form_li.append($remove_form_a); 
      $remove_form_a.on('click', function (e) { 
       e.preventDefault(); 
       $base_preset_form_li.remove(); 
      }) 
     } 
    </script> 
{% endblock %} 

最後,最長的清單 - 在 'BasePreset' 實體類:

<?php 
namespace AppBundle\Entity; 

use Doctrine\Common\Collections\ArrayCollection; 
use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; 


/** 
* Class BasePreset 
* @package AppBundle\Entity 
* 
* @ORM\Entity 
* @ORM\Table(name="base_presets") 
* @UniqueEntity(fields="name", message="There should be only one (unique) base preset") 
*/ 
class BasePreset { 
    /** 
    * @ORM\OneToMany(targetEntity="BaseParamsGroup", mappedBy="base_preset") 
    */ 
    private $base_params_groups; 

    /** 
    * @var int 
    * 
    * @ORM\Column(type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(type="string", length=100) 
    */ 
    private $name; 

    /** 
    * @var string 
    * 
    * @Assert\NotBlank() 
    * @ORM\Column(type="string", length=4000) 
    */ 
    private $description; 

    /** 
    * @var \DateTime 
    * 
    * @ORM\Column(type="datetime") 
    */ 
    private $created; 

    /** 
    * @var \DateTime 
    * 
    * @ORM\Column(type="datetime", columnDefinition="TIMESTAMP on update CURRENT_TIMESTAMP") 
    */ 
    private $updated; 

    public function __construct() { 
     $this->base_params_groups = new ArrayCollection(); 
     $this->created = new \DateTime(); 
     $this->updated = new \DateTime(); 
    } 

    /** 
    * Get id 
    * 
    * @return integer 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

    /** 
    * Set name 
    * 
    * @param string $name 
    * 
    * @return BasePreset 
    */ 
    public function setName($name) 
    { 
     $this->name = $name; 

     return $this; 
    } 

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

    /** 
    * Set description 
    * 
    * @param string $description 
    * 
    * @return BasePreset 
    */ 
    public function setDescription($description) 
    { 
     $this->description = $description; 

     return $this; 
    } 

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

    /** 
    * Set created 
    * 
    * @param \DateTime $created 
    * 
    * @return BasePreset 
    */ 
    public function setCreated($created) 
    { 
     $this->created = $created; 

     return $this; 
    } 

    /** 
    * Get created 
    * 
    * @return \DateTime 
    */ 
    public function getCreated() 
    { 
     return $this->created; 
    } 

    /** 
    * Set updated 
    * 
    * @param \DateTime $updated 
    * 
    * @return BasePreset 
    */ 
    public function setUpdated($updated) 
    { 
     $this->updated = $updated; 

     return $this; 
    } 

    /** 
    * Get updated 
    * 
    * @return \DateTime 
    */ 
    public function getUpdated() 
    { 
     return $this->updated; 
    } 

    /** 
    * Add baseParamsGroup 
    * 
    * @param \AppBundle\Entity\BaseParamsGroup $baseParamsGroup 
    * 
    * @return BasePreset 
    */ 
    public function addBaseParamsGroup(\AppBundle\Entity\BaseParamsGroup $baseParamsGroup) 
    { 
     $this->base_params_groups[] = $baseParamsGroup; 

     return $this; 
    } 

    /** 
    * Remove baseParamsGroup 
    * 
    * @param \AppBundle\Entity\BaseParamsGroup $baseParamsGroup 
    */ 
    public function removeBaseParamsGroup(\AppBundle\Entity\BaseParamsGroup $baseParamsGroup) 
    { 
     $this->base_params_groups->removeElement($baseParamsGroup); 
    } 

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

回答

1

由於您使用了fo沒有數據類RM,您需要直接從形式訪問對象提交的數據:

foreach ($form->get('base_presets')->getData() as $base_preset) { 
    $em->persist($base_preset); 
} 

更新
與管理現有的和持續的新的工作。如果您需要刪除實體,則可以將從數據庫加載的實體與提交的實體進行比較,然後刪除過濾。

+0

它適用於添加新行,但不適用於刪除現有行(仍然沒有錯誤,只是沒有更改)。它可以解決嗎?也許我應該創建一些集合類,將它作爲Data類放入集合表單類型中? – a1111exe

+0

@ a1111exe您可以將'$ base_presets'中的ID與提交的ID進行比較,然後分別調用'$ em-> remove($ notSubmittedEntity);'。 – jkucharovic

+0

我顯然可以,也許應該這樣做。我很好奇,如果這是唯一的方法。例如,對於官方示例中的subentity,不需要這樣做。這個解決方案看起來像一個微妙的黑客,以減少表單系統的一些缺乏靈活性。無論如何,我必須繼續前進,所以它會爲我工作。您能否將此添加到您的答案中,以便將其標記爲已接受? – a1111exe

相關問題