This article is linked to pilishen.com—-. Welcome to learn php&Laravel with Pilishen; Study group: 109256050

This article is an extended reading of the chapter of “Laravel Underlying Core Technology Practical Revelation” and “Laravel Underlying Core Concept Analysis”. Considering the basic differences of students, in order to avoid too detailed and lengthy videos, some PHP knowledge points related to laravel’s underlying implementation are presented in the form of articles for preview and reference at any time.

As we mentioned earlier in the course, it’s always wise to decouple controller from our Eloquent ORM (or other data source) when developing any formal Laravel project. Typically, we create an interface, write a repository that implements that interface, and then resolve the dependencies on that interface to the repository via the Laravel service container. Data manipulation is done in Repository.

The same applies to caches. As we all know, data queries are often a major performance bottleneck in a Web application, so it is inevitable to create caches for data queries. It’s also a bad idea to implement data caching specifically in your controller — you’re tying the controller to a specific cache implementation, and if you want to switch from memcache to redis, for example, Then you have to change the logic in your controller a lot. Also, when a single data query occurs in multiple places, you have to write duplicate cache implementations.

Perhaps you could write the cache-specific implementation logic in your repository, which would work for relatively small projects. However, this also means that your repository depends on both the ORm and the cache of your choice. If you want to change any of these dependencies, it is likely that you will have to write a whole new Repository from scratch, repeating much of the previous code in the process.

There is, of course, a more elegant way — by using a “decorator pattern”, we can create a repository that implements the same interface and “wrap” the implementation of the previous repository. Or “embellish” it. In the cache-specific repository, each method retrieves the logic in the previous data repository and returns the cached response accordingly. In this way, the logic of our cache is relatively separate from the logic of our data operations, so if we want to change the data source later, our cache implementation will not be affected.

Suppose this is the interface corresponding to our Usermodel:

<? php namespace App\Repositories\Interfaces; interface UserRepositoryInterface { publicfunction all();
    public function findOrFail($id);
    public function create($input);
}
Copy the code

Next is the corresponding repository for data operations:

<? php namespace App\Repositories; use App\User; use App\Repositories\Interfaces\UserRepositoryInterface; use Hash; class EloquentUserRepository implements UserRepositoryInterface { private$model;
    public function __construct(User $model)
    {
        $this->model = $model;
    }
    public function all()
    {
        return $this->model->all();
    }
    public function findOrFail($id)
    {
        return $this->model->findOrFail($id);
    }
    public function create($input)
    {
        $user = new $this->model;
        $user->email = $input['email'];
        $user->name = $input['name'];
        $user->password = Hash::make($input['password']);
        $user->save();
        return $user; }}Copy the code

We can define a cache repository as follows:

<? php namespace App\Repositories\Decorators; use App\Repositories\Interfaces\UserRepositoryInterface; use Illuminate\Contracts\Cache\Repository as Cache; class CachingUserRepository implements UserRepositoryInterface { protected$repository;
    protected $cache;
    public function __construct(UserRepositoryInterface $repository, Cache $cache)
    {
        $this->repository = $repository;
        $this->cache = $cache;
    }
    public function all()
    {
        return $this->cache->tags('users')->remember('all', 60.function () {
            return $this->repository->all();
        });
    }
    public function findOrFail($id)
    {
        return $this->cache->tags('users')->remember($id, 60.function () use ($id) {
            return $this->repository->findOrFail($id);
        });
    }
    public function create($input)
    {
        $this->cache->tags('users')->flush();
        return $this->repository->create($input); }}Copy the code

As you can see, each method in our cache repository is not actually responsible for any queries. We use constructor to receive an implementation class that also implements the interface, the repository of the previous data query, as well as the cache service. In this way, we do not need to touch any data query logic. Fetching the corresponding method in the repository of data and “wrapping” it in the cache, or “embellishing” the result of a previous query with the cache implementation.

To actually call our cache implementation, we need to update our service provider so that it resolves the decorator, our cache repository, accordingly:

<? php namespace App\Providers; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { publicfunction register()
    {
        $this->app->singleton('App\Repositories\Interfaces\UserRepositoryInterface'.function () {
            $baseRepo = new \App\Repositories\EloquentUserRepository(new \App\User);
            $cachingRepo = new \App\Repositories\Decorators\CachingUserRepository($baseRepo.$this->app['cache.store']);
            return $cachingRepo; }); }}Copy the code

As you can see, we instantiate the data query repository ($baseRepo), then instantiate the Cache Repository, pass in the data Repository and the cache service, and return the cache Repository instance. And once we do that, we can actually call it in the controller.

Note that using cache Repository to “decorate” an existing data repository is just one example and one use. Hopefully, you will learn how to “decorate” your existing data repository. You can also trigger specific events in decorators, for example.