Symfony和域驱动设计

Don*_*joe 1 doctrine domain-driven-design symfony

在Symfony 3中,您如何根据域驱动设计(DDD)区分以下内容?

  • 服务(在配置服务文件中定义的服务)
  • 教义存储库(\ Doctrine \ ORM \ EntityRepository)
  • 实体(实体文件夹中的类)

我知道该学说与Symfony脱钩了(即可以完全省略)。但是,没有教义的Symfony项目中的存储库是哪一个呢?也许Symfony(没有教义)实际上不是真的遵循DDD吗?

编辑

我尝试模拟以下情况以使问题更清楚

控制器具有返回项目的所有可用经理的功能

class ManagementController
    public function getAvailableManagers(Array $project)
    {
        ...
    }
}    
Run Code Online (Sandbox Code Playgroud)

可用的经理意味着他们手头上没有任何项目,并且该项目属于其专业领域(例如,客户服务,业务关系,物流等)

但是,由于设计不佳,专用域未存储在数据库中,而是需要通过API调用被调用到单独的HR系统。稍后将其集成到数据库中

我本以为(随时可以纠正我)管理器应该是一个存储库类,因为它当前从2个不同的来源获取其信息。问题是……我应该为此使用教义存储库吗?还是应该只是普通实体或服务?

class ReplacementInstructionRepository extends \Doctrine\ORM\EntityRepository
{
    private $id;
    private $name;
    private $speciality;
    private $projects;
}
Run Code Online (Sandbox Code Playgroud)

我需要有关如何拆分的指南。谢谢

干杯,

mgo*_*ile 5

尽管我对这个问题不太了解,但是这里有一些使用Symfony应用DDD原理的项目的示例。

https://github.com/PhpFriendsOfDdd/state-of-the-union/blob/master/README.md

编辑

经过您的最后描述,我想我可以给出更好的答案:-)。

我想说的是,规范模式非常适合您的情况。规范模式允许您将业务规则保留在“域”层中。在这种情况下,您提到了一条重要的业务规则:

可用的经理意味着他们手头上没有任何项目,并且该项目属于其专业领域(例如,客户服务,业务关系,物流等)

在这种情况下,您提到了我们需要处理的不良设计。在未开发的项目中,我将管理器的专用域保存在管理器中,因此所有内容都将驻留在同一聚合根(即管理器)中。

在您的情况下,我将通过存储库集成外部方(HR系统),如下所示:

nampespace xxx\infrastructure\persistence
class ManagersRepository
{
    public function __construct(HrApiClient $apiClient)
    {
        $this->apliClient = $apiClient;
    }

    public function findWithoutProjects()
    {
        $sqlQuery = //find all managers without project
        $managers = $this->execute($sqlQuery);
        foreach ($managers as $manager) {
            $projects = $this->apliClient->findProjectsOfManagerId($manager->id());
            $manager->specialisedIn($projects); //This should be done with reflection
        }

        return $managers;
    }

    public function selectSatisfying(Specification $specification)
    {
        return $specification->satisfyingElementsFrom($this);
    }
}

namespace xxx\Domain
class ManagersAvailableSpecification implements Specification
{
    public function __construct($aNewProject)
    {
        $this->aNewProject = $aNewProject;
    }

    public function isSatisfiedBy($manager)
    {
        // business rules here...
        if ($manager->isSpecialisedIn($this->aNewProject)) {
            return true;
        }

        return false;
    }

    public function satisfyingElementsFrom(ManagersRepository $managersRepository)
    {
        $managers = $managersRepository->findWithoutProjects();

        return array_filter(
            $managers,
            function (Manager $manager) {
                return $this->isSatisfiedBy($manager);
            }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,第一类是存储库的具体实现(使用MySql,Postgre等),位于基础结构层中。尽管第二个仅取决于接口,但它与定义可用管理器的业务规则一起存在于域中。

现在您可以拥有类似的服务:

class FindAvailableManagersService
{
    private $managersRepository;

    public function __construct(ManagersRepository $managersRepository)
    {
        $this->managersRepository = $managersRepository;
    }

    public function execute(FindAvailableManagersRequest $request)
    {
        $managersAvailable = $this->managersRepository->selectSatisfying(
            new ManagersAvailableSpecification($request->project())
        );

        return $managersAvailable;
    }
}
Run Code Online (Sandbox Code Playgroud)

还要注意,如果将来您将专用域从第三方迁移到您自己的数据库,则只需修改一个类,而不会触及其他任何问题:-)