Repository Design pattern in Laravel
The Repository Design Pattern
There’s an alternative approach to development that abstracts some calls into PHP classes called Repositories. The idea is that we can decouple models from controllers and assign readable names to complicated queries.
We’re going to refactor our app to use the Repository Pattern. The first step is to create a file for app/Repositories/Repository.php.
<?php namespace App\Repositories;
use Illuminate\Database\Eloquent\Model;
class Repository implements RepositoryInterface
{
// model property on class instances
protected $model;
// Constructor to bind model to repo
public function __construct(Model $model)
{
$this->model = $model;
}
// Get all instances of model
public function all()
{
return $this->model->all();
}
// create a new record in the database
public function create(array $data)
{
return $this->model->create($data);
}
// update record in the database
public function update(array $data, $id)
{
$record = $this->find($id);
return $record->update($data);
}
// remove record from the database
public function delete($id)
{
return $this->model->destroy($id);
}
// show the record with the given id
public function show($id)
{
return $this->model-findOrFail($id);
}
// Get the associated model
public function getModel()
{
return $this->model;
}
// Set the associated model
public function setModel($model)
{
$this->model = $model;
return $this;
}
// Eager load database relationships
public function with($relations)
{
return $this->model->with($relations);
}
}
This file defines our Repository class. Instances of this class have a model property that we tie to an Eloquent model. Once this is bound in the constructor we can call Eloquent methods like findOrFail
, update
or all
from the class methods.
The implements RepositoryInterface section isn’t strictly necessary but it adds an extra layer of structure to our code. An interface is a contract that defines the methods a class MUST have defined. In our case the interface looks like this:
<?php namespace App\Repositories;
interface RepositoryInterface
{
public function all();
public function create(array $data);
public function update(array $data, $id);
public function delete($id);
public function show($id);
}
If we make new Repositories that implement this interface we’ll always know these methods are defined. Interfaces provide structure so we know what our code needs to do.
Back in our TaskController.php file we instantiate a repository and pass in the Task model to it.
<?php
namespace App\Http\Controllers;
use App\Task;
use App\Repositories\Repository;
use Illuminate\Http\Request;
class TaskController extends Controller
{
// space that we can use the repository from
protected $model;
public function __construct(Task $task)
{
// set the model
$this->model = new Repository($task);
}
public function index()
{
return $this->model->all();
}
public function store(Request $request)
{
$this->validate($request, [
'body' => 'required|max:500'
]);
// create record and pass in only fields that are fillable
return $this->model->create($request->only($this->model->getModel()->fillable));
}
public function show($id)
{
return $this->model->show($id);
}
public function update(Request $request, $id)
{
// update model and only pass in the fillable fields
$this->model->update($request->only($this->model->getModel()->fillable), $id);
return $this->model->find($id);
}
public function destroy($id)
{
return $this->model->delete($id);
}
}
The Laravel service container will automatically resolve our dependencies and inject them into the controller instance (docs).
At this point our application works exactly the same but our code has been refactored to use repositories and we’ve added a couple more API endpoints.