Doctrine2最佳实践,实体应该使用服务吗?

时间:2010-12-16 20:49:22

标签: datamapper doctrine-orm service-layer

前一段时间我问了一个类似的问题:Using the Data Mapper Pattern, Should the Entities (Domain Objects) know about the Mapper?但是,它是通用的,我真的很感兴趣如何用Doctrine2专门完成一些事情

以下是一个简单的示例模型:每个Thing可以来自Vote UserUser可以投放多个Vote但只有Vote最后Msssage计数。由于其他数据(Vote等)与Vote相关,因此在放置第二个Vote时,原始Thing无法更新,因此需要替换。

目前public function addVote($vote) { $vote->entity = $this; } 具有此功能:

Vote

public function setThing(Model_Thing $thing) { $this->thing = $thing; $thing->votes[] = $this; } 负责建立关系:

User

在我看来,确保Vote仅计算最后Thing Thing应该确保的内容,not some service layer

所以要在模型中保留新的public function addVote($vote) { foreach($this->votes as $v){ if($v->user === $vote->user){ //remove vote } } $vote->entity = $this; } 函数:

Vote

那么如何从域模型中删除Vote::setThing()我应该放松NULL接受Thing吗?我是否应该使用foreach可用于删除投票的某种服务层?一旦投票开始累积,Thing将会变慢 - 如果使用服务层允许Vote搜索{{1}}而无需加载整个集合吗?

我绝对倾向于使用轻型服务层;但是,是否有更好的方法来处理Doctrine2的这类事情,或者我是朝着正确的方向前进?

2 个答案:

答案 0 :(得分:7)

我投票支持服务层。我经常努力尝试在实体本身添加尽可能多的逻辑,并且只是让自己感到沮丧。无法访问EntityManager,您根本无法执行查询逻辑,当您只需要几条记录时,您会发现自己使用了大量的O(n)操作或延迟加载整个关系集(这是超级的与DQL提供的所有优势相比,我感到茫然。

如果您需要一些帮助来克服贫血领域模型始终是反模式的想法,请参阅Matthew Weier O'Phinney的this presentationthis question

虽然我可能误解了术语,但我并不完全相信实体必须是域模型中允许的唯一对象。我很容易认为实体对象及其服务的总和构成了模型。我认为,当您最终编写一个几乎不关注关注点分离的服务层时,就会出现反模式。

我经常想到让所有实体对象将一些方法代理到服务层:

public function addVote($vote)
{
   $this->_service->addVoteToThing($vote, $thing);
}

然而,由于Doctrine没有任何类型的对象水合回调事件系统,我还没有找到一种优雅的方式来注入服务对象。

答案 1 :(得分:6)

我的建议是将所有查询逻辑放入EntityRepository,然后从中创建一个类似的接口:

class BlogPostRepository extends EntityRepository implements IBlogPostRepository {}

通过这种方式,您可以在服务对象的单元测试中使用接口,并且不需要依赖EntityManager。