我对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上没有定义反向。非常感谢您的帮助!
您可以对媒体集合应用筛选器
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
查询中获取所有媒体,实例化照片和视频,然后过滤结果。它可能会影响性能,但您可能会从条令缓存中受益,具体取决于您的场景。
如果性能是一个关键,您可能需要在PageRepository
中实现一个自定义方法,以便使用查询类型中所述的instance of
dql实际仅获取媒体的子集。
我认为您可以通过在特定子类上使用join
来解决这个问题:
$queryBuilder->select('m')
->from('Media', 'm')
->join('Photo', 'p', 'WITH', 'm.id = p.id')
->where('m.page = :page_id')
->setParameter('page_id', $pageId);
您的Page
类上不能有一个映射到超类的$media
属性。每个类都必须有一个属性。参见条令文件中的注释:
映射的超类不能是实体,它不可查询,并且映射超类定义的持久关系必须是单向(仅与拥有方)。这意味着一对多在映射的超类上根本不可能有关联。此外,只有当映射超类目前只在一个实体中使用。对于进一步支持继承、单表或联接表继承必须使用功能。