Decorator Pattern to Cache in Laravel PHP
Bedram Tamang
Oct 31, 2018 ยท 2 min read

Decorator Pattern to Cache in Laravel PHP

Consider that we defined a route http://localhost/users in web.php which returns the list of users in our application.index method of UsersController will invoke while hitting this route. as

<?php

use App\Http\Controllers\UsersConroller;    
    
    
Route::get("users", [UsersController::class,'index']);
    

List of users can be written from UsersController as:

<?php

namespace App\Http\Controllers;

...

class UserController extends Controller
{
    public function index()
    {
        return response()->json(["data" => User::all()]);
    }
}

This is very simple example where only users data is returning from controller. In our real world application, it requires to return multiple model data (users, articles) from a single controller, so we create a dedicated class called Data access object (DAO) class, to access all the data required in controller.

<?php

namespace App\DAO;

use App\Models\User;

class UserDAO
{
    public function getUser()
    {
        return User::all();
    }
}

Controller is updated to use UserDAO as:

<?php

namespace App\Http\Controllers;

use App\DAO\UserDAO;

class UserController extends Controller
{
    public function index()
    {
        return response()->json(["data" => (new UserDAO)->getUser()]);
    }
}

Since the above code is directly dependent on actual implementation of UserDAO class, so let's create a interface to make code loose coupling.

<?php

namespace App\DAO;

interface UserDAOInterface
{
    public function getUser();
}

and Implement this interface in UserDAO as:

<?php

namespace App\DAO;

use App\Models\User;

class UserDAO implements UserDAOInterface
{
    public function getUser()
    {
        return User::all();
    }
}

Now bind our UserInterfaceClass in AppServiceProvider as:

<?php

namespace App\Providers;

use App\DAO\UserDAO;
use App\DAO\UserDAOInterface;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app->singleton(UserDAOInterface::class, function ($app) {
            return new UserDAO();
        });
    }
}

Now controller can use UserDAOInterface as:

<?php

namespace App\Http\Controllers;

use App\DAO\UserDAOInterface;

class UserController extends Controller
{
    /**
     * @var UserDAOInterface
     */
    protected $userDAO;

    public function __construct(UserDAOInterface $userDAO)
    {
        $this->userDAO = $userDAO;
    }

    public function index()
    {
        return response()->json(["data" => $this->userDAO->getUser()]);
    }
}

To cache the data, Laravel has given a fluent api. This example shows to cache the users data.

<?php

$value = Cache::remember('users', $seconds, function () {
    return $this->userDAO->getUser();
});

To implement the decorator pattern, UserDAOCache class has been created as:

<?php

namespace App\DAO;

use Illuminate\Support\Facades\Cache;

/**
 * Class UserDAOCache
 * @package App\DAO
 */
class UserDAOCache implements UserDAOInterface
{
    /**
     * @var UserDAOInterface
     */
    protected $next;

    /**
     * UserDAOCache constructor.
     *
     * @param UserDAOInterface $next
     */
    public function __construct(UserDAOInterface $next)
    {
        $this->next = $next;
    }


    public function getUser()
    {
        return Cache::remember("users", 20, function () {
            return $this->next->getUser();
        });
    }
}

This class implements the same UserDAOInterface interface, and accepts the same interface as well. The implementation of method simply call the interface method wrapping the method inside of cache.

Now update the service provider as:

public function boot()
{
    $this->app->singleton(UserDAOInterface::class, function ($app) {
        return new UserDAOCache(new UserDAO());
    });
}

Here, In service provider, the actual implementation class (UserDAO) is being decorated in UserDAOCache class to facilitate the caching. The benefits of this implementation is that it enables caching without modifying the code of actual implementation. No changes is required in either of implementation or controller class.


WRITTEN BY
Bedram Tamang
Laravel Developer

More From Web2tailwind


© 2019 - 2021 Web2tailwind.com