2015-12-24 2 views
3

Я довольно новичок в Доктрине, поэтому любые общие советы приветствуются. Я пытаюсь достичь:Однозначное наследование (STI) с отношением ManyToOne

На странице могут быть как видео, так и фотографии. Оба являются средами и общими свойствами, поэтому я думал, что однозначное наследование имеет смысл. Вот соответствующие части моей установки:

Page

/** 
* @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, но это приводит к ошибке схемы, так как она не имеет обратного, определенный на фото. Любая помощь очень ценится!

ответ

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; 
      } 
     ); 
    } 
} 

Имейте в виду, он будет получать все Medias в одном запросе select, создайте экземпляр как фотографий, так и видео, а затем отфильтруйте результат. Это может повлиять на производительность, но вы можете использовать кеш доктрины в зависимости от вашего сценария.

Если производительность является ключевым, вам может понадобиться для реализации пользовательских методов в PageRepository на самом деле принести только подмножество медиа с использованием instance of DQL, как описано в Query the Type.

+0

Это ответ, который я искал. Благодарим вас за то, что вы назвали плюсы и минусы + альтернативным решением, используя репозиторий. – DerLola

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); 
+0

Действительный ответ, но мне нравится, что Алекс отвечает лучше, так как он соответствует моей ситуации. – DerLola

1

Вы не сможете найти отдельную недвижимость $media в своем классе Page, который соответствует классу суперкласса. У вас должно быть свойство для каждого класса. Смотрите note in the Doctrine docs:

сопоставленного суперкласс не может быть объектом, он не запрашивать-способным и постоянных отношений, определяемых сопоставленный суперкласс должны быть однонаправленным (с только стороны владеющего). Это означает, что ассоциации «один-ко-многим» не могут быть объединены в сопоставленный суперкласс. Кроме того, ассоциации Many-To-Many возможны только в том случае, если сопоставленный суперкласс класса используется только в одном объекте на данный момент. Для дальнейшая поддержка наследования, необходимо использовать однонаправленное или объединенное наследование таблицы .

+0

Имеет смысл, за исключением того, что в этом случае я не использую сопоставленный суперкласс, а STI. Объект Media на самом деле является сущностью, поэтому цитируемые документы не применяются. Кроме этого, отличный ответ. – DerLola

Смежные вопросы