我对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;
}
这很好用,但是 - 这是我的问题 - 如何获取页面的所有Photo
或Video
。我尝试过添加
/**
* @ORM\OneToMany(targetEntity="Photo", mappedBy="page", cascade={"persist"})
* @var ArrayCollection|Photo[]
*/
protected $photos;
到Page
,但这会导致架构错误,因为它没有在Photo上定义逆。非常感谢任何帮助!
答案 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:
映射的超类不能是实体,它不具有查询能力 由映射的超类定义的持久关系必须是 单向的(仅限拥有方)。这意味着一对多 根本不可能在映射的超类上进行关联。 此外,只有映射后,才能实现多对多关联 超类目前仅用于一个实体。对于 进一步支持继承,单个或连接表继承 必须使用功能。