Добрый день.
Я использую Symfony 3, Doctrine ORM, SonataAdminBundle.
Возникла задача, решением которой мне видится внедрение определённого интерфейса, однако я пока что не представляю, как правильно хранить данные такой структуры в базе и править в админке.
Предположим, есть такие исходные условия (прошу прощения за искусственность построения).
Есть сущность "Film", которая обладает какими-то своими свойствами (нам они не интересны). Для фильмов есть таблица в БД `film`.
Класс Film/**
* @ORM\Table(name="film")
* @ORM\Entity
*/
class Film
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
}
Есть сущность "User", которая означает пользователя. Таблица `user` в БД.
Класс User/**
* @ORM\Table(name="user")
* @ORM\Entity
*/
class User
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
}
Есть сущность "Cinema". У кинотеатра, среди прочего, есть поле "Город", которое определяет, в каком городе расположен кинотеатр. Для кинотеатров есть таблица в БД `cinema`.
Класс Cinema/**
* @ORM\Table(name="cinema")
* @ORM\Entity
*/
class Cinema
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var Town
*
* @ORM\ManyToOne(targetEntity="Town")
* @ORM\JoinColumn(name="town_id", referencedColumnName="id", nullable=false)
*/
private $town;
/**
* @return Town
*/
public function getTown()
{
return $this->town;
}
...
}
Ну и есть, собственно, сущность "Город":
Класс Town/**
* @ORM\Table(name="town")
* @ORM\Entity
*/
class Town
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
}
Далее возникает необходимость создать из этих данных "лог просмотров", т.е. объединить данные о каждом просмотре в сущности "View" (т.е. "Просмотр", ничего общего с view из MVC). Таблица `view` в БД:
Класс View/**
* @ORM\Table(name="view")
* @ORM\Entity
*/
class View
{
/**
* @var User
*
* @ORM\ManyToOne(targetEntity="User")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*/
private $user;
/**
* @var Film
*
* @ORM\ManyToOne(targetEntity="Film")
* @ORM\JoinColumn(name="film_id", referencedColumnName="id", nullable=false)
*/
private $film;
/**
* @var Cinema
*
* @ORM\ManyToOne(targetEntity="Cinema")
* @ORM\JoinColumn(name="cinema_id", referencedColumnName="id", nullable=false)
*/
private $cinema;
/**
* @return Cinema
*/
public function getCinema()
{
return $this->cinema;
}
...
}
Довольно простая схема, дающая довольно простую структуру таблиц и связей между ними.
Предположим, что в нашей бизнес-логике очень важным является
то, в каком городе пользователь осуществил просмотр. Для этого мы, имея объект класса "View" без проблем вызываем $view->getCinema()->getTown(), двигаясь по цепочке many-to-one.
Но вдруг оказывается, что
пользователь мог посмотреть фильм не только в кинотеатре (ВНЕЗАПНО), но и:
- по телевизору
- по компьютеру
На уровне кода решение кажется предельно простым: в классе "View" вместо поля "cinema" должно быть поле "viewPlace" (место просмотра), которое содержит объект, реализующий интерфейс ViewPlaceInterface, который обладает методом getTown(), что позволит нам вызвать $view->getViewPlace()->getTown():
Новый класс View, интерфейс ViewPlaceInterface, классы Cinema, TV, Computerclass View
{
...
/**
* @var ViewPlaceInterface
*/
private $viewPlace;
/**
* @return ViewPlaceInterface
*/
public function getViewPlace()
{
return $this->viewPlace;
}
...
}
interface ViewPlaceInterface
{
/**
* @return Town
*/
public function getTown();
}
class Cinema implements ViewPlaceInterface
{
/**
* @return Town
*/
public function getTown()
{
...
}
}
class TV implements ViewPlaceInterface
{
/**
* @return Town
*/
public function getTown()
{
...
}
}
class Computer implements ViewPlaceInterface
{
/**
* @return Town
*/
public function getTown()
{
...
}
}
Вопрос:
как реализовать это в условиях Symfony 3, Doctrine ORM, SonataAdminBundle?
Какие должны быть сущности, какие таблицы, какие аннотации?
Как должна быть сконфигурирована админка, чтобы всё это можно было заполнять через неё?
Спасибо.