How to Simplify Development with the Repository Pattern

In a recent application I found that I was too bound to a database as the application’s data source and wanted to decouple from it as much as possible, whilst using the least amount of effort. During research into the required changes, I came across an excellent pattern which gives a lot of flexibility, yet which doesn’t require a lot of code - it’s called the repository pattern.


In a recent application I found that I was too bound to a database as the application’s data source. After a bit of discussion, I decided to change direction and decouple from it as much as possible, whilst using the least amount of effort.

During research into the required changes, I came across an excellent pattern which gives utmost flexibility, yet doesn’t require a lot of code - it’s called the repository pattern. If you’re not familiar with it the repository pattern:

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

That may not be the most legible of descriptions. So how about two others, starting with this one from SitePoint:

It is an implementation of a brokering layer between the application and a data source. Neither party needs to be be aware of the other to perform their respective jobs which allows us to have a decoupled architecture which in turn helps in the scaling of the application in the big leagues without having hard dependencies.

Then there’s this one from Shawn McCool:

A repository represents the concept of a storage collection for a specific type of entity.

My take on it, is that it’s a pattern which helps abstract the logic for managing a collection of a particular entity type, which is quite similar to how Doctrine works. When properly implemented, the calling code requires a class which implements a given interface. It doesn’t request a concrete implementation.

In effect, what we’re doing is properly using polymorphism; that is, programming to an interface, not an implementation.

Before I go too much further, there are differences of opinion on just how far, with respect to entity management, that the pattern should go. For example some, such as Shawn McCool, suggest that the repository pattern should not be responsible for creating new instances. But for the purposes of this article, I’m not going to get too concerned with that aspect of discussion. I’ll leave that for another day.

What I want to show you today is how you can use it in a Zend Framework application, specifically a Zend Expressive application, to get a range of benefits. These include:

  • Simplifying Testing
  • Implementing DRY code
  • Implementing decoupled code

The frame of reference I’m going to use today is that the application’s you’re creating uses Zend\Db\Sql for handling persistence, storing data in relational databases, such as MySQL, PostgreSQL, Oracle, and so on. This is one which the manual encourages, by virtue of the fact that it covers it as a core part of the documentation.

There’s nothing wrong with this approach, and it’s one I use myself quite often. What’s more, if you’re application’s not too large in size, such as applications created for digital agencies perhaps, then it’s likely a good fit.

But if your application’s longer lived, larger in scale, or more complex, then it might benefit from implementing the repository pattern in order to achieve the three benefits listed above.

I’m really tempted at this point to trot out the old argument of having utmost flexibility, where you can change your database vendor if you needed to, or you can change your data source completely if you wanted to, such as changing from a relational database, to a NoSQL data store such as MongoDb and Hadoop, or use a remote API.

But I think that is a flawed argument, one which has never really stood the test of time. For example, despite the fact that we can use this approach to decouple our code from a specific data store, how often are we really going to do that?

It’s not as easy as installing a different database or service and porting a bit of code. Often times there can be quirks between platforms, not to mention different licensing considerations - which can get quite costly.

I’m much more interested in code being testable than I am in it being portable across backends. The fact that increased portability is a side benefit is quite handy though.

In the code example below, I have a CompanyTable class, which manages access to Company entities, with their data being stored in a relational database.

<?php

namespace App\TableGateway;

use App\Entity\Comapny;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\Sql\Select;
use Zend\Db\TableGateway\TableGateway;

class CompanyTable
{
    private $tableGateway;

    public function __construct(TableGateway $tableGateway)
    {
        $this->tableGateway = $tableGateway;
    }

    public function fetchAll() {}

    public function fetchByName($name) {}

    public function save(Entity\Company $company) {}
}

The class has three methods; one to fetch all records, one to fetch by the company’s name, and third to save a new company.

If this was a real class, you’d likely have a host of other methods, such as delete, and so on. But for the purposes of a simple example, this should be sufficient. Each of these methods would use the private $tableGateway member variable to interact with the database. But is this the right way to go?

In a smaller application, one without a lot of overhead, longevity, or sophistication, it’s likely quite fine. The approach has the advantages of not having many classes to manage, create, or maintain. Assuming you’re using dependency injection as part of your application, then there’s not a lot to configure there either. Given that, the application will likely be able to be refactored relatively quickly.

Let’s see how to implement it. The first thing we need to do is to consider the common methods on our existing TableGateway class above, and extract them out in to an interface. In this case, there aren’t many, those being fetchAll, fetchByName, and save. Given that, an equivalent interface might look like this:

class CompanyRepositoryInterface
{
    public function fetchAll();
    public function fetchByName($name);
    public function save(Entity\Company $company);
}

I’ve called the new interface CompanyRepositoryInterface, because I feel that it clearly expresses the interface’s purpose. Now that we have that, we need to do a minor refactor on CompanyTable above, so that it implements the interface.

class CompanyTable implements CompanyRepositoryInterface {
  // remaining code...
}

With that done, we now need to make one further change, which is in our Service Locator configuration. I’m not sure of your setup, but the approach I’ve commonly taken is to use either a factory or abstract factory class to handle the instantiation of the TableGateway, which is then passed to the constructor of the table class.

In the snippet below, you can see how I’d commonly instantiate a new TableGateway object using the HydratingResultSet.

$resultSet = new HydratingResultSet(
    new ArraySerializable(),
    new Company()
);
$tableGateway = new TableGateway(
    'tblcompany', $dbAdapter, null, $resultSet
);

Then, in another abstract factory, or factory, I’d then retrieve the TableGateway class from the ServiceLocator and pass it to the constructor of the table class as follows:

public function createServiceWithName(
    ServiceLocatorInterface $serviceLocator,
    $name,
    $requestedName
) {
    if (class_exists($requestedName)) {
        $tableGateway = $requestedName . 'Gateway';
        return new $requestedName($serviceLocator->get($tableGateway));
    }

    return false;
}

Then, in dependencies.global.php I’d have a configuration such as this:

'abstract_factories' => [
    App\ServiceManager\AbstractFactory\TableAbstractFactory::class,
    App\ServiceManager\AbstractFactory\TableGatewayAbstractFactory::class,
],

Now that we’ve covered how we might use Table and TableGateway classes, let’s get more specific with a use case, and see what would be involved in refactoring it to use the repository pattern. In the code example below, you can see a stub of a CompanyPageAction class, which is responsible for handling interactions with a company page.

class CompanyPageAction
{
    private $companyTable;

    public function __construct(
        RouterInterface $router,
        TemplateRendererInterface $template,
        CompanyTable $companyTable,
    ) {
        $this->router = $router;
        $this->template = $template;
        $this->companyTable = $companyTable;
    }
}

You can see that, aside of the standard PageAction requirements of a RouterInterface and a TemplateRendererInterface, it requires a CompanyTable object as the third constructor parameter.

class PageActionAbstractFactory implements AbstractFactoryInterface
{
    public function createServiceWithName(
        ServiceLocatorInterface $serviceLocator, $name, $requestedName
    ) {
        if ($requestedName == CompanyPageAction::class) {
            $router     = $serviceLocator->get(RouterInterface::class);
            $template   = $serviceLocator->get(TemplateRendererInterface::class);
            $companyTable = $serviceLocator->get(CompanyTable::class);
            return new $requestedName(
                $router,
                $template,
                $companyTable
            );
        }
    }
}

When this class is instantiated, such as by a PageActionFactory, as in the example below, it will retrieve a CompanyTable from the service locator and supply it to the constructor. Note: this isn’t using the latest version of the Zend ServiceManager.

To make use of the new interface, we first change the constructor signature of the CompanyPageAction to use the new interface, as below.

class CompanyPageAction
{
    private $companyTable;

    public function __construct(
        RouterInterface $router,
        TemplateRendererInterface $template,
        CompanyRepositoryInterface $companyRepository,
    ) {
        $this->router = $router;
        $this->template = $template;
        $this->companyRepository = $companyRepository;
    }
}

Then we’d refactor the PageActionAbstractFactory to reflect the refactoring of the CompanyPageAction, as follows.

class PageActionAbstractFactory implements AbstractFactoryInterface
{
    public function createServiceWithName(
        ServiceLocatorInterface $serviceLocator, $name, $requestedName
    ) {
        if ($requestedName == CompanyPageAction::class) {
            $router     = $serviceLocator->get(RouterInterface::class);
            $template   = $serviceLocator->get(TemplateRendererInterface::class);
            $repository = $serviceLocator->get(CompanyRepositoryInterface::class);
            return new $requestedName(
                $router,
                $template,
                $repository
            );
        }
    }
}

And with that, we are able to continue on exactly as before, yet already begin seeing the benefits of more decoupled and more testable code.

You’re Now Better Able to Test?

This, to me, is the key benefit of implementing the repository pattern. By having made the above changes, we can now test a lot more easily. We’re able to do so by creating a class which implements the interface and passing that to our relevant classes during unit tests.

We could also create mocks, stubs, doubles and so on. And this is still a viable option. But that may not be the best approach. Instead we’re now much more able to provide canned implementations, if that works best, to test code which relies on these classes. This, to me, is the most important aspect.

Normally, when we talk about making code more flexible, and more maintainable there’s the subtle inference that we’re going to have to do a lot of setup work just to start seeing any benefits. But as these code samples should have shown, we don’t need to do very much at all, to start seeing quite an extensive range of benefits.

To reiterate, here’s the process which we followed:

  1. We extracted the common methods from an existing implementation to a new interface.
  2. We refactored our existing class to implement that interface.
  3. We updated the constructor signatures of relevant classes to require that interface.
  4. We refactored all requests by the service locator to request an implementation of the interface.

Now if the application you’re developing, or maintaining, is already quite sizeable, then it well may be quite an investment to make. However, in spite of the effort, the choice may well be the right one to make. But that’s a choice which only you and your team can make.

If you’re considering writing it off as too hard, or too much work, I strongly encourage you to stop for a moment and consider the potential long term benefits and the trade off which an investment in refactoring may make over the longer term. It may just turn out to be worth it.

If you’re not sure, why not consider a partial refactor as a test case? Consider refactoring a small portion of the application to implement the repository pattern, and then assess how much of an investment was required. That way, you’re in a better position to determine if a complete refactor is worthwhile.

Either way, implementing the repository pattern’s been something which has yielded numerous benefits for me personally. I hope that it will do the same for you.

If you’re already using it, or are strongly considering doing so, what experience and thoughts do you have to share? Let us all know in the comments.

There’s a lot more to the topic than I’ve been able to cover here. But if this discussion of the repository pattern has piqued your curiosity, here are a list of further resources which provide a far more in-depth discussion.


You might also be interested in these tutorials too...

Tue, Aug 9, 2016

The 3-Step Guide to Downloading Files in Zend Expressive

A common requirement of web-based applications is to upload and download files. But, out of the box, there’s no simple way to download them in Zend Expressive. This tutorial shows you how - step-by-step.

Wed, May 18, 2016

How to Edit Consistently Using EditorConfig

When working with other developers on a project, editor and IDE differences, whilst not fatal, can be annoying, and even violate group coding standards. Put an end to that by using EditorConfig.

Tue, Jun 26, 2018

What Are Delegator Factories and Why You Should Use Them

Ever wanted to dynamically expand the functionality of an object which you retrieve from your dependency injection container, based on different needs, yet without creating messy, hard to maintain configurations? Then you’re going to want to know about a powerful new technique - called Delegator Factories.

Tue, Jul 25, 2017

How to Create a Zend Expressive Module

Ever thought of creating a Zend Expressive module, one that either scratches an itch or allows you to use a set of related functionality across multiple Zend Expressive projects? I created one recently and share how I did it with you in this three-part series.


Want more tutorials like this?

If so, enter your email address in the field below and click subscribe.

You can unsubscribe at any time by clicking the link in the footer of the emails you'll receive. Here's my privacy policy, if you'd like to know more. I use Mailchimp to send emails. You can learn more about their privacy practices here.

Join the discussion

comments powered by Disqus