Skip to content

Instantly share code, notes, and snippets.

@petervmeijgaard
Created September 11, 2018 17:39
Show Gist options
  • Save petervmeijgaard/90fb033c560c4bca44619b59e0ef86d9 to your computer and use it in GitHub Desktop.
Save petervmeijgaard/90fb033c560c4bca44619b59e0ef86d9 to your computer and use it in GitHub Desktop.
My take on the Repository Pattern
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* @var string The table where the posts are stored.
*/
protected $table = 'posts';
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use App\Repositories\Contracts\PostRepository;
class PostController extends Controller
{
/**
* Construct the controller.
*
* @param PostRepository $repository The post repository.
*/
public function __construct(PostRepository $repository) {
$this->repository = $repository;
}
/**
* Fetches all the posts.
*
* @param Request $request The post model.
*
* @return JsonResponse The response in JSON format.
*/
public function index(Request $request) : JsonResponse
{
return $this->repository->all();
}
/**
* Fetches a single post by its ID.
*
* @param Request $request The post model.
* @param int $id The post primary identifier.
*
* @return JsonResponse The response in JSON format.
*/
public function show(Request $request, int $id) : JsonResponse
{
return $this->repository->find($id);
}
/**
* Stores a new post.
*
* @param Request $request The post model.
*
* @return JsonResponse The created post in JSON format.
*/
public function store(Request $request) : JsonResponse
{
return $this->repository->store($request->all());
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use App\Repositories\Contracts\PostRepository;
class PostController extends Controller
{
...
public function show(Request $request, int $id) : JsonResponse
{
$post = $this->repository->find($id);
// So what if the Eloquent codebase changes?
// What if retrieving attributes by value isn't supported anymore?
// We need to update every bit of our application that's dependent on Eloquent.
return [
'id' => $post->id,
'title' => $post->title,
'description' => $post->description,
'content' => $post->content,
];
}
...
}
<?php
namespace App\Repositories\Contracts;
use App\Models\Post;
use Illuminate\Support\Collection;
interface PostRepository extends Repository
{
/**
* Fetches the post from it's primary identifier.
*
* @param int $id The primary identifier.
*
* @return Post The post model.
*/
public function find(int $id) : Post;
/**
* Fetches all the available posts.
*
* @return Collection The collection with all the posts.
*/
public function all() : Collection;
/**
* Stores a new post.
*
* @param mixed[] $attributes The attributes of the post.
*
* @return Post The created post.
*/
public function store(array $attributes) : Post;
}
<?php
namespace App\Repositories\Contracts;
use App\Entities\PostEntity;
use Illuminate\Support\Collection;
interface PostRepository extends Repository
{
/**
* Fetches the post from it's primary identifier.
*
* @param int $id The primary identifier.
*
* @return PostEntity The post entity.
*/
public function find(int $id) : PostEntity;
/**
* Fetches all the available posts.
*
* @return Collection The collection with all the posts.
*/
public function all() : Collection;
/**
* Stores a new post.
*
* @param mixed[] $attributes The attributes of the post.
*
* @return PostEntity The created post entity.
*/
public function store(array $attributes) : PostEntity;
}
<?php
namespace App\Repositories\Eloquent;
use App\Repositories\Contracts\PostRepository as PostRepositoryContract;
class PostRepository extends Repository implements PostRepositoryContract
{
/**
* Construct the repository.
*
* @param Post $model The post Eloquent model.
*/
public function __construct(Post $model) {
$this->model = $model;
}
/**
* {@inheritdoc}
*/
public function find(int $id) : Post
{
return $this->model->find($id);
}
/**
* {@inheritdoc}
*/
public function all() : Collection
{
return $this->model->all();
}
/**
* {@inheritdoc}
*/
public function store(array $attributes) : Post
{
$post = new $this->model;
$post->title = $attributes['title'];
$post->description = $attributes['description'];
$post->content = $attributes['content'];
$post->save();
return $post->fresh();
}
}
<?php
namespace App\Repositories\Eloquent;
use App\Repositories\Contracts\PostRepository as PostRepositoryContract;
class PostRepository extends Repository implements PostRepositoryContract
{
...
// The find method returns an Eloquent model.
// When switching to Doctrine, we need to update every instance that uses `$this->repository->find(...)`.
public function find(int $id) : Post
{
return $this->model->find($id);
}
...
}
<?php
namespace App\Repositories\Eloquent;
use App\Repositories\Contracts\PostRepository as PostRepositoryContract;
class PostRepository extends Repository implements PostRepositoryContract
{
/**
* Construct the repository.
*
* @param Post $model The post Eloquent model.
* @param Entity $entity The post entity.
*/
public function __construct(Post $model, PostEntity $entity) {
$this->model = $model;
$this->entity = $entity;
}
/**
* {@inheritdoc}
*/
public function find(int $id) : PostEntity
{
return $this->model->find($id);
}
/**
* {@inheritdoc}
*/
public function all() : Collection
{
return $this->model->all();
}
/**
* {@inheritdoc}
*/
public function store(array $attributes) : Post
{
$post = new $this->model;
$post->title = $attributes['title'];
$post->description = $attributes['description'];
$post->content = $attributes['content'];
$post->save();
return $post->fresh();
}
}
<?php
namespace App\Providers;
use App\Repositories\Eloquent\PostRepository;
use App\Repositories\Contracts\PostRepository as PostRepositoryContract;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* @var mixed[] The array of repositories.
*/
private $repositoryMapping = [
PostRepositoryContract::class => PostRepository::class,
];
/**
* Bootstrap any application services.
*/
public function boot() : void
{
//
}
/**
* Register any application services.
*/
public function register() : void
{
foreach ($this->repositoryMapping as $contract => $instance)
{
$this->app->bind($contract, $instance);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment