Repository query conditions, dependencies and DRY
- by vFragosop
To keep it simple, let's suppose an application which has Accounts and Users. Each account may have any number of users. There's also 3 consumers of UserRepository:
An admin interface which may list all users
Public front-end which may list all users
An account authenticated API which should only list it's own users
Assuming UserRepository is something like this:
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...
}
Keeping in mind the comment above, and the necessity to abstract user querying conditions, How should I handle querying of users filtering by account_id? I can picture three possible roads:
1. Should I create an 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);
}
}
This has the advantage of reducing the duplication of UsersRepository methods, but doesn't quite fit into anything I've read about DDD so far (I'm rookie by the way)
2. Should I put it as a method on AccountsRepository?
class AccountsRepository extends DatabaseAbstraction {
public function getAccountUsers(Account $account) {
return $this->database()
->select('users.*')
->where('account_id', '=', $account->id)
->exec();
}
}
This requires the duplication of all UserRepository methods and may need another UserQuery layer, that implements those querying logic on chainable way.
3. Should I query UserRepository from within my account entity?
class Account extends Entity {
public function getUsers() {
return UserRepository::findByAccountId($this->id);
}
}
This feels more like an aggregate root for me, but introduces dependency of UserRepository on Account entity, which may violate a few principles.
4. Or am I missing the point completely?
Maybe there's an even better solution?
Footnotes: Besides permissions being a Service concern, in my understanding, they shouldn't implement SQL query but leave that to repositories since those may not even be SQL driven.