私は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を呼び出すと、削除された項目の削除が作業単位に登録されます。
変更後。削除されたアイテムはデータベースから正しく削除されます。 しかし、これは厄介だと思います。 この問題を回避する正しい方法を教えてください。 私はあなたの助けに感謝します。
を読むことをお勧め
orphanRemoval
オプションを追加
ArticleAttributes
でArticle
関係を変更しようとするあなたの助けをいただき、ありがとうございます。 – MiwanoushiorphanRemovalオプションを追加しようとしました。 正常に動作します。 簡単な方法。 私はあなたの助けを借りて迷路から出ることができました。 – Miwanoushi
@Miwanoushi:私がリンクしている外部参照もお読みください。深いところでどのように動作するかを知ることが重要です。また、これが正解であれば、「緑色のマーク」で確認してください。ありがとうございました。 – DonCallisto