Doctrine нарушает концепцию DDD?

Смотрела на сайте симфони пример применения доктрины:

/**
 * @ORM\Entity(repositoryClass=ProductRepository::class)
 */
class Product {
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    /**
     * @ORM\Column(type="integer")
     */
    private $price;

    public function getId(): ?int {
        return $this->id;
    }

    // ... getter and setter methods
}

В итоге получаем, что мы делаем маппинг сущности. Но ведь сущность в концепции DDD - это класс, который не должен никак зависеть или знать о внешних вещах, таких как фреймворки или БД. DDD специально для code first. А тут, в конечном итоге, получается сущность - отражение строки в БД.

Может быть я что-то не понимаю? Или конкретно эти сущности для маппинга и сущности доменного слоя - это разные вещи и описываются в разных местах? А как и где если например у меня есть такой класс в доменном слое:

Employee(
    new Id(25), // value object
    new \DateTimeImmutable(),
    new Name('Пупкин', 'Василий', 'Петрович'), // value object
    new Address('Россия', 'Липецкая обл.', 'г. Пушкин', 'ул. Ленина', 25), //value object
    [
        new Phone(7, '920', '00000001'),  // value object
        new Phone(7, '910', '00000002'),
    ]
);
  • Employee - одна таблица
  • Address - другая таблица
  • Phone - третья таблица

Ответы (1 шт):

Автор решения: Vitalii Marenkov

Symfony и Doctrine - универсальные инструменты и не предназначены специально для DDD. Тем не менее, благодаря их гибкости, их можно использовать для реализации DDD.

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

В вашем примере value objects надо объявить как Embedded, вот так:

/**
 * @Embeddable
 */
class Name
{
    /**
     * @ORM\Column(type="string", length=255)
     */
    private $firstName;
     
    ...
}

class Employee
{
    /**
     * @var Name
     * 
     * @Embedded(class = "App\ValueObject\Name", columnPrefix = "name_")
     */
    private $name;
    ...
}

При этом все данные будут храниться в одной таблице.

Сложнее дело обстоит со списком телефонов. Для них все же придется использовать отдельную таблицу и связь один ко многим. При этом с точки зрения модели данных, номера телефонов будут выглядеть как сущности, но в модели домена это должны быть объекты-значения с невидимым для клиентов идентификатором.

→ Ссылка