注入Doctrine实体管理器到服务中 - 是一种不好的做法吗?

7

使用https://insight.sensiolabs.com来扫描/检查我的代码时,我收到以下警告:

Doctrine Entity Manager不应作为参数传递。

为什么在服务中注入Entity Manager是不好的实践?有什么解决方案吗?


看看它是否抱怨注入Doctrine实体存储库。与管理器相比,存储库的“范围”有点更窄,因此通常最好注入存储库。更容易模拟和测试等。 - Cerad
1
仓库没有问题,但是不能使用仓库将实体持久化到数据库中。 - Machiel
2个回答

7

关于不能将实体持久化到存储库的评论。

class MyRepository extends EntityRepository
{
    public function persist($entity) { return $this->_em->persist($entity); }
    public function flush  ()        { return $this->_em->flush  (); }

我喜欢让我的存储库遵循一个“标准”的存储库接口。因此,我会:

interface NyRepositoryInterface
[
    function save($entity);
    function commit();
}
class MyRepository extends EntityRepository implements MyRepositoryInterface
{
    public function save  ($entity) { return $this->_em->persist($entity); }
    public function commit()        { return $this->_em->flush  (); }

这使我能够定义和注入非doctrine仓库。
您可能反对必须将这些辅助函数添加到每个仓库中。但我认为稍微复制/粘贴一下是值得的。Traits也可能有所帮助。
这个想法是移动远离实体管理器的整个概念。

似乎是一个很好的解决方案,只是好奇其他开发者是否有另外的方法。 - Machiel
2
这非常有用,谢谢。只是一个小的修正:方法persist和flush是void类型的,不返回任何内容。 - iarroyo

3

我目前正在处理一个相当大的项目,并最近开始采用可以改变数据的存储库方法。我真的不明白为什么必须将EntityManager注入为依赖项,这与向任何类注入ServiceManager一样糟糕。这只是人们试图证明的糟糕设计。像持久化、删除和刷新等操作可以抽象成像AbstractMutableRepository这样的东西,每个其他存储库都可以继承它。到目前为止,它一直表现得很好,使代码更易读和易于单元测试!

请给我展示至少一个服务,其中EM已经被注入,并且它的单元测试看起来正确?能够对具有EM注入的内容进行单元测试更多地涉及测试实现而不是其他任何内容。然后会出现这种情况:你需要设置很多模拟,以至于你无法真正称之为良好的单元测试!它只是代码覆盖率的提高者,仅此而已!


这似乎并没有回答问题。 - ntzm
确实是这样的 :) 请仔细阅读。 为什么在服务中注入EntityManager是如此糟糕的做法? 因为EntityManager在数据库世界中类似于ServiceManager。它可以做任何事情,而您不应该使您的类依赖于整个世界,因为您无法真正地进行单元测试。 - user3647324
2
Doctrine2的作者提出的模式,即仅为了从中获取我们的存储库而注入EntityManager,这是一个不好的想法。为什么?使用Entity Manager可以以几种方式完成A事情。它是许多职责的大怪物,无法以任何合理的方式进行存根或模拟。因此,我们有Repository(模式)来减少范围并清楚地说明依赖关系。将世界注入到任何地方都会使组件不太可移植,更加脆弱,更难进行单元测试和推理。 - user3647324

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接