Home » Php » php – Laravel Cache:: Best Practices

php – Laravel Cache:: Best Practices

Posted by: admin July 12, 2020 Leave a comment

Questions:

PHP Colleagues:

This question relates to best practices for using Laravel Cache.

The central objective is to reduce the number of accesses to the database for all the usual
performance-related reasons. The application is a read-intensive news site with perhaps a dozen controllers at most, mostly resource-type.

Are there any documented best practices for the application design? It seems obvious to me
that since Cache:: is a one-line statement, it’s easy to drop this into the controllers —
either return the cached data or call the model and cache the results. And invalidate the
cache (maybe with an eager reload) when requests update the model. But is that a good practice?

Here’s a first look at doing this in the controller

/**
 * Retrieve listing of the gallery resource.
 *
 * @uses GET /gallery to return all image_collections.
 *
 * @param int $id The gallery id
 *
 * @return Response - Contains a HTTP code and a list of articles.
 */
public function index()
{
    $response_data = array();
    $response_code = 200;

    // TRY TO RETURN A CACHED RESPONSE
    $cache_key = "gallery_index";
    $response_data = Cache::get($cache_key, null);

    // IF NO CACHED RESPONSE, QUERY THE DATABASE
    if (!$response_data) {
        try {
            $response_data['items'] = $this->gallery->all();
            Cache::put($cache_key, $response_data, Config::get('app.gallery_cache_minutes'));
        } catch (PDOException $ex) {
            $response_code = 500;
            $response_data['error'] = ErrorReporter::raiseError($ex->getCode());
        }
    }

    return Response::json($response_data, $response_code);
}

I’ve heard the suggestion that you could use Laravel Route Filters to cache the responses,
but I can’t quite get my head around the idea.

Thoughts? References? Examples?

Thanks to all,
Ray

How to&Answers:

Many people do this differently but when best practices is a concern I believe the best place to do caching is in your repository.

Your controller shouldn’t know too much about the data source I mean whether its coming from cache or coming from database.

Caching in controller doesn’t support DRY (Don’t Repeat Yourself) approach, because you find yourself duplicating your code in several controllers and methods thereby making scripts difficult to maintain.

So for me this is how I roll in Laravel 5 not so different if are using laravel 4:

//1. Create GalleryEloquentRepository.php in App/Repositories

<?php namespace App\Repositories;

use App\Models\Gallery;
use \Cache;

/**
 * Class GalleryEloquentRepository
 * @package App\Repositories
 */
class GalleryEloquentRepository implements GalleryRepositoryInterface
{

    public function all()
    {
        return Cache::remember('gallerys', $minutes='60', function()
        {
            return Gallery::all();
        });
    }


    public function find($id)
    {
        return Cache::remember("gallerys.{$id}", $minutes='60', function() use($id)
        {
            if(Cache::has('gallerys')) return Cache::has('gallerys')->find($id); //here am simply trying Laravel Collection method -find

            return Gallery::find($id);
        });
    }

}

//2. Create GalleryRepositoryInterface.php in App/Repositories

<?php namespace App\Repositories;

/**
 * Interface GalleryRepositoryInterface
 * @package App\Repositories
 */
interface GalleryRepositoryInterface
{

    public function find($id);

    public function all();
}

//3. Create RepositoryServiceProvider.php in App/Providers

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;

/**
 * Class RepositoryServiceProvider
 * @package App\Providers
 */
class RepositoryServiceProvider extends ServiceProvider
{

    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    //protected $defer = true;

    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {

        $this->app->bind(
            'App\Repositories\GalleryRepositoryInterface',
            'App\Repositories\GalleryEloquentRepository'
        );
    }
}

//4. At the controller you can do this

<?php namespace App\Http\Controllers;

use \View;
use App\Repositories\GalleryRepositoryInterface;

class GalleryController extends Controller {

    public function __construct(GalleryRepositoryInterface $galleryInterface)
    {
        $this->galleryInterface = $galleryInterface;

    }


    public function index()
    {
        $gallery = $this->galleryInterface->all();

        return $gallery ? Response::json($gallery->toArray()) : Response::json($gallery,500);
    }

}

Answer:

Of course there are techniques that you can avoid putting cache logic within your controllers and hand it off to some third party packages to manage the caching for you.

I recommend you to take a look at this article

https://github.com/imanghafoori1/laravel-widgetize

This way you can organize your page partials into well defined and self cached widgets classes. so you will have granular control for cache configs, and you only have to set the “configs”(and not the caching logic). like “cache tags”, “expiration period” and etc.
The cache logic is written by some one else for you and extracted out into a well unit tested package. so it does not pollute you code.

The other advantage is that not only you save database queries in this way but you also save a lot of php code from running over and over again, for example the php code behind laravel blade does not need to be run and it doesn’t when the widget is within the cache.