My Laravel Repository Pattern Solution (in only 30 lines of code)

A 30 line piece of script can finally provide a good solution for a repository pattern in Laravel apps.

The problem

Laravel provides a beautiful way to query your database through Eloquent, an Object Relational Mapping. The moment your project becomes larger there starts to rise a problem. The difference between entities and models start to become vague. Let me give you an example:

We have two methods, one called

findByName

and one called

concatName

.



namespace App;

use IlluminateDatabaseEloquentModel;

class Product extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'products';

    /**
     * Find published product by name
     * @param  string $name
     * @return Product
     */
    public function findByName(string $name): Product
    {
        return $this->whereName($name)
                    ->whereIsPublished(1)
                    ->first();
    }

    /**
     * Say we want to concat the name and a category name
     * @return string 
     */
    public function concatName(): string
    {
        return $this->attributes['name'] . ' - ' . $this->attributes['category_name'];
    }
}

What we are actually doing here is mixing methods for retrieving (collections of) Products, with methods for instances of 1 Product. 

A much cleaner approach would be to separate them into 2 different classes. One for obtaining instances and collections of models and one for the model definition itself. You might call this the repository pattern.

Splitting into 2 classes

There are several libraries for Laravel to start using the repository pattern. One thing that’s a huge disadvantage to me is that you can’t use Eloquent functions on your repositories. Since Eloquent is a huge reason why I am using Laravel I still wanted to be able to use Eloquent on repositories for obtaining models. 

The solution

I created a very simple piece of code which enables all the features of Eloquent on your repositories. This way you can use the repository pattern in a way which is fun and keep your models and your repositories clean! A repository with the use of

laravel-repositories

would look like this:



namespace AppRepositories;

use AppModelsProduct;
use MrAtiebatieRepository;
use IlluminateDatabaseEloquentModel;

/**
 * Product repository
 */
class ProductRepository extends Model
{
    use Repository;

    /**
     * The model being queried.
     *
     * @var IlluminateDatabaseEloquentModel
     */
    protected $model;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->model = app(Product::class);
    }

    /**
     * Find published products by SKU
     * @param  {int} $sku
     * @return {Product}
     */
    public function findBySku(int $sku): Product {
        return this->whereIsPublished(1)
                   ->whereSku($sku)
                   ->first();
    }
}
By the use of the Repository trait and the

$model

property,

laravel-repositories

knows which model to query and where to use Eloquent and where to use your own repository methods. 

With this definition of the repository we can now use it in our controllers, jobs, commands etc:



/**
 * In your routes/web.php
 */

$router->get('/', function (AppRepositoriesProductRepository $productRepo) {

    // Use any Eloquent feature directly
    $productRepo->all()->dd();

    // Use your custom repository methods
    echo $productRepo->findBySku(12345)->name;

    // You can even query relations
    echo $productRepo->first()->category;

});

Go try it out and leave me some feedback for improvement!

I’m currently working on Laravel Pigeon, a notification center for communicating with your users and debugging notifications. Sign up for early access!

read original article here