DEV Community

Naster Blue
Naster Blue

Posted on

5 2

Implement Repository Design Pattern in Laravel

# The Repository Pattern

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  

namespace App;  

use Illuminate\Database\Eloquent\Model;  

class Post extends Model  
{  
  protected $table = 'posts';  
}
Enter fullscreen mode Exit fullscreen mode
  • Contract
<?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 = ['*']);

}

Enter fullscreen mode Exit fullscreen mode

Implementation Details

Newbie/Beginner/Fresher/Intern level

<?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);
    }
}

Enter fullscreen mode Exit fullscreen mode

Database Repository/ Junior Level

<?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);
    }
}

Enter fullscreen mode Exit fullscreen mode

Caching Repository/ Senior Level

<?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);
    }
}

Enter fullscreen mode Exit fullscreen mode

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post