fusonic / ddd-extensions

用于与 Doctrine ORM 一起使用的 Symfony 领域驱动设计构建块。

2.0.0 2024-09-09 07:51 UTC

This package is auto-updated.

Last update: 2024-09-09 07:53:30 UTC


README

License Latest Version Total Downloads php 8.2+

关于

此库为在 PHP 中实现领域驱动设计提供了一些基类。提供了用于与 Symfony 和 Doctrine 一起使用的有用工具,但您不必使用这些工具。

安装

使用 composer 从 Packagist 安装库。

composer require fusonic/ddd-extensions

配置

services:
    # This service dispatches the domain events raised on aggregate roots to the given message bus.
    Fusonic\DDDExtensions\Doctrine\LifecycleListener\DomainEventLifecycleListener:
        arguments:
            $bus: '@Symfony\Component\Messenger\MessageBusInterface'
        tags:
            # Note: The listener has to be tagged individually for each event
            - { name: doctrine.event_listener, event: 'postPersist', priority: 500 }
            - { name: doctrine.event_listener, event: 'postUpdate', priority: 500 }
            - { name: doctrine.event_listener, event: 'postRemove', priority: 500 }
            - { name: doctrine.event_listener, event: 'postFlush', priority: 500 }

    # Optionally configure a ModelDescriber if you are using NelmioApiDocBundle to display EntityId objects in the 
    # generated documentation
    Fusonic\DDDExtensions\ModelDescriber\EntityIdDescriber:
        tags:
            - { name: nelmio_api_doc.model_describer, priority: 1000 }
    
    # Optionally configure a normalizer to automatically serialize/deserialize AbstractIntegerId objects
    Fusonic\DDDExtensions\Normalizer\EntityIdNormalizer:
        tags:
            - { name: serializer.normalizer }

使用和建议

例如,请参阅 测试中的示例

值对象

值对象必须扩展 Fusonic\DDDExtensions\Domain\Model\ValueObject。值对象必须是不可变的。所有需要的属性必须在初始化对象时设置。值对象不能有任何设置器属性。

比较值对象时,必须实现 equals 函数。

聚合根

聚合根是边界上下文的 入口点。扩展 Fusonic\DDDExtensions\Domain\Model\AggregateRoot 的领域对象是聚合根。只有聚合根可以直接在边界上下文之外创建/修改。所有子实体都通过聚合根进行修改/创建。

领域实体

领域实体必须实现 Fusonic\DDDExtensions\Domain\Model\EntityInterface

您不应该直接对领域实体(不是聚合根)进行操作。所有操作都应通过聚合根进行。

getId() 返回的 "id" 可以返回任何内容,但建议为每个领域实体创建一个专门的 "id" 类。例如,一个具有 UserId 类的 User 类。扩展 EntityId 的类必须实现一个 __toString 方法和一个 getValue() 方法,该方法将返回内部值。内部值的实现取决于您。对于 Doctrine,您可以使用整数并使用 Fusonic\DDDExtensions\Domain\Model\EntityIntegerId 类作为基类,请参阅 此示例

为了保持一致的返回类型并避免在所有地方进行空值检查,您不能返回 null。如果您使用 AbstractIntegerId 基类,默认内部值将是 0。为了检查这一点,实现了方便的 isDefined() 方法。

public function getId(): UserId
{
    return new UserId($this->id);
}

断言

领域层不依赖于任何验证服务。验证逻辑必须在模型内部。对于领域中的断言,有一个静态辅助类,其中包含常用的断言函数。请参阅: Fusonic\DDDExtensions\Domain\Validation\Assert

领域异常

领域异常只能从领域内部抛出。所有领域异常都必须实现 Fusonic\DDDExtensions\Domain\Exception\DomainExcetionInterface

领域事件

扩展 Fusonic\DomainDrivenDoctrin\Domain\Model\AggregateRoot 的领域对象可以引发事件。在类内部,您可以调用 $this->raise(...) 并传递一个实现 Fusonic\DDDExtensions\Domain\Event\DomainEventInterface 的事件。

所有引发的事件将在 Doctrine flush 被调用时分发。 Fusonic\DDDExtensions\Doctrine\LifecycleListener\DomainEventLifecycleListener 处理此操作。

ORM 映射

您不能使用PHP注解或属性来定义您的ORM映射。映射应该配置在领域之外。对于Doctrine,您可以使用XML或PHP映射。

作为嵌入对象的值对象

可以使用Doctrine嵌入对象来实现值对象映射,但仅限于一对一关系。嵌入对象的优势在于,您可以使用Doctrine查询语言轻松查询字段。

作为JSON的值对象

另一种映射值对象的方法是定义自定义的Doctrine类型。扩展Fusonic\DDDExtensions\Doctrine\Type\ValueObjectType并实现convertToDatabaseValueconvertToPHPValue方法来定义值对象的映射。该类提供了四个辅助方法用于序列化:serializedeserializeserializeArraydeserializeArray,如果您想存储值对象的数组(一对多关系)。示例请参考这里这里。在数据库中,对象将以json格式存储。

实现自定义类型后,您需要注册它

在Doctrine中,无法直接查询JSON数据,但可以通过扩展实现(示例)。