Вот сделка.
Используя Doctrine ORM для PHP, мне нужно «отделить» модель от персистентного слоя сущности.
Скажем, у нас есть UserEntity, которая содержит все приятные вещи для отображения БД
как: аннотации, свойства, установщики / получатели и так далее.
С другой стороны, я хотел бы иметь отдельный класс User, который содержит только логику, связанную с бизнесом, например: User :: getFullName ().
Кроме того, я хочу, чтобы пользователь расширил UserEntity, чтобы пользователь наследовал все методы доступа.
Возможные решения, которые я проверил, не работают для меня:
есть идеи ?
Попался ! (> = Решение PHP 5.4)
Коротко: сделайте сущность признаком, используйте признак сущности в классе модели.
Оформить заказ на этой странице документа: http://doctrine-orm.readthedocs.org/en/latest/tutorials/override-field-association-mappings-in-subclasses.html.
Пример:
Предположим, у нас есть модель пользователя. Сначала создайте пользовательский объект:
/**
* @ORM\Table(name="user")
*/
trait UserEntity {
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="first_name", type="string", length=100, nullable=true)
*/
protected $firstName;
/**
* @var string
*
* @ORM\Column(name="last_name", type="string", length=100, nullable=true)
*/
protected $lastName;
// other mapping here...
}
Затем создайте модель и используйте в ней черту сущности:
/**
* @ORM\Entity
*/
class User {
use UserEntity;
public function getFullName() {
return $this->firstName . ' ' . $this->lastName;
}
}
Mind @Entity аннотация в пользовательской модели. Это необходимо для непосредственного использования модели
в менеджере сущностей.
Теперь предположим, что нам нужна модель администратора, которая расширяет пользовательскую модель. Это немного сложно.
Мы должны изменить @Entity на @MappedSuperclass в User, чтобы его можно было расширить.
Затем создайте модель администратора, объявите ее как @Entity, а также повторно объявите имя таблицы на ней
использование аннотации @Table (в противном случае Doctrine будет перепутана из какой таблицы по какой-либо причине).
Выглядеть так:
/**
* @ORM\MappedSuperclass
*/
class User {
use UserEntity;
public function getFullName() {
return $this->firstName . ' ' . $this->lastName;
}
}
/**
* @ORM\Entity
* @ORM\Table(name="user")
*/
class Admin extends User {
public function getFullName() {
return parent::getFullName() . ' (admin)';
}
}
Таким образом, в Doctrine могут использоваться как пользовательские, так и административные модели (= сущности).
И нет, мы можем делать то, что мы обычно делаем с сущностями:
найти () их через менеджер сущностей, использовать модели непосредственно в запросах и т. д.
Вы можете использовать магические методы в PHP для пересылки всех вызовов методов доступа, таких как:
class UserModel
{
protected $userEntity;
public function __construct($entity)
{
$this->userEntity = $entity;
}
public function __call($name, $arguments)
{
if (!method_exists($this, $name) AND method_exists($this->userEntity, $name)) {
return call_user_func_array(array($this, $name), $arguments);
}
}
}
Вы можете определить свой собственный локальный класс EntityRepository, который расширяет Doctrine\ORM\EntityRepository
, Таким образом, вы можете убедиться, что find
, findBy
, findOneBy
методы создадут новые экземпляры вашей Модели, установят объект $ entity внутри Модели и вернут новый экземпляр Model вместо Entity.
Вы можете написать класс модели (без регистрации его в Doctrine2), который расширяет класс сущности, и написать свой собственный класс Hydrator (и зарегистрировать его в Doctrine2), чтобы убедиться, что ваши результаты будут возвращены в виде массива класса Model, а не массива. класса Entity.
Вы можете определить все эти «бизнес-логики, связанные с БД», внутри вашего класса репозитория сущностей и все эти «бизнес-логики, не связанные с БД», внутри класса сервисов (вы можете создать сервис, выделенный для одного объекта, если хотите) , А затем вызовите уровень бизнес-логики (сервисы, репозитории) с параметрами db-logic (сущности).
С другой стороны, способ Symfony очень гибок, поскольку вы можете создавать любые функциональные возможности вне предустановленной структуры Symfony, если они являются PSR.
О кастом гидраторе.
Короче говоря, это решение также не вариант для меня (хотя я могу что-то упустить, хотя). две подводные камни здесь:
В результате, решение, предложенное Михаем Станку, не работает для меня.
Ну, в последнее время я задавал себе этот вопрос, и простой ответ, к которому я пришел, состоит в том, чтобы переместить все аннотации из сущности в yaml или xml для удаления моей «модели» / сущности.
Тогда у меня есть все мои свойства в моем пользовательском классе, но вся конфигурация персистентности была удалена, тогда вы также можете делать что хотите с геттерами и сеттерами (по моему мнению, удалить как можно больше).