php - ddd - 与远程 API 的同步应该去哪里?

标签 php service domain-driven-design

为了让我的应用程序正常工作,我需要定期从外部服务(可以是 API 或简单的文本文件,但现在是 API)同步数据。

由于这需要同时创建/更新许多实体,因此我需要创建一个域服务。但是,我还需要创建一些包含远程 API 响应的 DTO,对吗?

这个逻辑应该去哪里?我是否应该具有以下目录结构:

Domain -
    Model - // my set of entities and repository interfaces are here
        ....
    Synchronization -
        RunSynchronizationService.php // domain service
Application
    Synchronization - 
        SynchronizeData.php // application service
        SynchronizationDataSourceInterface.php // used by application service
        MySpecificRemoteApiDataSource.php // this implements the interface above
        SynchronizationDataSourceResponse.php // this would be returned by each call of  SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Infrastructure -
    MyConcreteImplementationOfModelEntityRepository.php   

当我想同步数据时,我只需调用 Application\Synchronization\SynchronizeData 的同步方法,这将采用 SynchronizationDataSourceInterface 的具体实现,调用它的方法,并在将它们传输到 Domain\Model\之前验证返回的 SynchronizationDataSourceResponse 对象同步\运行同步服务?

或者我应该删除 RunSynchronizationService(域服务)并让应用程序服务(SynchronizeData.php)在同步过程的每一步创建/更新域实体?

最佳答案

通常,当出现外部服务接口(interface)应该存在于何处的问题时,我会尝试将其视为另一个存储库。我在这里选择的抽象级别将在很大程度上取决于谁将使用该服务(只是这个项目的域/应用层?其他项目?),如果服务有不同的版本/供应商,以及如何使用哪个服务是确定。

对于您的示例,我将假设此应用程序是唯一一个直接使用同步服务的应用程序。共享服务需要进一步隔离公共(public)端点(例如接口(interface)和输出对象),以避免将不必要的对象溢出到其他项目中。

但在这种情况下,为了将服务视为另一个存储库,我将为其放置接口(interface)以及域期望和在域中使用的标准输出。

“验证”的含义在您的描述中有点含糊,因此我将在此处尝试驳斥对此的不同看法。一项或全部可能适用。

如果验证要求您与域数据进行比较,它可能应该驻留在 RunSynchronizationService.php 中模块。该模块似乎负责获取同步数据并将其应用于您的域。

如果对从同步服务调用返回的数据进行验证,并且不需要直接访问域对象图,我会将验证放在接口(interface)的服务实现上,并将验证调用暴露在服务接口(interface)。要处理同步服务的多个版本(例如 VersionA、VersionB 等)的验证相同的情况,您可以使用继承和覆盖,或同步服务的通用辅助函数等。在我下面的示例中,我使用了继承。

您可能需要进行这两种验证。首先检查与域无关的同步数据问题(在已实现的类上),然后检查域中的业务规则(在 RunSynchronizationService 中)。但很可能这两个调用都发生在 RunSynchronizationService 中。因为您会在界面上公开同步数据验证调用。

应用层应该负责创建服务实例(MySpecificRemoteApiDataSource),并将其传递给RunSynchronizationService.php模块为 SynchronizationDataSourceInterface .如果有多个版本,应用层可能会负责选择哪个版本(可能来自配置),并使用工厂。

但这又高度依赖于该同步服务的范围。如果您有依赖它的外部项目,您可能需要服务层本身的工厂部分,以便其他每个项目都使用相同的选择方法进行操作。

Domain -
    Model - // my set of entities and repository interfaces are here
        ....
    Synchronization -
        RunSynchronizationService.php // domain service
        SynchronizationDataSourceInterface.php // used to define the contract associated with a sync service
        SynchronizationDataSourceResponse.php // this would be returned by each call of  SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Application -  
    Synchronization - 
        SynchronizeData.php // application service - Uses a factory or some means of determining which version to use and introduce the domain to the data point.

Infrastructure -
    MyConcreteImplementationOfModelEntityRepository.php  

Synchornization -
    VersionA -  
        MySpecificRemoteApiDataSource.php  // Implements SynchronizationDataSourceInterface.php, inherits from SyncApiDataSourceBase.php
    SyncApiDataSourceBase.php  // Common logic for sync goes here, such as validation.

关于php - ddd - 与远程 API 的同步应该去哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41824821/

相关文章:

PHP:链接方法调用

c++ - GetCurrentDirectory 并没有真正返回可执行文件的路径

domain-driven-design - DDD - 使用在整个系统中必须唯一的联系信息对用户进行建模

c# - DDD : Repository, 工作单元、ORM 和依赖项注入(inject)

c# - Windows 服务更改/删除注册表值

domain-driven-design - 领域驱动设计(DDD): Domain Model Granularity and Bounded Context

php - wordpress 循环查询以获取帖子 ID 和类别

php - 如何合并从mysql查询得到的多个数组,然后遍历新数组

php - 将视频从 Android 上传到 PHP 的代码

tomcat - 使用批处理删除/安装Windows服务