Repository design pattern done right in Laravel

In this post I will show you how to setup the repository design pattern in Laravel from scratch. I will be using the Laravel 5.8.3 version, but the Laravel version shouldn’t really matter too much. Before we start coding there are a few things you need to know about the repository design pattern.

The repository design pattern allows you to use objects without having to know how these objects are persisted. Essentially it is an abstraction of the data layer.

This means that your business logic doesn’t need to know how data is retrieved or what the source of the data is. The business logic relies on the repository to retrieve the correct data.

A misconception that I see a lot regarding to this pattern is that repositories are being implemented in such a way to create or update records. This is not what a repository should do. Repositories shouldn’t create or update data, but should only be used to retrieve data.

Enough of the theory, let’s start coding

Since we will be doing this from scratch, let’s start by creating a new Laravel project:

composer create-project --prefer-dist laravel/laravel repository

For this tutorial I will be creating a small blog application. Now that we have created a project we need to create a Controller and Model for the blog.

php artisan make:controller BlogController

This will create the BlogController in the app/Http/Controllers folder.

php artisan make:model Models/Blog -m

Note: 
The -m option will create a database migration. This file can be found in the database/migrations folder.

This will create your Blog model and store it in the app/Models folder. This is just one way to store your models, which tempts to be the method I prefer.

Now that we have our Controller and Model it is time to look at the migration file we created. Our blog only needs a title, content and user_id field for now besides the default Laravel timestamp fields.

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateBlogsTable extends Migration
{
public function up()
{
Schema::create('blogs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('content');
$table->integer('user_id');
$table->timestamps();

$table->foreign('user_id')
->references('id')
->on('users');
});
}

public function down()
{
Schema::dropIfExists('blogs');
}
}

Note:
If you are using an older version than Laravel 5.8 you should replace the following line

$table->bigIncrements(‘id’);

with

$table->increments('id');

Setup the database

I will be using a MySQL database for this example. The first step is to create a new database.

mysql -u root -p 
create database laravel_repository;

This will create a database called laravel_repository. Next we have to add the database credentials to the .env file.

DB_DATABASE=laravel_repository
DB_USERNAME=root
DB_PASSWORD=secret

After you have changed the .env file we have to clear the configuration cache:

php artisan config:clear

Run the migration

Now that we have setup the database we can run the migration:

php artisan migrate

This will create our blogs table with the title, content and user_id fields that we declared in the migration.

Implementing the Repository design pattern

With everything in place we can now start implementing the repository design pattern. We will start by creating a Repositories folder in the app folder. The second folder that we will create is the Interfaces folder. This folder will be located in the Repositories folder that we just created.

In the Interfaces folder we create a BlogRepositoryInterface class which will have two methods for now:

  1. The all method which will return all blogs.
  2. The getByUser method which will return all blogs that were created by a specific user.
<?php

namespace App\Repositories\Interfaces;

use App\User;

interface BlogRepositoryInterface
{
public function all();

public function getByUser(User $user);
}

The final class that we are going to create is the BlogRepository, which will implement the BlogRepositoryInterface. We are going to stick to a very straightforward implementation.

<?php

namespace App\Repositories;

use App\Models\Blog;
use App\User;
use App\Repositories\Interfaces\BlogRepositoryInterface;

class BlogRepository implements BlogRepositoryInterface
{
public function all()
{
return Blog::all();
}

public function getByUser(User $user)
{
return Blog::where('user_id'. $user->id)->get();
}
}

Your Repositories folder should look like this:

app/
└── Repositories/
├── BlogRepository.php
└── Interfaces/
└── BlogRepositoryInterface.php

You have now succesfully created your repository! But we aren’t done yet. It is time to start using our repository.

The repository in action

To start using the BlogRepository we should inject it into the BlogController. Since the repository will be injected, it is easy to swap it out with another implementation. This is what our controller will look like:

<?php

namespace App\Http\Controllers;


use App\Repositories\Interfaces\BlogRepositoryInterface;
use App\User;

class BlogController extends Controller
{
private $blogRepository;

public function __construct(BlogRepositoryInterface $blogRepository)
{
$this->blogRepository = $blogRepository;
}

public function index()
{
$blogs = $this->blogRepository->all();

return view('blog')->withBlogs($blogs);
}

public function detail($id)
{
$user = User::find($id);
$blogs = $this->blogRepository->getByUser($user);

return view('blog')->withBlogs($blogs);
}
}

As you can see the code in the controller is short and thus readable. You don’t need ten lines of code to get the dataset you want, all could be done in one line of code thanks to the repository. This is also great for unit testing, since the methods of the repository could be easily mocked.

The repository design pattern also makes it very easy to change between datasources. In this example we are using a database to retrieve our blogs. We rely on Eloquent to do that for us. But let’s say that we saw a great blog API somewhere on the internet and we want to use this API. All we have to do is rewrite the BlogRepository to make use of this API instead of Eloquent.

The RepositoryServiceProvider

Instead of injecting the BlogRepository in the BlogController we will be injecting the BlogRepositoryInterface and then let the Service Container decide which repository will be used. This could be done in the boot method of the AppServiceProvider, but I prefer to create a new provider for this to keep things clean.

php artisan make:provider RepositoryServiceProvider

The reason we create a new provider for this is that things tempt to get really messy when your project starts growing. Imagine a project with more than 10 models each having their own repository. Your AppServiceProvider will get unreadable.

This is what our RepositoryServiceProvider will look like:

<?php

namespace App\Providers;

use App\Repositories\BlogRepository;
use App\Repositories\Interfaces\BlogRepositoryInterface;
use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
BlogRepositoryInterface::class,
BlogRepository::class
);
}
}

Note how easy it is to swap out the BlogRepository with another repository.

Don’t forget to add the RepositoryServiceProvider to the list of providers in the config/app.php file. After that we have to clear the configuration cache once more.

php artisan config:clear

That’s it

You’ve now succesfully implemented the repository design pattern. It wasn’t that hard, right?

You could choose to expand your code by adding some routes and views, but I’ll end this post here since this post is about implementing the repository pattern.

If you enjoyed this post or if it helped you setting up the repository design pattern make sure to check out my other posts aswell. Please feel free to leave a comment if you have any feedback, questions or want me to write about another Laravel related topic.