Symfony表单集合无法保存引用

4

我有一个实体,其中包含多张照片:

/**
 * related images
 * @ORM\OneToMany(targetEntity="Photo", mappedBy="entity",cascade={"persist"})
 * @ORM\OrderBy({"uploaded_at" = "ASC"})
 */
private $photos;

照片与实体之间有多对一的关系

    /**
 * @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entity\Entity", inversedBy="photos")
 * @ORM\JoinColumn(name="entity_id", referencedColumnName="id", onDelete="CASCADE")
 */
private $entity;

所有的setter和getter都已设置,我正在遵循Symfony集合文档:http://symfony.com/doc/current/reference/forms/types/collection.html

表单类型:

             ->add('photos', 'collection', array(
             'type' => new PhotoFormType(),
             'allow_add' => true,
             'by_reference' => false,
             'allow_delete' => true,
             'prototype' => true

         ))

照片类型:

        $builder
        ->add('title', null, ['label' => 'front.photo.title', 'required' => true])
        ->add('image', 'file', array('required' => false))
    ;

我使用vichUploadableBundle进行上传,图片保存正常,但entity_id未保存且为null。我不知道我错过了什么。
4个回答

6

以下是目前使用Symfony表单组件进行调查或研究的最佳解决方案。

表单类型:

     ->add("photos",'collection', array(
            'type' => new PhotoFormType(),
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false
))

实体类
public function addPhoto(Photo $photo)
{
    $photo->setEntity($this);
    $this->photos->add($photo);        
}

public function removePhoto(Photo $photo)
{
    $this->photos->removeElement($photo);
}

最佳实践是不要使用循环手动绑定引用实体。请记住,by_reference必须为false,例如'by_reference' => false。

谢谢,by_reference => false 这一行对我很有帮助! - DelphiLynx
最干净的解决方案,无需在控制器上迭代每个元素。 - Williams A.
请记得在实体类的removePhoto方法中添加$photo->setEntity(null)以在编辑时删除照片,并在实体类的照片注释中添加orphanRemoval=true - ericksho

4

遇到了相同的问题,但我记得有更好的解决方案。

你需要在具有集合的实体中指定添加和删除函数。

class Entity
{
    // ...

    public function addPhoto(Photo $photo)
    {
        $this->photos->add($photo);
        $photo->setEntity($this);
    }

    public function removePhoto(Photo $photo)
    {
        $this->photos->removeElement($photo);
    }
}

在这种情况下,控制器中就不需要循环。另外,如果设置了

orphanRemoval=true

,删除也没有问题。

+1 对于 orphanRemoval=true 的技巧,我有一个反向关系并且删除元素时遇到了问题。使用这个技巧后,我不需要在控制器中迭代每个元素并将其删除。 - Williams A.

3

我也遇到了这个问题。我认为主要问题是,即使主实体具有cascade={"persist"},在创建新条目时,子实体也不会获得ID。

所以我的解决方法,有点hacky,但是很有效的是这里

// $em->persist($entity);  After persisting entity:
foreach ($entity->getPhotos() as $photo) {
    $photo->setEntity($entity);
}

基本上是在创建父实体后将ID保存在子实体中。

但另一方面,至少我对Doctrine的理解是这样的,如果我理解有误,请纠正我。尝试添加orphanRemoval/fetch附加属性:

父实体具有:

 /**
  * Related images.
  * @ORM\OneToMany(targetEntity="Photo", mappedBy="entity", cascade={"persist"}, orphanRemoval=true, fetch="EAGER")
  * @ORM\OrderBy({"uploaded_at" = "ASC"})
  */

  private $photos;

我猜你可能可以在一个add方法中完成这个操作,而不是遍历它们。不过这似乎是Doctrine应该处理的事情。 - Hayden

0

照片实体被持久化,因此我添加了控制器处理程序,以设置每个照片实体。不知道这是否是正确的解决方案,但它正在工作。

                /** @var Photo $photo */
                foreach ($entity->getPhotos() as $photo){
                    $photo->setEntity($entity);
                    $em->persist($photo);
                }

看起来不错,但我不会在每个循环中执行持久化操作,只需要在foreach之后执行$em->flush()即可 :) - Martin Fasani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接