Question

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.

Was it helpful?

Solution

Fetching all users belonging to an account is more of an UI concern. My suggestion is use your MVC controller(like AccountAdminController?) invoke the UserRepository.findByAccountId() directly.

I think Aggregates should be returned only by its own repository.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top