Easy repositories and decorators with Laravel Repositories

Published by at 10th January 2018 12:22 pm

Creating repositories for your Laravel models, as well as creating caching decorators for them, is a useful way of not only implementing caching in your web app, but decoupling the application from a specific ORM. Unfortunately, it can involve writing a fair amount of boilerplate code.

Laravel Repositories is a set of base classes and interfaces for creating repositories and decorators in your application. It consists of:

  • A generic interface for repositories
  • A base repository that implements the interface and can be extended for your own repositories
  • A base decorator that also implements the interface and can similarly be extended

By using these, not only are you able to implement caching quickly and easily for most use cases, but you can easily extend the base classes to add additional methods for your use case. By creating new interfaces that extend the base interface, then having your repositories extend the repository and decorator, you can minimise the amount of work required to set up new repositories.

The main interface used is Matthewbdaly\LaravelRepositories\Repositories\Interfaces\AbstractRepositoryInterface, and your interfaces should extend this. Your decorators should extend Matthewbdaly\LaravelRepositories\Repositories\Decorators\BaseDecorator, and your repositories should extend Matthewbdaly\LaravelRepositories\Repositories\Base. Then, if you add any additional methods to your interface and ensure your repository and decorator implement that interface, it should be straightforward to type-hint the interface and get back the decorated repository, which will handle caching for you.

To be able to type-hint the repositories, you need to set them up in a service provider:

3namespace App\Providers;
5use Illuminate\Support\ServiceProvider;
7class AppServiceProvider extends ServiceProvider
9 /**
10 * Bootstrap any application services.
11 *
12 * @return void
13 */
14 public function boot()
15 {
16 //
17 }
19 /**
20 * Register any application services.
21 *
22 * @return void
23 */
24 public function register()
25 {
26 $this->app->singleton('App\Repositories\Interfaces\ExampleRepositoryInterface', function () {
27 $baseRepo = new \App\Repositories\EloquentExampleRepository(new \App\Example);
28 $cachingRepo = new \App\Repositories\Decorators\ExampleDecorator($baseRepo, $this->app['cache.store']);
29 return $cachingRepo;
30 });
31 }

Also, note that the cache backend used must be one that supports tags, such as Redis or Memcached. Data is cached using a tag derived from the model name. This also means you have to be careful when eager-loading relations, as the data will be cached under the main model's name, not that of the relation. You may want to set up separate model events to flush those tags when the related field is updated.