【发布时间】:2016-03-18 20:33:54
【问题描述】:
到目前为止,我将存储库视为“食谱书”,我会将模型中的几乎所有查询都放在其中。
例如:
Model -> Post
Repo -> PostRepository with Post injected via DI
Method -> find() uses $this->post->find
到目前为止,这对于减少重复和单元测试很有帮助。
但后来我遇到了一个需要在另一个存储库中的存储库的情况。 然后我需要另一个存储库中的第一个存储库。 我将这两个注入到彼此的构造函数中。
我的测试会失败并且会抛出一个限制耗尽错误。无限注入是个问题。
经过一番思考,我想出了 3 个潜在的解决方案:
1) 仅在方法中注入 Repos。这将解决我的实际问题,但我必须格外小心,我永远不会注入相同的 repo 并返回案例 1。我讨厌这个选项。
2) 存储库应该是关于概念的,而不是关于模型的。如果我需要另一个存储库,也许它们共享相同的概念,应该将其提取到另一个存储库。 这不会永远解决问题,因为我觉得如果应用程序增长,我必须在某个时候将其中一个存储库注入另一个存储库。 我对这个选项有点“好”。
3) 我需要另一种类型/级别的课程。仅在模型的最低级别上查询的一种。这些将被任何存储库以任何需要的方式使用,这绝不会导致任何问题。这也有助于不犯由问题 1) 引起的错误。我最喜欢这个选项。
我觉得最好的解决方案可能是上述所有内容的混合,但我现在有点迷失了。 这显然都是在 Laravel 环境中,尽管我觉得这比框架甚至语言级别更抽象。
谢谢。
编辑:
正如评论中所问的,这是一个简单的代码示例,我需要在另一个 repo 中进行查询:
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 模型应该具有“cmets”关系,但我仍然觉得这种逻辑在这里是错误的,我不认为就像把它放在控制器中一样。该代码只会获得带有“自动”DI 的无限循环。
【问题讨论】:
-
您能否添加一个(简化的)示例,说明何时需要访问另一个存储库?在 Symfony 术语(它使用存储库来存储数据库)中,您所描述的内容听起来像是一项服务
-
为什么要将commentRepository 注入PostRepository。您可以将 Comment 模型(甚至违反单一职责原则)注入 PostRepository。您可以创建 PostCommentRepository,而不是我认为这将是理想的..
-
我想过这样做,但我只是在这里创建一个评论。逻辑(如果)涉及 postRepository 但我觉得这里涉及的主要概念是 Comment 模型。这是否也意味着我需要一个新的存储库时我需要另一个存储库?我同意这违反了 SRP。即使是这里的简单 if 语句也违反了它。
标签: php laravel dependency-injection repository-pattern