PHP 中没有 ORM 映射的 DDD 值对象和实体

DDD Value Objects and Entity Without ORM Mapping in PHP

首先,据我所知,DDD 中的实体与值对象几乎相同,只是实体具有身份。我读过的每篇文章都说实体 ID 与任何 ORM 工具都有 ORM 映射。但是我不想在 Entity 中使用 ORM 映射。相反,我想在没有映射的情况下使用存储库接口进行数据库操作。而且,在这种情况下,我不知道应该怎么做。

我会在下面举例说明

假设我有一个 TODO 应用程序,TODO 中有一些问题,每个问题都有一些答案。

我们有 3 个值对象(或实体): 去做 Todo问题 TodoQuestionValue

现在,我认为我有一个 TODO 的值对象(或实体)。此值对象有一个获取问题的方法,该方法获取 TodoQuestion 值对象的数组。在 TodoQuestion 值对象内部,我们有一个获取问题值的方法,该方法获取 TodoQuestionValue 数组。

<?php
class Todo{
   private int $id;
   /**
    * @param array<TodoQuestion> $questions
    */
   private array $questions;
   private TodoRepositoryInterface $repository;
   public function __constructor(TodoRepositoryInterface $repository){
      $this->repository = $repository;
   }
   public function getQuestions(){
      $this->questions = $this->repository->listQuestionsByTodoId($this->id);
   }
}
<?php
class TodoQuestion{
   private int $id;
   private string $question;
   /**
    * @param array<TodoQuestionValue> $values
    */
   private array $values;
   private TodoRepositoryInterface $repository;
   public function __constructor(TodoRepositoryInterface $repository){
      $this->repository = $repository;
   }
   public function getValues(){
      $this->values = $this->repository->listValuesByQuestionId($this->id);
   }
}

现在,我想听听您对我如何通过遵循 DDD 规则塑造这个结构的意见。

谢谢。

Let’s assume I have a TODO application and there are some questions in the TODO and some answers in each those questions.

您只需要将其翻译成代码即可。这里唯一的实体是 Todo。使其成为聚合根并为其创建存储库。

<?php

class Todo
{
    private int $id;
    /**
     * @param array<TodoQuestion> $questions
     */
    private array $questions;

    public function getQuestions()
    {
        return $this->questions;
    }
}

问题有答案。您可以使用 2 个值对象对其进行建模:问题和答案。

<?php

class TodoQuestion
{
    private string $question;
    private array $values;
    /**
     * @var TodoAnswer[]
     */
    private array $answers;

    public function getValues()
    {
        return $this->values;
    }

    public function getAnswers(): array
    {
        return $this->answers;
    }
}

您的模型永远不应依赖于存储库。存储库任务是保存聚合的状态并在查询聚合时重建相同的状态。

interface TodoRepository {
    public function save(Todo $todo): void;

    public function todoOfId(TodoId $id): Todo;
}

您只需要这 2 种方法。如果你想获得一个 Todo 的问题列表,你只需获取 Todo 聚合根,然后调用 ->getQuestions()。在您的存储库实现中,您可以决定使用 orm、编写原始查询、序列化聚合然后保存它……只要确保您的模型与这些基础架构问题分离,可能性是无限的。