Php 将业务逻辑放在实体中

Php 将业务逻辑放在实体中,php,entity-framework,symfony,doctrine-orm,software-design,Php,Entity Framework,Symfony,Doctrine Orm,Software Design,我读过福勒关于“贫血领域模型”(链接:)的文章,我同意他的观点 我曾尝试创建一个应用程序,其中实体是简单的POPO,但通过这种方式,我有一个胖服务层,而将一些逻辑放入实体将是最简单的解决方案 所以我会有一个这样的架构: ^ | Twig | Controller | API | Service | Model | Entity 其中: 实体:将是简单的POPO,只是一包setter和getter 模型:将是用业务逻辑修饰的实体对象 服务:包含涉及多个实体的所有业务逻辑(这里我还将放置验证任务)

我读过福勒关于“贫血领域模型”(链接:)的文章,我同意他的观点

我曾尝试创建一个应用程序,其中实体是简单的POPO,但通过这种方式,我有一个胖服务层,而将一些逻辑放入实体将是最简单的解决方案

所以我会有一个这样的架构:

^
| Twig
| Controller | API
| Service
| Model
| Entity
其中:

实体:将是简单的POPO,只是一包setter和getter

模型:将是用业务逻辑修饰的实体对象

服务:包含涉及多个实体的所有业务逻辑(这里我还将放置验证任务),其作用类似于转换器实体->模型

控制器| API:只需将请求与服务匹配、参数转换和检查自动化

细枝:表示层

我的问题是如何将实体层隐藏到控制器,并且只对模型有效。 为了用业务逻辑装饰我的实体,我想构建一个使用存储库并装饰结果的服务(我找不到其他方法来实现)

所以,一个愚蠢的例子:

namespace ...\Entity\Article;
class Article {
    private $id;
    private $description;

    // getter and setter
}


namespace ...\Model\Article;
class Article {
    private $article; // all methods will be exposed in some way
    private $storeService; // all required services will be injected

    public function __construct($article, $storeService) {
       $this->article = $article;
       $this->storeService = $storeService;
    }

    public function getEntity() {
       return $this->article;
    }

    public function isAvailable() {
       return $storeService->checkAvailability($this->article);
    }

    ...
}


class ArticleService {
    private $storeService; // DI
    private $em; // DI
    private $repository; // Repository of entity class Article

    public function findById($id) {
       $article = $this->repository->findById($id);
       return new \Model\Article($article, $storeService);
    }

    public function save(\Model\Article $article) {
       $this->em->persist($article->getEntity());
    }
    ...
}
上层是用通常的方法制作的。 我知道这不是一个好的解决方案,但我找不到更好的方法来拥有一个模型层。我真的不喜欢这样的东西:

$articleService->isAvailable($article);
而不是一个更加面向对象的:

$article->isAvailable();

我让DoctrineEntity对象扩展DomainModel对象。虽然控制器实际上可能接收doctrineetities,但它们只在DomainModelInterface上操作

... namespace DomainModel;
interface ArticleDomainModelInterface ...
interface ArticleDomainModelRepositoryInterface ... // create, find, save, commit
class ArticleDomainModel implements ArticleDomainModelInterface

... namespace Doctrine;
class ArticleDoctrineEntity extends ArticleDomainModel
class ArticleDoctrineRepository implements ArticleDomainModelRepositoryInterface

... namespace Memory;
// Usually dont need a memory article object
class ArticleMemoryRepository implements ArticleDomainModelRepositoryInterface
所有模型的创建和持久化都是通过存储库完成的。控制器和其他相关服务只知道ArticleDomainModel方法。这为您提供了一个很好的分离,并允许使用不同的存储库进行测试或支持不同的持久性机制。它还允许在域模型中使用值对象,同时仍然使用原则2来保持它们

然而,在php中,我确实很难理解到底什么样的有用业务逻辑可以放在域模型对象本身中。我倾向于在服务中使用大部分逻辑。这是因为我的大多数php应用程序都非常面向crud

还有一个问题:控制器本身是否应该访问域模型对象

条令2的主要开发者之一本杰明·埃伯莱(Benjamin Eberley)在这个主题上发表了许多博客文章。他的所有文章都值得细读。以下是一些:


我对答案也很感兴趣。为了执行业务逻辑,您的模型是否支持容器(能够调用服务)?或者仅仅局限于他们自己?你们是如何解决这个问题的?看看生成层的软件工厂。最重要的元素是实体关系模型,一个Python生成器模块可以在1天内编写完成。