存储库查询条件、依赖项和 DRY


Repository query conditions, dependencies and DRY

为了简单起见,让我们假设一个具有AccountsUsers的应用程序。每个帐户可以有任意数量的用户。还有 3 个消费者UserRepository

  • 可以列出所有用户的管理界面
  • 公共前端,可以列出所有用户
  • 经过帐户身份验证的 API,应仅列出自己的用户

假设UserRepository是这样的:

class UsersRepository extends DatabaseAbstraction {
    private function query() {
        return $this->database()->select('users.*');
    }
    public function getAll() {
        return $this->query()->exec();
    }
    // IMPORTANT:
    // Tons of other methods for searching, filtering,
    // joining of other tables, ordering and such...
}

牢记上面的评论,以及抽象用户查询条件的必要性,我应该如何处理按account_id过滤的用户的查询?我可以想象三条可能的道路:

1. 我应该创建一个AccountUsersRepository吗?

class AccountUsersRepository extends UserRepository {
    public function __construct(Account $account) {
        $this->account = $account;
    }
    private function query() {
        return parent::query()
            ->where('account_id', '=', $this->account->id);
    }
}

这具有减少UsersRepository方法重复的优点,但不太适合我到目前为止读到的有关DDD的任何内容(顺便说一下,我是新手)

2. 我应该把它作为一种方法放在AccountsRepository上吗?

class AccountsRepository extends DatabaseAbstraction {
    public function getAccountUsers(Account $account) {
        return $this->database()
            ->select('users.*')
            ->where('account_id', '=', $account->id)
            ->exec();
    }
}

这需要复制所有UserRepository方法,并且可能需要另一个UserQuery层,以可链接的方式实现这些查询逻辑。

3. 我应该从我的账户实体内查询UserRepository吗?

class Account extends Entity {
    public function getUsers() {
        return UserRepository::findByAccountId($this->id);
    }
}

这对我来说更像是一个聚合根,但引入了UserRepositoryAccount实体的依赖,这可能会违反一些原则。

4.还是我完全错过了重点?

也许有更好的解决方案?


脚注:除了权限是一个服务问题之外,在我的理解中,他们不应该实现SQL查询,而是将其留给存储库,因为这些存储库甚至可能不是SQL驱动的。

获取属于某个帐户的所有用户更像是一个 UI 问题。我的建议是使用你的MVC控制器(如AccountAdminController?)直接调用UserRepository.findByAccountId()。

我认为聚合应该只由它自己的存储库返回。