到目前为止,我认为存储库是“食谱书”,我将几乎每个查询都放在我的模型中。
例如:
Model -> Post
Repo -> PostRepository with Post injected via DI
Method -> find() uses $this->post->find
到目前为止,这对于减少重复并帮助进行单元测试非常有用。
但后来遇到了我需要另一个存储库中的存储库的情况。 然后我需要另一个存储库中的第一个存储库。 我在彼此的构造函数中注入了这两个。
我的测试会失败并会引发限制耗尽错误。无限注射是问题。
经过一番思考后,我想出了3个可能的解决方案:
1)仅在方法中注入Repos。这将解决我的实际问题,但我必须特别小心,我从不注入相同的回购并回到案例1.我讨厌这个选项。
2)存储库应该是概念,而不是模型。如果我需要另一个存储库,也许它们共享相同的概念,并且应该提取到另一个存储库。 这不会永远解决问题,因为我觉得如果应用程序增长,我将不得不在另一个存储库中注入其中一个存储库。 我对这个选项有点“好”。
3)我需要另一种类型/级别的课程。只能在最低级别查询模型的人。这些将以任何方式由任何存储库使用,并且永远不会导致任何问题。这也有助于避免因问题导致的错误1)。我最喜欢这个选项。
我觉得最好的解决方案可能是上面所有内容的混合,但我现在有点迷失了。 这显然都在Laravel环境中,尽管我觉得这比框架甚至语言层次更抽象。
感谢。
编辑:
正如在评论中提到的那样,这是一个代码的简单示例,我需要在另一个回购中查询:
class PostRepository {
private $post;
private $commentRepository;
public function __construct(Post $post, CommentRepository $commentRepository) {
$this->post = $post;
$this->commentRepository = $commentRepository;
}
public function hasComments($post) {
return $this->commentRepository->countCommentsForPost($post->id) > 0;
}
public function exists($post) {
// ...
}
}
class CommentRepository {
private $comment;
private $postRepository;
public function __construct(Comment $comment, PostRepository $postRepository) {
$this->comment = $comment;
$this->postRepository = $postRepository;
}
public function create($content, $post) {
if ($this->postRepository->exists($post)) {
return $this->comment->create(['content' => $content, 'post_id' => $post->id]);
}
}
public function countCommentsForPost($post) {
// ...
}
}
这是一个非常简单(而不是太聪明)的例子,你可以说Post模型应该有一个“评论”关系,但我仍然觉得这种逻辑在这里是错误的,我不知道比如把它放在控制器里。该代码只会通过“自动”DI获得无限循环。
答案 0 :(得分:1)
据我所知,存储库通常用于其他所有存储库。或者,我从未真正想过你需要这样一个例子的例子。
您所描述的内容可能是一个服务类,可能会通过构造函数注入一些存储库。
哦,我读到的关于存储库的最后一件事给了我一个有趣的想法,即只读存储库只是查询数据库的结果,但他们不保存/创建/更新/删除东西。由于复杂性,这些方法留在模型中。
以下是我读过这篇文章的帖子: http://adamwathan.me/2015/02/14/active-repository-is-an-antipattern/
哦,通过单元测试存储库,你的意思是集成测试吗?因为为已经测试的东西编写单元测试可能不是最好的主意。 (谈论Eloquent)更新: 我刚看到你的更新,似乎你需要Comment模型,而不是整个存储库。并且存储库应该尽可能短,通常一个返回语句没有任何ifs,但我从来没有遇到过这样的情况,所以我不确定检查那些东西是否是最好的主意。
也许在其他地方检查if,如果它通过则运行查询?
此外,对于某些查询,使用关系可能会对您有所帮助。
答案 1 :(得分:1)
简单的答案是,尽管您可以将DI存储库类转换为其他存储库类,但您不能像在此编码那样使用循环DI。为您解析DI的laravel容器类将调用获取DI的每个类的构造函数。因此,您需要做的是整理您的依赖关系层次结构,例如将一些常用功能移到一个依赖关系层。