Il caching è essenziale per ottenere alte prestazioni e scalabilità. Implementare la corretta strategia di caching fin dalla fase di sviluppo è fondamentale per evitare ritardo nelle API e lentezza nei tempi di caricamento delle pagine. Laravel è uno dei framework PHP più popolari, quindi un’implementazione della strategia di caching Laravel ottimale è indispensabile per una migliore esperienza utente e un maggiore impatto sul business.

In questo articolo, esploreremo le strategie per implementare e manipolare il caching in Laravel: imparerete come funziona, quali sono le query di caching in Laravel e come gestire il caching nelle applicazioni Laravel.

Questo articolo vi sarà ancora più utile se avete già una conoscenza di base di questi temi:

Iniziamo!

Guardate la nostra video guida alla cache di Laravel

Perché la Cache È Importante?

Con il boom dei business internet, le statistiche di diverse aziende mostrano come il tempo di caricamento del sito web e le basse prestazioni possono avere un impatto pesante sulla SEO, l’impegno degli utenti e i tassi di conversione. E questi risultati iniziano con un’eccellente strategia di caching.

Uno studio online ha scoperto che “1 secondo di ritardo nel caricamento costerebbe ad Amazon 1,6 miliardi di dollari di vendite all’anno”.

Un altro studio di Google ha riportato: “La nostra ricerca mostra che se i risultati di ricerca sono rallentati anche di una frazione di secondo, la gente fa meno ricerche (sul serio: un ritardo di 400ms porta a un calo dello 0,44% del volume di ricerca). E questa impazienza non è solo limitata alla ricerca: quattro utenti di internet su cinque fanno clic se un video si blocca durante il caricamento”.

Un leggero ritardo nel tempo di caricamento della vostro pagina web può avere un impatto massiccio sull’esperienza dei vostri utenti e sulla perdita di fondi a lungo termine.

Cos’È la Cache di Laravel?

Laravel fornisce un’implementazione per il caching robusta e facile da usare, nonché diversi backend di caching. Con Laravel cache, potete passare in modo efficiente ed efficace tra molti motori di caching senza bisogno di scrivere codice.

Potete trovare la configurazione della cache di Laravel all’interno della cartella config/cache.php, anche se probabilmente avrete bisogno solo del file .env per passare tra diversi backend di cache.

Laravel cache fornisce anche molti metodi pratici che possiamo usare per implementare diverse strategie di caching.

Driver della Cache di Laravel e Confronti

Laravel cache fornisce ottimi backend e driver di caching. A seconda del vostro caso d’uso, potete passare da uno all’altro per migliorare le prestazioni dell’applicazione e il tempo di caricamento.

Detto questo, Laravel cache fornisce anche un modo efficace per creare un backend personalizzato e usarlo con Laravel cache, ma solo se l’elenco qui sotto non rientra tra i vostri casi d’uso.

In seguito parleremo di tutti i backend forniti da Laravel cache.

1. File

Il driver file è il backend predefinito usato dalla cache di Laravel quando nessun driver è specificato nel file .env.

Il backend file è progettato per memorizzare i dati in cache in un file criptato che si trova sotto storage/framework/. Laravel crea un file criptato con i dati e la chiave della cache quando vengono memorizzati nuovi dati. Lo stesso accade quando l’utente cerca di recuperare il contenuto. Laravel cache cerca nella cartella la chiave specificata e, se la trova, restituisce il contenuto.

Il backend file funziona perfettamente e fa risparmiare tempo nell’installazione e nella configurazione di driver esterni, ma può funzionare molto bene anche per lo sviluppo. È più veloce che accedere direttamente ai dati dal server del database.

Per usare il driver file, aggiungete il seguente codice al vostro file .env:

CACHE_DRIVER=file

2. Array

Il driver array è un backend di caching perfetto per l’esecuzione di test automatizzati e si configura facilmente con Github Actions, Jenkins, ecc.

Il backend array memorizza i dati in cache in un array in PHP e non richiede l’installazione o la configurazione di nessun driver. Funziona perfettamente per i test automatici ed è un po’ più veloce del backend della cache dei file.

Per usare il driver array, aggiungete il seguente codice al vostro file .env:

CACHE_DRIVER=array

3. Database

Quando usate il driver database, i dati sono salvati in memoria per il processo PHP corrente. Pertanto, è necessario creare una tabella di database per memorizzare i dati in cache. Inoltre, la cache del database migliora la scalabilità distribuendo il carico di lavoro delle query dal backend a più frontend.

Potete eseguire questo comando Artisan – php artisan cache:table – per generare automaticamente lo schema del database necessario al driver del database.

Il driver database si usa soprattutto in situazioni in cui è possibile installare qualsiasi software sulla piattaforma di hosting.

Per esempio, diciamo che state usando un piano di hosting gratuito con opzioni limitate. Per questo, vi suggeriamo di attenervi al driver file perché il driver database è, nella maggior parte dei casi, il punto più debole della vostra applicazione, e cercare di spingere più dati in quel collo di bottiglia non è una buona idea.

Per usare il driver database, aggiungete il seguente codice al vostro file .env:

CACHE_DRIVER=database

4. Redis

Il driver redis usa la tecnologia di cache basata sulla memoria chiamata Redis. Anche se è veloce rispetto agli altri driver di cache discussi sopra, richiede l’installazione e la configurazione di una tecnologia esterna.

Per usare il driver redis, aggiungete il seguente codice al vostro file .env:

CACHE_DRIVER=redis

5. Memcached

Memcached è noto per essere il più popolare in-memory-based cache-store. Se non vi dispiace fare un po’ di manutenzione extra del server (dover installare e mantenere servizi aggiuntivi), i driver di cache basati sulla memoria Memcached sono ottime opzioni.

L’utilizzo del driver memcached richiede l’installazione del pacchetto Memcached PECL.

Per usare il driver memcached, aggiungete il seguente codice al vostro file .env:

CACHE_DRIVER=memcached 

Il miglior driver di cache da usare e le prestazioni del driver di cache dipendono dal vostro progetto e dalla quantità di dati da recuperare.

Uso e Metodi della Cache di Laravel

Laravel cache fornisce molti metodi preziosi usati per implementare molte strategie di caching.

Di seguito elencheremo e spiegheremo i diversi metodi (classificati in base al loro caso d’uso):

  1. put()
  2. get()
  3. many()
  4. putMany()
  5. increment()
  6. decrement()
  7. forever()
  8. forget()
  9. flush()
  10. remember()
  11. rememberForever()

Memorizzazione della Cache

Memorizzare nuovi dati nella cache è molto semplice con i diversi metodi, ognuno dedicato a specifici casi d’uso.

1. Cache::put()

Questo metodo accetta tre parametri chiave: key, la durata (duration) e i dati (data) da mettere in cache.

Diamo un’occhiata a come usare Cache::put():

Cache::put(key, data, duration)

$post = Post::find(1);

Cache::put('post_1', $post, 20);

Il codice qui sopra metterà in cache il post con key unica per 20 secondi.

2. Cache::putMany()

Questo metodo memorizza un array di dati nella cache in una volta sola con la stessa durata. Accetta due parametri che sono data e seconds.

Diamo un’occhiata a come usare Cache::putMany():

Cache::putMany(data, duration) // syntax

$posts = Post::all();

Cache::putMany($posts, 20);
3. Cache::remember()

Questo è un altro modo eccellente per implementare la strategia cache Aside. Il metodo Cache::remember() accetta tre parametri, una chiave (key), i secondi (seconds) e la chiusura (closure) usata per recuperare i dati dal database se non vengono trovati.

Vediamo come usare Cache::remember():

Cache::remember(key, duration, closure) // syntax

Cache::remember('posts', 20, function(){
  return Post::all();
});

La cache di Laravel include anche il metodo Cache::rememberForever(), che non accetta il parametro seconds e memorizza i dati (data) per sempre.

4. Cache::forever()

Questo metodo memorizza i dati nel server di cache per sempre senza specificare alcuna durata. Potete implementarlo con il seguente codice:

Cache::forever(key, data)

$post = Post::find(1);

Cache::forever('post_1', $post);

Recuperare i Dati della Cache

I metodi di questa categoria recuperano dati dalla cache. Alcuni di questi metodi possono comportarsi diversamente a seconda che i dati vengano trovati o meno.

1. Cache::get()

Questo metodo recupera i dati dal server della cache con una chiave specifica. È possibile recuperare un elemento utilizzando il codice qui sotto:

Cache::get(key) // syntax

$posts = Cache::get('posts');
2. Cache::many()

Questo metodo è simile a Cache::putMany(). Viene utilizzato per recuperare un array di dati in cache in una volta sola, utilizzando un array delle chiavi memorizzate in cache. È possibile recuperare un array di cache usando il seguente codice:

Cache::many(keys) // syntax

const $keys = [
  'posts',
  'post_1',
  'post_2'
];

$posts = Cache::many($keys);
3. Cache::remember()

Potete usare questo metodo per recuperare i dati memorizzati nella cache, controllando il server della cache con la chiave fornita. Se i dati sono memorizzati nella cache, verranno recuperati. Altrimenti, verranno recuperati i dati dal server di database per poi memorizzarli in cache.

Questo metodo è lo stesso del metodo Cache::rememberForever() ma include un ulteriore parametro seconds nel metodo Cache::remember().

Rimozione di Elementi dalla Cache

I metodi di questa categoria sono usati per rimuovere elementi dalla cache e sono raggruppati per funzionalità.

1. Cache::forget()

Questo metodo rimuove un singolo elemento dalla cache con un parametro chiave specificato:

Cache::forget('key');
2. Cache::flush()

Questo metodo cancella tutti i motori di cache e tutti gli elementi memorizzati ovunque nella cache:

Cache::flush();

Aumentare o Diminuire i Valori della Cache

Potete regolare i valori di un valore intero memorizzato nella vostra cache usando, rispettivamente, i metodi increment e decrement:

Cache::increment('key');

Cache::increment('key', $amount);

Cache::decrement('key');

Cache::decrement('key', $amount);

Laravel cache include molti altri ottimi metodi che non abbiamo discusso sopra, ma quelli visti finora sono i più popolari. Per avere una panoramica di tutti i metodi, date un’occhiata alla documentazione ufficiale della cache di Laravel.

Spiegazione dei Comandi di Cache

Laravel fornisce dei comandi per rendere il lavoro con la cache di Laravel facile e veloce. Di seguito è riportato l’elenco di tutti i comandi e le loro funzionalità.

Cancellare la Cache di Laravel

Questo comando serve a cancellare la cache di Laravel prima che scada usando il terminale o la console. Per esempio, potete eseguire il seguente comando:

php artisan cache:clear

Cancellare la Cache di Route

Questo comando si usa per cancellare la cache di route della vostra applicazione Laravel. Per esempio, eseguite il seguente comando per cancellare la cache di route:

php artisan config:cache

Cancellare i File di Visualizzazione Compilata

Questo comando è usato per cancellare i file di visualizzazione compilata della vostra applicazione Laravel. Potete ottenerlo con il seguente comando:

php artisan view:clear

Tabella del Database

Quando si usa il driver database, è necessario creare uno schema di database chiamato cache per memorizzare i dati della cache. Potete anche usare il comando Artisan per generare una migrazione con lo schema appropriato:

php artisan cache:table

Strategie di Caching di Laravel

A seconda del caso d’uso dell’applicazione e della struttura dei dati, sono probabilmente disponibili diverse strategie di cache. Potete anche creare una strategia personalizzata per soddisfare le vostre esigenze. Ora vedremo l’elenco delle strategie di caching popolari che potete implementare nel vostro progetto Laravel.

writeThrough

Nella strategia writeThrough, il server di cache si trova tra le richieste e il server di database, facendo passare ogni operazione di scrittura attraverso il server di cache prima di andare al server di database. Quindi, la strategia di caching writeThrough è simile alla strategia readThrough.

Potete usare il seguente codice per implementare questa strategia con la cache di Laravel:

public function writeThrough($key, $data, $minutes) {
    $cacheData = Cache::put($key, $data, $minutes)

    // Database Server is called from(after) the Cache Server.
    $this->storeToDB($cachedData)
    return $cacheData
}

private function storeToDB($data){
    Database::create($data)
    return true
}

writeBack (writeBehind)

Questa strategia è un modo più avanzato di implementare la strategia writeThrough aggiungendo ritardi nelle operazioni di scrittura.

Si può anche chiamare questa strategia writeBehind a causa del ritardo temporale applicato al server della cache prima che vengano scritti i dati al server di database.

Potete usare il seguente codice per implementare questa strategia con la cache di Laravel:

$durationToFlush = 1; // (in minute)
 $tempDataToFlush = [];

  public function writeBack($key, $data, $minutes){
    return $this->writeThrough($key, $data, $minutes);
  }

  public function writeThrough($key, $data, $minutes) {
      $cacheData = Cache::put($key, $data, $minutes);
      $this->storeForUpdates($cacheData);
      return $cacheData;
  }

// Stores new data to temp Array for updating
  private function storeForUpdates($data){
    $tempData = {};
    $tempData['duration'] = this.getMinutesInMilli();
    $tempData['data'] = data;
    array_push($tempDataToFlush, data);
  }

// Converts minutes to millisecond
private function getMinutesInMilli(){
  $currentDate = now();
  $futureDate = Carbon(Carbon::now()->timestamp + $this->durationToFlush * 60000)
  return $futureDate->timestamp
}

// Calls to update the Database Server.
public function updateDatabaseServer(){
  if($this->tempDataToFlush){
    foreach($this->tempDataToFlush as $index => $obj){
      if($obj->duration timestamp){
        if(Database::create($obj->data)){
            array_splice($this->tempDataToFlush, $index, 1);
        }
      }
    }
  }
}

Il metodo writeBack richiama il metodo writeThrough, che memorizza i dati sul server della cache e su un array temporaneo da spingere successivamente sul server di database tramite il metodo updateDatabaseServer. È possibile impostare un CronJob per aggiornare il server di database ogni cinque minuti.

writeAround

Questa strategia permette a tutte le operazioni di scrittura di andare direttamente al server di database senza aggiornare il server di cache: solo durante le operazioni di lettura (read) il server di cache viene aggiornato.

Supponiamo che un utente voglia creare un nuovo articolo (Article): Article viene memorizzato direttamente sul server di database. Quando l’utente vuole leggere il contenuto di Article per la prima volta, questo viene recuperato dal server di database e aggiorna il server di cache per le richieste successive.

Potete implementare questa strategia con la cache di Laravel usando il seguente codice:

public function writeAround($data) {
    $storedData = Database::create($data);
    return $storedData;
}

public function readOperation($key, $minutes){
    $cacheData = Cache::remember($key, $minutes, function() {
      return Article::all();
    })
    return $cacheData;
}

Cache Aside (Lazy Loading)

In questa strategia il database viene messo da parte e l’applicazione richiede prima i dati dal server di cache. Poi, se c’è un hit (found), i dati vengono restituiti al client. Altrimenti, se c’è un miss (not found), il server di database richiede i dati e aggiorna il server di cache per le richieste successive.

Potete implementare questa strategia con la cache di Laravel tramite il seguente codice:

public function lazyLoadingStrategy($key, $minutes, $callback) {
  if (Cache::has($key)) {
      $data = Cache::get($key);
      return $data;
  } else {
      // Database Server is called outside the Cache Server.
      $data = $callback();
      Cache::set($key, $data, $minutes);
      return $data;
  }
}

Il codice qui sopra mostra l’implementazione della cache Aside Strategy, che è equivalente all’implementazione del metodo Cache::remember.

Read Through

Questa strategia è il diretto opposto della strategia di cache Aside. In questa strategia, il server di cache si trova tra la richiesta del client e il server di database.

Le richieste vanno direttamente al server di cache: questo è responsabile del recupero dei dati dal server di database se non vengono trovati nel server di cache.

Potete implementare questa strategia con la cache di Laravel tramite il seguente codice:

public function readThrough($key, $minutes) {
      $data = Cache::find($key, $minutes);
      return $data;
}

private function find($key, $minutes){
    if(Cache::has($key);){
      return Cache::get($key);
    }

    // Database Server is called from the Cache Server.
    $DBdata = Database::find($key);
    Cache:put($key, $DBdata, $minutes);
    return $DBdata;
}

Ecco fatto! Ora abbiamo discusso alcune strategie di caching popolari per la vostra prossima applicazione Laravel. Ricordate: potete anche usare una strategia di caching personalizzata che meglio si adatta ai requisiti del vostro progetto.

Caching della Interfaccia Utente di un’Applicazione Laravel

Il caching dell’interfaccia utente della nostra app Laravel è un concetto noto come Full Page cache FPC. Il termine si riferisce al processo di caching della risposta HTML di un’applicazione.

È eccellente per le applicazioni in cui i dati HTML dinamici non cambiano frequentemente. È possibile memorizzare nella cache la risposta HTML e ottenere così una risposta complessiva e un rendering più veloce dell’HTML.

Possiamo implementare FPC con la seguente linea di codice:

class ArticlesController extends Controller {
    public function index() {
        if ( Cache::has('articles_index') ) {
            return Cache::get('articles_index');
        } else {
            $news = News::all();
            $cachedData = view('articles.index')->with('articles', $news)->render();
            Cache::put('articles_index', $cachedData);                                         
            return $cachedData;           
        }  
    }
}

A prima vista, potreste aver notato che controlliamo se la pagina articles_index esiste già nel nostro server di cache. Poi restituiamo la pagina renderizzandola con i metodi view() e render() di Laravel.

Altrimenti, renderizziamo la pagina e memorizziamo l’output nel nostro server cache per le richieste successive prima di restituire la pagina renderizzata al browser.

Costruire un’Applicazione Laravel

Ora applicheremo ciò che abbiamo imparato finora creando un nuovo progetto Laravel e implementando la cache Laravel.

Se non avete mai usato Laravel, potete leggere cos’è Laravel e dare un’occhiata alla nostra lista con eccellenti tutorial su Laravel, utili per iniziare.

Impostazione di Laravel

Per prima cosa, creeremo una nuova istanza di Laravel usando il seguente comando. Potete consultare la documentazione ufficiale per saperne di più.

Aprite la vostra console e navigate fino al punto in cui memorizzate i vostri progetti PHP prima di eseguire i comandi qui sotto. Verificate di avere Composer installato e configurato correttamente.

composer create-project laravel/laravel fast-blog-app

// Change directory to current Laravel installation
cd fast-blog-app

// Start Laravel development server.
php artisan serve

Configurazione e Seeding del Database

Successivamente, imposteremo il nostro database, creeremo un nuovo modello di Article e faremo un seeding di 500 data point falsi per i test.

Aprite il vostro client di database e create un nuovo database. Faremo lo stesso con il nome fast_blog_app_db e poi riempiremo il nostro file .env con le credenziali del database:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=fast_blog_app_db
DB_USERNAME=//DB USERNAME HERE
DB_PASSWORD=//DB PASSWORD HERE

In seguito, eseguiremo il seguente comando per creare simultaneamente la migrazione e il modello di Article:

php artisan make:model Article -m

Aprite la migrazione appena creata che è stata trovata database/migrations/xxx-create-articles-xxx.php, e incollate il seguente codice:

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('description');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

Poi, eseguite il comando qui sotto per creare un nuovo seeder:

php artisan make:seeder ArticleSeeder

Aprite il file seeder appena creato che si trova in database/seeders/ArticleSeeder.php e incollate il seguente codice:

<?php
namespace Database\Seeders;
use App\Models\Article;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Article::factory()->count(500)->create();
    }
}

Aprite il file DatabaseSeeder.php nella stessa directory e aggiungete il seguente codice:

<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(ArticleSeeder::class);
    }
}

Poi, eseguite il comando seguente per creare una nuova factory:

php artisan make:factory ArticleFactory

Aprite il file factory appena costruito che si trova in database/factories/ArticleFactory.php e incollate il seguente codice:

<?php
namespace Database\Factories;
use App\Models\Article;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Article::class;
    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'title' => $this->faker->text(),
            'description' => $this->faker->paragraph(20)
        ];
    }
}

Ora, eseguite il comando qui sotto per migrare lo schema che abbiamo appena creato e anche per fare seed dei nostri dati falsi per i test:

php artisan migrate --seed

Creare il Controller dell’Articolo

Successivamente, creeremo il nostro controller e imposteremo le route per gestire la nostra richiesta e recuperare i dati utilizzando il modello di cui sopra.

Eseguite il seguente comando per creare un nuovo ArticlesController all’interno della cartella app/Http/Controllers:

php artisan make:controller ArticlesController --resource

Aprite il file e aggiungete il seguente codice alla classe:

// Returns all 500 articles with Caching
public function index() {
  return Cache::remember('articles', 60, function () {
      return Article::all();
  });
}

// Returns all 500 without Caching
public function allWithoutCache() {
  return Article::all();
}

Dopo di che, aprite il file api.php che si trova all’interno della cartella routes/ e incollate il seguente codice per creare un endpoint da richiamare per recuperare i nostri dati:

Route::get('/articles', 'ArticlesController@index');

Route::get('/articles/withoutcache', 'ArticlesController@allWithoutcache');

Test delle Prestazioni

Infine, testeremo le prestazioni della risposta della nostra app con o senza l’implementazione della cache di Laravel.

Questa schermata mostra il tempo di risposta dell’API con la cache implementata:

Tempo di risposta di Laravel API con la cache.
Tempo di risposta di Laravel API con la cache.

Il seguente screenshot mostra il tempo di risposta dell’API senza cache implementata: notate che il tempo di risposta è aumentato rispetto all’istanza nella cache di oltre il 5.000%:

Tempo di risposta di Laravel API senza cache.
Tempo di risposta di Laravel API senza cache.

Riepilogo

Abbiamo esplorato varie strategie per implementare e manipolare il caching di Laravel costruendo un nuovo progetto, facendo il benchmarking delle sue risposte e confrontando i risultati.

Avete anche imparato a usare i diversi driver e metodi di caching di Laravel. Inoltre, abbiamo implementato diverse strategie di caching per aiutarvi a capire quale potrebbe essere quella giusta per voi.

Per saperne di più su Laravel, date un’occhiata alla nostra selezione dei migliori tutorial su Laravel. Che voi siate principianti o abbiate esperienza nello sviluppo di Laravel, abbiamo qualcosa per voi!

Se avete ancora domande sul caching di Laravel, fatecelo sapere nella sezione dei commenti.

Solomon Eseme

I am a Software Engineer and Content Creator who is geared toward building high-performing and innovative products following best practices and industry standards. I also love writing about it at Masteringbackend.com. Follow me on Twitter, LinkedIn, and About Me