具有ManyToOne关系的单表继承(STI)

时间:2015-12-24 21:50:55

标签: php doctrine-orm

我对Doctrine很新,所以欢迎任何一般建议。我试图实现以下目标:

一个页面可以包含视频和照片。两者都是媒体和共享属性,所以我认为单表继承是有道理的。以下是我的设置的相关部分:

网页

/**
 * @ORM\Entity
 */
class Page {

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="Media", mappedBy="page", cascade={"persist"})
     * @var ArrayCollection|Media[]
     */
    protected $media;

    /**
     * @return Media[]|ArrayCollection
     */
    public function getMedia()
    {
        return $this->media;
    }
}

媒体

/**
 * @ORM\Entity
 * @ORM\Table(name="media")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="media_type", type="string")
 * @ORM\DiscriminatorMap({"video" = "Video", "photo" = "Photo"})
 */
abstract class Media {

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $url;

    /**
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="media")
     */
    protected $page;
}

照片

/**
 * @ORM\Entity
 */
class Photo extends Media {

    /**
     * @ORM\Column(type="string")
     */
    protected $exif;
}

视频

/**
 * @ORM\Entity
 */
class Video extends Media {

    /**
     * @ORM\Column(type="integer")
     */
    protected $length;
}

这很好用,但是 - 这是我的问题 - 如何获取页面的所有PhotoVideo。我尝试过添加

之类的内容
/**
 * @ORM\OneToMany(targetEntity="Photo", mappedBy="page", cascade={"persist"})
 * @var ArrayCollection|Photo[]
 */
protected $photos;

Page,但这会导致架构错误,因为它没有在Photo上定义逆。非常感谢任何帮助!

3 个答案:

答案 0 :(得分:2)

您可以将过滤器应用于媒体集

class Page {
    .....
    public function getPhotos()
    {
        return $this->getMedia()->filter(
            function($media) {
                return $media instanceof Photo;
            }
        );
    }

    public function getVideos()
    {
        return $this->getMedia()->filter(
            function($media) {
                return $media instanceof Video;
            }
        );
    }
}

请记住,它会在单个select查询中获取所有媒体,实例化照片和视频,然后过滤结果。它可能会影响性能,但您可能会受益于doctrine缓存,具体取决于您的方案。

如果性能是关键,您可能需要在PageRepository中实现自定义方法,以便使用instance of dql实际仅获取媒体子集,如Query the Type中所述。

答案 1 :(得分:1)

我认为您可以通过在特定子类上使用join来解决此问题:

$queryBuilder->select('m')
   ->from('Media', 'm')
   ->join('Photo', 'p', 'WITH', 'm.id = p.id')
   ->where('m.page = :page_id')
   ->setParameter('page_id', $pageId);

答案 2 :(得分:1)

您的$media类中将无法使用映射到超类的Page属性。您必须拥有每个级别的房产。请参阅note in the Doctrine docs

  

映射的超类不能是实体,它不具有查询能力   由映射的超类定义的持久关系必须是   单向的(仅限拥有方)。这意味着一对多   根本不可能在映射的超类上进行关联。   此外,只有映射后,才能实现多对多关联   超类目前仅用于一个实体。对于   进一步支持继承,单个或连接表继承   必须使用功能。