Implement Repository Design Pattern in Laravel
Tags: repositorydesignpattern, laravel, laravelcachingapi, cachingapi
Published: 2019-12-04 18:39:39


[# The Repository Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff649690(v=pandp.10)?redirectedfrom=MSDN)

![](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/images/ff649690.4058e458-bd54-4597-845e-6f8b1a21cfc3%28en-us%2cpandp.10%29.png)

# Use case
* We have Post resource
* Need to implement controller to support APIs for these features :

> Get all posts
 Paginate posts
 Find posts with condition
 Find post by id
 Caching APIs to improve performance

# Preparation
* Post model (database driver can be MySQL/ PostgreSQL/ SQLite/ SQL Server)
```php
<?php  

namespace App;  
  
use Illuminate\Database\Eloquent\Model;  
  
class Post extends Model  
{  
  protected $table = 'posts';  
}
```

* Contract 
```php
<?php

namespace App\Http\Contracts;

interface RepositoryInterface
{
    /**
     * Retrieve all data of repository
     *
     * @param array $columns
     *
     * @return mixed
     */
    public function all($columns = ['*']);

    /**
     * Retrieve all data of repository, paginated
     *
     * @param null $limit
     * @param array $columns
     *
     * @return mixed
     */
    public function paginate($limit = null, $columns = ['*']);

    /**
     * Find data by multiple fields
     *
     * @param array $where
     * @param array $columns
     *
     * @return mixed
     */
    public function findWhere(array $where, $columns = ['*']);

    /**
     * Find data by id
     *
     * @param       $id
     * @param array $columns
     *
     * @return mixed
     */
    public function find($id, $columns = ['*']);

}

```
# Implementation Details
> ##  Newbie/Beginner/Fresher/Intern level

```php
<?php

namespace App\Http\Controllers;

use App\Http\Contracts\RepositoryInterface;
use App\Post;

class PostController extends Controller  implements RepositoryInterface
{
    protected $post;

    public function __construct(Post $post)
    {
        $this->post = $post;
    }

    public function all($columns = ['*'])
    {
        return $this->post->all($columns);
    }

    public function paginate($limit = null, $columns = ['*'])
    {
        return $this->post->paginate($limit, $columns);
    }

    public function find($id, $columns = ['*'])
    {
        return $this->post->find($id, $columns);
    }

    public function findWhere(array $where, $columns = ['*'])
    {
        foreach ($where as $field => $value) {
            if (is_array($value)) {
                list($field, $condition, $val) = $value;
                $this->post = $this->post->where($field, $condition, $val);
            } else {
                $this->post = $this->post->where($field, '=', $value);
            }
        }
        return $this->post->get($columns);
    }
}

```
##
> ##  Database Repository/ Junior Level
```php
<?php

namespace App\Http\Controllers;

use App\Http\Contracts\RepositoryInterface;
use App\Post;

class DbPostRepository implements RepositoryInterface
{
    private $post;

    public function __construct(Post $post)
    {
        $this->post = $post;
    }

    public function all($columns = ['*'])
    {
        return $this->post->all($columns);
    }

    public function paginate($limit = null, $columns = ['*'])
    {
        return $this->post->paginate($limit, $columns);
    }

    public function findWhere(array $where, $columns = ['*'])
    {
        foreach ($where as $field => $value) {
            if (is_array($value)) {
                list($field, $condition, $val) = $value;
                $this->model = $this->post->where($field, $condition, $val);
            } else {
                $this->model = $this->post->where($field, '=', $value);
            }
        }
        return $this->post->get($columns);
    }

    public function find($id, $columns = ['*'])
    {
        return $this->post->find($id, $columns);
    }
}

class DbPostController extends Controller
{
    private $dbPostRepository;

    public function __construct(DbPostRepository $dbPostRepository)
    {
        $this->dbPostRepository = $dbPostRepository;
    }

    public function all($columns = ['*'])
    {
        return $this->dbPostRepository->all($columns);
    }

    public function paginate($limit = null, $columns = ['*'])
    {
        return $this->dbPostRepository->paginate($limit, $columns);
    }

    public function findWhere(array $where, $columns = ['*'])
    {
        return $this->dbPostRepository->findWhere($where, $columns);
    }

    public function find($id, $columns = ['*'])
    {
        return $this->dbPostRepository->find($id, $columns);
    }
}

```


##
> ##  Caching Repository/ Senior Level
```php
<?php

namespace App\Http\Controllers;

use App\Http\Contracts\RepositoryInterface;
use Illuminate\Contracts\Cache\Repository as CacheRepository;

class CachePostRepository implements RepositoryInterface
{
    private $dbPostRepository;
    private $cacheRepository;

    public function __construct(DbPostRepository $dbPostRepository, CacheRepository $cacheRepository)
    {
        $this->dbPostRepository = $dbPostRepository;
        $this->cacheRepository = $cacheRepository;
    }

    public function getCacheMinutes()
    {
        return config('repository.cache.minutes', 30);
    }

    public function getCacheKey($method, $args = null)
    {
        $request = app('Illuminate\Http\Request');
        $args = serialize($args);
        $criteria = $this->serializeCriteria();
        $key = sprintf('%s@%s-%s', get_called_class(), $method, md5($args . $criteria . $request->fullUrl()));
        return $key;
    }

    public function all($columns = ['*'])
    {
        $key = $this->getCacheKey('all', func_get_args());
        $minutes = $this->getCacheMinutes();
        return $this->cacheRepository->remember($key, $minutes, function () use ($columns) {
            return $this->dbPostRepository->all($columns);
        });
    }

    public function paginate($limit = null, $columns = ['*'])
    {
        $key = $this->getCacheKey('paginate', func_get_args());
        $minutes = $this->getCacheMinutes();
        return $this->cacheRepository->remember($key, $minutes, function () use ($limit, $columns) {
            return $this->dbPostRepository->paginate($limit, $columns);
        });
    }


    public function findWhere(array $where, $columns = ['*'])
    {
        $key = $this->getCacheKey('findWhere', func_get_args());
        $minutes = $this->getCacheMinutes();
        return $this->cacheRepository->remember($key, $minutes, function () use ($where, $columns) {
            return $this->dbPostRepository->findWhere($where, $columns);
        });
    }

    public function find($id, $columns = ['*'])
    {
        $key = $this->getCacheKey('find', func_get_args());
        $minutes = $this->getCacheMinutes();
        return $this->cacheRepository->remember($key, $minutes, function () use ($columns) {
            return $this->dbPostRepository->all($columns);
        });
    }
}

class CachePostController extends Controller
{
    private $cachePostRepository;

    public function __construct(CachePostRepository $cachePostRepository)
    {
        $this->cachePostRepository = $cachePostRepository;
    }

    public function all($columns = ['*'])
    {
        return $this->cachePostRepository->all($columns);
    }

    public function paginate($limit = null, $columns = ['*'])
    {
        return $this->cachePostRepository->paginate($limit, $columns);
    }

    public function findWhere(array $where, $columns = ['*'])
    {
        return $this->cachePostRepository->findWhere($where, $columns);
    }

    public function find($id, $columns = ['*'])
    {
        return $this->cachePostRepository->find($id, $columns);
    }
}

```