Throw exceptions in repositories

Here's why you should consider throwing exceptions in your repositories.

99% of the time you're going to want to bail if you're expecting to find an entity by a specific key. Having code like the two private methods in the old code below in every single one of your handlers is crazy and not DRY.

I think the idea of "only throw exceptions when something exceptional happens" is too generic and doesn't take context into consideration.

A repository's only job is to find entities. If you give it a key and it can't find it, i think that's exceptional(in the context of the repository).

If it actually is expected in your client code it's not a big deal, catch the EntityNotFoundException and carry on.

This also unifies the types of exceptions thrown. It is entirely possible some handlers could be throwing a EntityNotFoundException while your partner developer is throwing a ValidationException. Encapsulate that in the repository.

class AddPersonCommandHandler
{
    private $categories;

    private $people;

    public function __construct(CategoryRepsoitory $categories, PersonRepository $people)
    {
        $this->categories = $categories;
        $this->people = $people;
    }

    public function handle(AddPersonCommand $command)
    {
        $category = $this->findCategory($command->getCategoryId()));
        $referrer = $this->findPerson($command->getReferrerId());

        $person = new Person(
            $command->getName(),
            $category,
            $referrer
        );

        $this->people->add($person);
    }

    private function findCategory($id)
    {
        if (null === $category = $this->categories->find($id)) {
            throw new EntityNotFoundException("Cateogry not found.");
        }

        return $category;
    }

    private function findPerson($id)
    {
        if (null === $person = $this->people->find($id)) {
            throw new EntityNotFoundException("Person not found.");
        }

        return $person;     
    }
}

Becomes:

class AddPersonCommandHandler
{
    private $categories;

    private $people;

    public function __construct(CategoryRepsoitory $categories, PersonRepository $people)
    {
        $this->categories = $categories;
        $this->people = $people;
    }

    public function handle(AddPersonCommand $command)
    {
        $category = $this->categories->find($command->getCategoryId());
        $referrer = $this->people->find($command->getReferrerId());

        $person = new Person(
            $command->getName(),
            $category,
            $referrer
        );

        $this->people->add($person);
    }
}

Tags: PHP