2016-09-12 4 views
0

私はSymfony2.8.10とDoctrineでコレクションの永続性について質問します。 次のエンティティクラスArticleおよびArticleAttributeを記述しました。コレクションアイテムを削除できません。 (CollectionType、OneToMany双方向を使用)

/** 
* Article 
* 
* @ORM\Table(name="article") 
* @ORM\Entity(repositoryClass="AppBundle\Repository\ArticleRepository") 
* @ORM\HasLifecycleCallbacks 
* */ 
class Article 
{ 
    /** @ORM\Id @ORM\Column(type="integer") */ 
    private $id; 
    /** @ORM\Column(type="string") */ 
    private $title; 

    /** 
    * @var ArticleAttribute[] 
    * @ORM\OneToMany(targetEntity="ArticleAttribute", mappedBy="article", cascade={"ALL"}) 
    */ 
    private $attributes; 

    /** 
    * Constructor 
    */ 
    public function __construct() 
    { 
     $this->attributes = new ArrayCollection(); 
    } 

    /** 
    * Get attributes 
    * 
    * @return ArticleAttribute[] 
    */ 
    public function getAttributes() 
    { 
     return $this->attributes; 
    } 

    /** 
    * @param $item ArticleAttribute 
    */ 
    public function addAttribute($item) 
    { 
     $this->attributes[$item->getAttribute()] = $item; 
     $item->setArticle($this); 
    } 

    /** 
    * Remove attributes 
    * 
    * @param ArticleAttribute $attribute 
    */ 
    public function removeAttribute(ArticleAttribute $attribute) 
    { 
     $this->attributes->removeElement($attribute); 
    } 
... 

/** 
* @ORM\Table(name="article_attribute") 
* @ORM\Entity 
*/ 
class ArticleAttribute 
{ 
    /** 
    * @var Article 
    * @ORM\Id 
    * @ORM\ManyToOne(targetEntity="Article", inversedBy="attributes") 
    * @ORM\JoinColumn(name="article_id", referencedColumnName="id") 
    */ 
    private $article; 

    /** 
    * @ORM\Id 
    * @ORM\Column(type="string") 
    */ 
    private $attribute; 

    /** 
    * Get article 
    * 
    * @return Article 
    */ 
    public function getArticle() 
    { 
     return $this->article; 
    } 

    /** 
    * Set article 
    * 
    * @param Article $article 
    * @return ArticleAttribute 
    */ 
    public function setArticle(Article $article) 
    { 
     $this->article = $article; 
     return $this; 
    } 
.... 

これらのクラスを形成するためにバインドされました。

class ArticleType extends AbstractType 
{ 
    /** 
    * @param FormBuilderInterface $builder 
    * @param array $options 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('id') 
      ->add('title') 
      ->add('attributes', CollectionType::class, [ 
       'entry_type' => ArticleAttributeType::class, 
       'allow_add' => true, 
       'allow_delete' => true, 
      ]); 
    } 

上記コードはFormTypeの一部です。

ページの複数のArticleAttributesを削除してください。 フォームを送信してください。 handleRequestと$ em-> flush();を呼び出します。 削除されたアイテムはまだデータベースに残っています。

この問題の回避策を見つけました。 FormResizeListenerクラスのonSubmitメソッドを変更しました。

public function onSubmit(FormEvent $event) 
    { 
     /** @var FormBuilder $form */ 
     $form = $event->getForm(); 
     /** @var PersistentCollection $data */ 
     $data = $event->getData(); 

     // At this point, $data is an array or an array-like object that already contains the 
     // new entries, which were added by the data mapper. The data mapper ignores existing 
     // entries, so we need to manually unset removed entries in the collection. 

     if (null === $data) { 
      $data = []; 
     } 

     if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) { 
      throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)'); 
     } 

     if ($this->deleteEmpty) { 
      $previousData = $event->getForm()->getData(); 
      foreach ($form as $name => $child) { 
       $isNew = !isset($previousData[$name]); 

       // $isNew can only be true if allowAdd is true, so we don't 
       // need to check allowAdd again 
       if ($child->isEmpty() && ($isNew || $this->allowDelete)) { 
        unset($data[$name]); 
        $form->remove($name); 
       } 
      } 
     } 

     // The data mapper only adds, but does not remove items, so do this 
     // here 
     if ($this->allowDelete) { 
      $arr = (array)$data; //added 
      /** @var EntityManager $em */ //added 
      $em = @$arr["\0Doctrine\\ORM\\PersistentCollection\0em"]; //added 

      $toDelete = []; 

      foreach ($data as $name => $child) { 
       if (!$form->has($name)) { 
        $toDelete[] = $name; 
       } 
      } 

      foreach ($toDelete as $name) { 
       if ($em) $em->remove($data[$name]); //added 
       unset($data[$name]); 
      } 
     } 

     $event->setData($data); 
    } 

$ em-> removeを呼び出すと、削除された項目の削除が作業単位に登録されます。

変更後。削除されたアイテムはデータベースから正しく削除されます。 しかし、これは厄介だと思います。 この問題を回避する正しい方法を教えてください。 私はあなたの助けに感謝します。

答えて

2

ことは私もthis article

+0

を読むことをお勧めorphanRemovalオプション

/** * @var ArticleAttribute[] * @ORM\OneToMany(targetEntity="ArticleAttribute", mappedBy="article", cascade={"ALL"}, orphanRemoval=true) */ private $attributes; 

を追加ArticleAttributesArticle関係を変更しようとするあなたの助けをいただき、ありがとうございます。 – Miwanoushi

+0

orphanRemovalオプションを追加しようとしました。 正常に動作します。 簡単な方法。 私はあなたの助けを借りて迷路から出ることができました。 – Miwanoushi

+0

@Miwanoushi:私がリンクしている外部参照もお読みください。深いところでどのように動作するかを知ることが重要です。また、これが正解であれば、「緑色のマーク」で確認してください。ありがとうございました。 – DonCallisto

関連する問題