Php Doctrine2:实体和单表继承映射的有界上下文。我有点困惑,我做得对吗

Php Doctrine2:实体和单表继承映射的有界上下文。我有点困惑,我做得对吗,php,doctrine,domain-driven-design,bounded-contexts,Php,Doctrine,Domain Driven Design,Bounded Contexts,长话短说 我使用Doctrine的单表继承映射来映射一个公共实体的三个不同上下文(类):NotActivatedCustomer、DeletedCustomer和Customer。此外,还有一个AbstractCustomer,其中包含以下内容: App\Identity\Domain\Customer\AbstractCustomer: 类型:实体 inheritanceType:单表 鉴别器列: 姓名:discr 类型:字符串 歧视地图: 客户:App\Identity\Domain\Cus

长话短说

我使用Doctrine的单表继承映射来映射一个公共实体的三个不同上下文(类):NotActivatedCustomerDeletedCustomerCustomer。此外,还有一个AbstractCustomer,其中包含以下内容:

App\Identity\Domain\Customer\AbstractCustomer:
类型:实体
inheritanceType:单表
鉴别器列:
姓名:discr
类型:字符串
歧视地图:
客户:App\Identity\Domain\Customer\Customer
NotActivatedCustomer:App\Identity\Domain\Customer\NotActivatedCustomer
DeletedCustomer:App\Identity\Domain\Customer\DeletedCustomer
表:客户
身份证件:
身份证件:
类型:客户识别码
独一无二:真的
发电机:
策略:定制
自定义IDGenerator:
类别:Symfony\Bridge\Doctrine\IdGenerator\UuidV4Generator
领域:
电邮:
类型:电子邮件
长度:180
独一无二:真的
子类型定义示例:


我认为你想避免客户变成上帝的对象是绝对正确的。继承是一种方法,但对处于不同状态的客户使用它可能会导致问题

在我的经历中,有两个关键问题:

  • 随着新状态的出现,您会继续添加不同的继承实体吗
  • 当客户处于两种不同的状态时会发生什么情况,例如,一个客户是
    未激活的客户
    ,但现在是
    删除的客户
  • 因此,我只在继承的类型真正是更特定的类型时才保留继承,其中给定的实体在其整个生命周期中将仅是这些类型中的一种。例如,汽车不会变成摩托车

    我有两种不同的模式来解决这个问题。我倾向于从第一个开始,然后转到第二个

    interface DeletedCustomer
    {
      public function getDeletedAt(): DateTime;
    }
    
    interface NotActivatedCustomer
    {
      public function getCreatedAt(): DateTime;
    }
    
    class Customer implements DeletedCustomer, NotActivatedCustomer
    {
      private $id;
      private $name;
      private DateTime $deletedAt;
      private bool $isActivated = false;
    
      public function getDeletedAt(): DateTime {...}
      public function getCreatedAt(): DateTime {...}
    }
    
    class DeletedCustomerRepository
    {
      public function findAll(): array
      {
        return $this->createQuery(<<<DQL
          SELECT customer 
          FROM   Customer 
          WHERE  customer.deletedAt IS NOT NULL
        >>>)->getQuery()->getResults();
      }
    }
    
    class NotActivatedCustomerRepository
    {
      public function findAll(): array
      {
        return $this->createQuery(<<<DQL
          SELECT customer 
          FROM   Customer 
          WHERE  customer.isActivated = false
        >>>)->getQuery()->getResults();
      }
    }
    
    class DeletedCustomerService
    {
      public function doTheThing(DeletedCustomer $customer) {}
    }
    
    
    接口删除客户
    {
    公共函数getDeletedAt():DateTime;
    }
    接口NotActivatedCustomer
    {
    公共函数getCreatedAt():DateTime;
    }
    类Customer实现DeletedCustomer,而不是ActivatedCustomer
    {
    私人$id;
    私人$name;
    私有日期时间$deletedAt;
    私有bool$isActivated=false;
    公共函数getDeletedAt():日期时间{…}
    公共函数getCreatedAt():日期时间{…}
    }
    类DeletedCustomerRepository
    {
    公共函数findAll():数组
    {
    返回$this->createQuery()->getQuery()->getResults();
    }
    }
    类NotActivatedCustomerRepository
    {
    公共函数findAll():数组
    {
    返回$this->createQuery()->getQuery()->getResults();
    }
    }
    类DeletedCustomerService
    {
    公共函数doTheThing(DeletedCustomer$customer){}
    }
    
    这减少了耦合,这是上帝对象的主要问题之一。因此,当这些列开始大量增加时,我可以将它们转移到加入
    客户
    的真实实体。引用
    DeletedCustomer
    的组件仍将收到一个

    第二种模式是事件源lite—与“CustomerLifeCycleeEvent”实体具有多对一关系。根据客户是否有“已删除”事件进行查询。第二种方法要复杂得多,包括更新和查询。您仍然可以拥有返回实体的专用存储库,如
    DeletedCustomer
    ,但您需要做更多的样板