【问题标题】:Doctrine2 Best Practice, Should Entities use Services?Doctrine2 最佳实践,实体应该使用服务吗?
【发布时间】:2011-05-26 19:11:57
【问题描述】:

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

这是一个简单的示例模型:每个Thing 可以从User 中获得一个Vote,一个User 可以转换多个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 只计算最后一个 VoteThingnot some service layer 应该确保的。

为了将其保留在模型中,新的Thing 函数:

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 而无需加载整个集合?

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

【问题讨论】:

    标签: datamapper doctrine-orm service-layer


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 我将检查链接 - 我同意服务层可以(应该)被视为模型的一部分。我认为 Fowler 在他的贫血领域模型帖子中也说了同样的话)。虽然我(目前)赞成让实体处理内部添加投票,但我会代理服务层以查找/删除投票 - 而不是通过集合进行疯狂搜索。我想问题是 - 如何注入服务对象。也许像$em->getRepository() 这样的静态函数?
    • 有机会浏览该演示文稿 - 非常好的信息。让我想起了一些 Zend Framework 架构(这并不奇怪)。仍在处理更重的服务层如何影响单元测试的简易性。再次,很棒的链接。
    • 我对你的方法很感兴趣。我还在考虑将服务作为我的实体的属性,然后在实体本身(使用服务来处理持久性)上实现诸如“保存”之类的方法。这似乎有点 activeRecord(ish) 这就是为什么我没有这样做。是否可以使用服务对象但将实体 INTO 传入?
    • @kissmyface 你的实体只是一个数据容器,你不应该依赖它这种依赖。即使您使用某种类型的依赖注入,您最终也会拥有一个充满方法来操作数据的实体,并且经常重复其自己的服务类的方法。为什么您的实体中没有服务类别,而服务类别中没有他们的实体?
    【解决方案2】:

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

    class BlogPostRepository extends EntityRepository implements IBlogPostRepository {}
    

    这样您就可以在服务对象的单元测试中使用该接口,并且不需要依赖 EntityManager。

    【讨论】:

    • +1 想知道将存储库/服务层/等添加到方程式后的最佳测试方法。
    猜你喜欢
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    • 2012-06-01
    相关资源
    最近更新 更多