Доктрина — отделенная модель от сущности

Вот сделка.
Используя Doctrine ORM для PHP, мне нужно «отделить» модель от персистентного слоя сущности.
Скажем, у нас есть UserEntity, которая содержит все приятные вещи для отображения БД
как: аннотации, свойства, установщики / получатели и так далее.
С другой стороны, я хотел бы иметь отдельный класс User, который содержит только логику, связанную с бизнесом, например: User :: getFullName ().
Кроме того, я хочу, чтобы пользователь расширил UserEntity, чтобы пользователь наследовал все методы доступа.

Возможные решения, которые я проверил, не работают для меня:

  • просто расширение модели из сущности, а затем указание модели в DQL не работает
  • make UserEntity / ** @MappedSuperclass * / не работает, так как в этом случае UserEntity «не является сущностью»
  • InheritanceType / DiscriminatorColumn / DiscriminatorMap не работает, так как модель не является сущностью

есть идеи ?

4

Решение

Попался ! (> = Решение 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 могут использоваться как пользовательские, так и административные модели (= сущности).

И нет, мы можем делать то, что мы обычно делаем с сущностями:
найти () их через менеджер сущностей, использовать модели непосредственно в запросах и т. д.

2

Другие решения

Эй, дети хотят купить магию?

Вы можете использовать магические методы в 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.

Хотите более чистую интеграцию с результатами Doctrine?

Вы можете написать класс модели (без регистрации его в Doctrine2), который расширяет класс сущности, и написать свой собственный класс Hydrator (и зарегистрировать его в Doctrine2), чтобы убедиться, что ваши результаты будут возвращены в виде массива класса Model, а не массива. класса Entity.

Хотите сделать это способом Symfony?

Вы можете определить все эти «бизнес-логики, связанные с БД», внутри вашего класса репозитория сущностей и все эти «бизнес-логики, не связанные с БД», внутри класса сервисов (вы можете создать сервис, выделенный для одного объекта, если хотите) , А затем вызовите уровень бизнес-логики (сервисы, репозитории) с параметрами db-logic (сущности).

С другой стороны, способ Symfony очень гибок, поскольку вы можете создавать любые функциональные возможности вне предустановленной структуры Symfony, если они являются PSR.

0

О кастом гидраторе.
Короче говоря, это решение также не вариант для меня (хотя я могу что-то упустить, хотя). две подводные камни здесь:

  1. не удобно переназначать исходные данные из базы данных в объект модели внутри собственного гидратора. проблема заключается в том, что поля в таблице БД являются «отдельными словами» (например, «имя / фамилия»), тогда как, как и в объектах, я вручную изменил их, чтобы они были в верблюжьей оболочке (для удобства чтения). это, конечно, может быть решено чтением метаинформации из аннотаций сущностей, но это потребует магии и дополнительных временных ресурсов. так что это решение было бы довольно «грязным».
  2. Как бы я использовать пользовательский гидратор, например, «найти» функции? как: $ em-> find (‘My \ Model \ User’, 1)? Потому что я хочу, чтобы мои модели могли быть использованы на сто процентов в любом месте, где будет использоваться сущность.

В результате, решение, предложенное Михаем Станку, не работает для меня.

  • Магия внутри модельного класса: не чистое решение, потому что оно предполагает передачу сущности в конструктор и не даст вам подсказки типа (причина волшебства __call)
  • Таможенный гидратор: кажется более чистым, но не может использоваться во всех случаях, и переназначение из необработанного результата db в объект модели является сложным (= много времени)
  • Способ обслуживания Symfony: также не чистое решение, потому что мне нужно 100% разделение логики модели и логики, связанной с БД (поэтому в моей модели нет ни одной информации / аннотации отображения, просто чисто бизнес-логика)
0

Ну, в последнее время я задавал себе этот вопрос, и простой ответ, к которому я пришел, состоит в том, чтобы переместить все аннотации из сущности в yaml или xml для удаления моей «модели» / сущности.

Тогда у меня есть все мои свойства в моем пользовательском классе, но вся конфигурация персистентности была удалена, тогда вы также можете делать что хотите с геттерами и сеттерами (по моему мнению, удалить как можно больше).

0
По вопросам рекламы [email protected]