Repository query conditions, dependencies and DRY

Posted by vFragosop on Programmers See other posts from Programmers or by vFragosop
Published on 2013-10-24T02:47:34Z Indexed on 2013/10/24 4:07 UTC
Read the original article Hit count: 189

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.

© Programmers or respective owner

Related posts about php

Related posts about domain-driven-design