草庐IT

php - 将业务逻辑放在实体中

coder 2024-01-01 原文

我读过 Fowler 关于“贫血领域模型”的文章(链接:http://www.martinfowler.com/bliki/AnemicDomainModel.html),我同意他的观点。

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

所以我会有这样的架构:

^
| Twig
| Controller | API
| Service
| Model
| Entity

地点:

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

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

服务:包含涉及多个实体的所有业务逻辑(我也会在此处放置验证任务),并且充当转换器实体 -> 模型

Controller | API:只匹配请求与服务,ParamConvert和检查授权

Twig:表示层

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

所以,一个愚蠢的例子:

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 对象。虽然 Controller 实际上可能接收 DoctrineEntities,但它们仅在 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

所有模型的创建和持久化都是通过存储库完成的。 Controller 和其他相关服务只知道 ArticleDomainModel 方法。这为您提供了很好的分离,并允许使用不同的存储库进行测试或支持不同的持久性机制。它还允许在您的域模型中使用值对象,同时仍然使用 Doctrine 2 持久化它们。

但是,在 php 中,我确实在思考什么样的有用业务逻辑实际上可以放在域模型对象本身中。我倾向于以服务中的大部分逻辑结束。那是因为我的大多数 PHP 应用程序都是严重面向 crud 的。

还有一个问题: Controller 本身应该有权访问域模型对象吗?

Doctrine 2 的主要开发者之一,Benjamin Eberlei,有很多关于这个主题的博客文章。他的所有文章都值得详细阅读。这里有一些:

http://www.whitewashing.de/2013/07/24/doctrine_and_domainevents.html http://www.whitewashing.de/2012/08/22/building_an_object_model__no_setters_allowed.html http://www.whitewashing.de/2012/08/18/oop_business_applications__command_query_responsibility_seggregation.html

关于php - 将业务逻辑放在实体中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20018369/

有关php - 将业务逻辑放在实体中的更多相关文章

  1. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  2. Linux磁盘分区中物理卷(PV)、卷组(VG)、逻辑卷(LV)创建和(LVM)管理 - 2

    文章目录一基础定义二创建逻辑卷2-1准备物理设备2-2创建物理卷2-3创建卷组2-4创建逻辑卷2-5创建文件系统并挂载文件三扩展卷组和缩减卷组3-1准备物理设备3-2创建物理卷3-3扩展卷组3-4查看卷组的详细信息以验证3-5缩减卷组四扩展逻辑卷4-1检查卷组是否有可用的空间4-2扩展逻辑卷4-3扩展文件系统五删除逻辑卷5-1备份数据5-2卸载文件系统5-3删除逻辑卷5-4删除卷组5-5删除物理卷六LVM逻辑卷缩容6-1缩容注意事项6-2标准缩容步骤一基础定义LVM,LogicalVolumeManger,逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分

  3. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  4. ruby-on-rails - Ruby 和 SQL 中的重复业务逻辑 - 2

    我有一个PORO(普通旧Ruby对象)来处理一些业务逻辑。它接收一个ActiveRecord对象并对其进行分类。为了简单起见,以下面为例:classClassificatorSTATES={1=>"Positive",2=>"Neutral",3=>"Negative"}definitializer(item)@item=itemenddefnameSTATES.fetch(state_id)endprivatedefstate_idreturn1if@item.value>0return2if@item.value==0return3if@item.value但是,我还想根据这些st

  5. ruby - 了解 Ruby 中赋值和逻辑运算符的优先级 - 2

    在以下示例中,我无法理解Ruby运算符的优先级:x=1&&y=2由于&&的优先级高于=,我的理解是类似于+和*运算符:1+2*3+4解析为1+(2*3)+4它应该等于:x=(1&&y)=2但是,所有Ruby源代码(包括内部语法解析器Ripper)都将其解析为x=(1&&(y=2))为什么?编辑[08.01.2016]让我们关注一个子表达式:1&&y=2根据优先规则,我们应该尝试将其解析为:(1&&y)=2这没有意义,因为=需要特定的LHS(变量、常量、[]数组项等)。但是既然(1&&y)是一个正确的表达式,那么解析器应该如何处理呢?我试过咨询Ruby的parse.y,但它太像意大利面条

  6. Ruby每道逻辑题 - 2

    我正在尝试解决来自SevenLanguagesinSevenWeeks的一个简单的Ruby问题Printthecontentsofanarrayofsixteennumbers,fournumbersatatime,usingjusteach这是我想到的,可以用简单的方式完成还是改进它?a=(1..16).to_ai=0j=[]a.eachdo|item|i+=1j可以在一行中使用each_slicea.each_slice(4){|x|px} 最佳答案 Teja,你的解决方案没问题。由于您需要使用每一个,因此算法的复杂性将受限于数

  7. ruby-on-rails - 如果字段不为零,则葡萄实体有条件地公开 - 2

    在一个葡萄实体中,我只想在没有运气的情况下显示一个字段(不是零?)。我正在尝试这段代码,但根本没有按预期工作,但总是隐藏该字段。expose:winner,:using=>PlayerEntity,:unless=>{:winner=>nil}我认为代码本身解释了我真正需要的东西,但正如我所说,我没有得到预期的结果。有什么线索吗? 最佳答案 好的,检查grape-entity的代码我发现你需要将这个block作为RubyProc传递。此代码将按预期工作:expose:winner,:using=>PlayerEntity,:unle

  8. arrays - 给定一个大小为 y 的数组,其中包含大小为 n 的数组,我如何使用 Ruby 返回所有逻辑组合? - 2

    我想做的是处理n个集合,而我在下面提供的代码正好处理4个集合。defshow_combinations@combos=[]['A','noA'].eachdo|a|['B','noB'].eachdo|b|['C','noC'].eachdo|c|['D','noD'].eachdo|d|@combos我如何重构以下代码来处理以下场景:鉴于我有一个大小为y的数组,其中包含大小为n的数组,我想返回所有组合。请务必注意,每个子数组中只能有一个项目出现在结果中。(如“已完成资料”不能同时出现在“未完成资料”的结果中)背景:用户可能有一些任务:例如,“完成配置文件”或“设置电子邮件”或其他任何

  9. ruby - 如何从定义相同名称的模块内部访问ruby中的顶级实体 - 2

    在一个模块中,我有一个名为Process的类。moduleMProcess=Class.newProcess::wait(0)end这会引发NoMethodError。如何从模块内部访问顶级Process?如果不重命名我的类(class),这完全有可能吗? 最佳答案 ::Process.wait(0) 关于ruby-如何从定义相同名称的模块内部访问ruby中的顶级实体,我们在StackOverflow上找到一个类似的问题: https://stackoverf

  10. ruby-on-rails - 如何使用 searchkick 进行逻辑运算的复杂查询 - 2

    我正在使用searchkick库作为产品搜索的elasticsearch客户端。https://github.com/ankane/searchkick可以创建'OR'条件和'AND'条件;AND运算Product.search其中:{price:{lte:200},in_stock:true}或运算Product.search其中:{或:[[{in_stock:true},{backordered:true}]]}但我坚持使用searchkick创建多个“AND”“OR”条件。我需要类似的东西A或B或(C和D)或者我需要这样,A与B与(C或D)请指导我,如何实现这一目标谢谢

随机推荐