Php 域驱动设计,实体调用存储库验证相关资源

Php 域驱动设计,实体调用存储库验证相关资源,php,architecture,domain-driven-design,Php,Architecture,Domain Driven Design,我正在尝试用php实现DDD。我有一个名为message的实体,它与fromFieldId相关。当在消息上设置此fromField时,我想验证它是否存在于数据库中,我不想让调用者承担此验证的负担,因为它发生在代码中的许多地方。然而,根据我在DDD中的理解,实体不应该调用存储库?在DDD中如何处理此问题 我想要这样的东西: class MessageEntity{ public function setFromFieldId($fromFieldId){ if(!$t

我正在尝试用php实现DDD。我有一个名为message的实体,它与fromFieldId相关。当在消息上设置此fromField时,我想验证它是否存在于数据库中,我不想让调用者承担此验证的负担,因为它发生在代码中的许多地方。然而,根据我在DDD中的理解,实体不应该调用存储库?在DDD中如何处理此问题

我想要这样的东西:

class MessageEntity{

     public function setFromFieldId($fromFieldId){
         if(!$this->fromFieldRepository->isExists($fromFieldId)){
              // throw some exception
         }
         $this->fromFieldId = $fromFieldId;
     }

 }

您可以简单地从存储库加载FromField AR,并将整个实例传递给消息AR,但只保留id

伪代码:

MessageApplicationService {
    setFromFieldId(messageId, fromFieldId) {
        fromField = fromFieldRepository.findById(fromFieldId);

        //You could have a null check for fromField here
        //or call a method that throws automatically
        //e.g. findExistingById(). You could also prevent
        //null from being passed in message.setFromField

        message = messageRepository.findById(messageId);
        message.setFromField(fromField); //only holds onto the id
    }
}

我认为您需要的是一个
域服务
,即DDD

来自Eric Evans域驱动设计:

当域中的重要流程或转换不是实体或值对象的自然职责时,将操作作为声明为服务的独立接口添加到模型中。根据模型的语言定义接口,并确保操作名称是通用语言的一部分。使服务无状态

在您的情况下,如果在您的通用语言中只设置一次字段是一个合适的概念,那么一种方法可以是:

class SettingFieldOnceService
{
    private $repository;

    public function __construct(Repository $repository)
    {
        $this->repository = $repository;
    }

    public function setFieldInEntity($field, $entity)
    {
        if ($anotherEntity = $this->repository->findByField($field)) {
            throw new DomainException("...");
    }

        $entity->setField($field);
    }
}

我明白,但在我看来,这是一种过分的行为。我需要一个单独的类(服务)来设置其他类(实体)的属性。我不明白的是,为什么实体不能直接与存储库对话?我知道我不应该用基础设施细节(例如mysql查询)污染实体,但是,如果基础设施隐藏在存储库良好的接口后面,那么我看不到实体与该接口对话有任何错误。服务也是如此,为什么实体在需要某个服务时不能直接调用它呢?存储库保存或重建AggregateRoot(VO和实体的集群,其中根类是实体)。AggregateRoot的目的是执行业务逻辑,保持其不变量。因此,如果设置一个字段,您需要两个实体,它们可能属于同一个AR,或者您可以使用获取这两个实体的DomainService,并使用业务逻辑来设置该字段。DDD取决于您的域,它通常用于复杂域。也许不同的方法,如us ActionRecord或TableGateway适合您的需要。