Documentación de Laravel 10.x
Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.
Algunas de las tareas de recuperación o procesamiento de datos realizadas por tu aplicación podrían ser intensivas en CPU o llevar varios segundos en completarse. Cuando este sea el caso, es común almacenar en caché los datos recuperados durante un tiempo para poder recuperarlos rápidamente en solicitudes posteriores para los mismos datos. Los datos en caché generalmente se almacenan en un almacén de datos muy rápido como Memcached o Redis.
Afortunadamente, Laravel proporciona una API expresiva y unificada para varios backends de caché, lo que te permite aprovechar su rápida recuperación de datos y acelerar tu aplicación web.
El archivo de configuración de caché de tu aplicación se encuentra en config/cache.php
. En este archivo, puedes especificar qué controlador de caché te gustaría usar de forma predeterminada en toda tu aplicación. Laravel es compatible con backends de caché populares como Memcached, Redis, DynamoDB y bases de datos relacionales. Además, hay disponible un controlador de caché basado en archivos, mientras que los controladores de caché array
y "null" proporcionan backends de caché convenientes para tus pruebas automatizadas.
El archivo de configuración de caché también contiene varias otras opciones, que se documentan dentro del archivo, así que asegúrate de leer estas opciones. De forma predeterminada, Laravel está configurado para usar el controlador de caché file
, que almacena objetos serializados en el sistema de archivos del servidor. Para aplicaciones más grandes, se recomienda que uses un controlador más robusto como Memcached o Redis. Incluso puedes configurar múltiples configuraciones de caché para el mismo controlador.
Al usar el controlador de caché database
, deberás configurar una tabla para contener los elementos de caché. Encontrarás un ejemplo de declaración de Schema
para la tabla a continuación:
Schema::create('cache', function (Blueprint $table) { $table->string('key')->unique(); $table->text('value'); $table->integer('expiration');});
Nota También puedes usar el comando Artisan
php artisan cache:table
para generar una migración con el esquema adecuado.
Para usar el controlador Memcached, es necesario instalar el paquete Memcached PECL. Puedes listar todos tus servidores Memcached en el archivo de configuración config/cache.php
. Este archivo ya contiene una entrada memcached.servers
para comenzar:
'memcached' => [ 'servers' => [ [ 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 'port' => env('MEMCACHED_PORT', 11211), 'weight' => 100, ], ],],
Si es necesario, puedes establecer la opción host
en la ruta del socket UNIX. Si haces esto, la opción port
debe establecerse en 0
:
'memcached' => [ [ 'host' => '/var/run/memcached/memcached.sock', 'port' => 0, 'weight' => 100 ],],
Antes de usar una caché Redis con Laravel, deberás instalar la extensión PHP PhpRedis a través de PECL o instalar el paquete predis/predis
(~1.0) a través de Composer. Laravel Sail ya incluye esta extensión. Además, las plataformas oficiales de implementación de Laravel, como Laravel Forge y Laravel Vapor, tienen instalada la extensión PhpRedis por defecto.
Para obtener más información sobre la configuración de Redis, consulta su página de documentación de Laravel.
Antes de usar el controlador de caché DynamoDB, debes crear una tabla DynamoDB para almacenar todos los datos en caché. Normalmente, esta tabla debería llamarse cache
. Sin embargo, debes nombrar la tabla según el valor de la configuración stores.dynamodb.table
dentro del archivo de configuración cache
de tu aplicación.
Esta tabla también debe tener una clave de partición de cadena con un nombre que coincida con el valor de stores.dynamodb.attributes.key
en la configuración de caché de tu aplicación. Por defecto, la clave de partición debería llamarse key
.
Para obtener una instancia de almacenamiento en caché, puedes utilizar el facade Cache
, que es lo que usaremos en toda esta documentación. El facade Cache
proporciona un acceso conveniente y conciso a las implementaciones subyacentes de los contratos de caché de Laravel:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Cache; class UserController extends Controller{ /** * Mostrar una lista de todos los usuarios de la aplicación. */ public function index(): array { $value = Cache::get('key'); return [ // ... ]; }}
Usando el facade Cache
, puedes acceder a varios almacenes de caché a través del método store
. La clave pasada al método store
debe corresponder a uno de los almacenes enumerados en la matriz de configuración stores
en tu archivo de configuración cache
:
$value = Cache::store('file')->get('foo'); Cache::store('redis')->put('bar', 'baz', 600); // 10 minutos
El método get
del facade Cache
se utiliza para recuperar elementos de la caché. Si el elemento no existe en la caché, se devolverá null
. Si lo deseas, puedes pasar un segundo argumento al método get
especificando el valor predeterminado que deseas que se devuelva si el elemento no existe:
$value = Cache::get('key'); $value = Cache::get('key', 'default');
Incluso puedes pasar una clausura como valor predeterminado. El resultado de la clausura se devolverá si el elemento especificado no existe en la caché. Pasar una clausura te permite posponer la recuperación de valores predeterminados desde una base de datos u otro servicio externo:
$value = Cache::get('key', function () { return DB::table(/* ... */)->get();});
El método has
se puede utilizar para determinar si un elemento existe en la caché. Este método también devolverá false
si el elemento existe pero su valor es null
:
if (Cache::has('key')) { // ...}
Los métodos increment
y decrement
se pueden utilizar para ajustar el valor de elementos enteros en la caché. Ambos métodos aceptan un segundo argumento opcional que indica la cantidad en la que se debe incrementar o decrementar el valor del elemento:
// Inicializar el valor si no existe...Cache::add('key', 0, now()->addHours(4)); // Incrementar o decrementar el valor...Cache::increment('key');Cache::increment('key', $amount);Cache::decrement('key');Cache::decrement('key', $amount);
A veces, puedes desear recuperar un elemento de la caché, pero también almacenar un valor predeterminado si el elemento solicitado no existe. Por ejemplo, puedes desear recuperar todos los usuarios de la caché o, si no existen, recuperarlos de la base de datos y agregarlos a la caché. Puedes hacer esto utilizando el método Cache::remember
:
$value = Cache::remember('users', $seconds, function () { return DB::table('users')->get();});
Si el elemento no existe en la caché, se ejecutará la clausura pasada al método remember
y su resultado se colocará en la caché.
Puedes usar el método rememberForever
para recuperar un elemento de la caché o almacenarlo para siempre si no existe:
$value = Cache::rememberForever('users', function () { return DB::table('users')->get();});
Si necesitas recuperar un elemento de la caché y luego eliminar el elemento, puedes usar el método pull
. Al igual que el método get
, se devolverá null
si el elemento no existe en la caché:
$value = Cache::pull('key');
Puedes usar el método put
en el facade Cache
para almacenar elementos en la caché:
Cache::put('key', 'value', $seconds = 10);
Si no se pasa el tiempo de almacenamiento al método put
, el elemento se almacenará indefinidamente:
Cache::put('key', 'value');
En lugar de pasar el número de segundos como un entero, también puedes pasar una instancia de DateTime
que represente el tiempo de vencimiento deseado del elemento almacenado en caché:
Cache::put('key', 'value', now()->addMinutes(10));
El método add
solo agregará el elemento a la caché si aún no existe en el almacén de caché. El método devolverá true
si el elemento se agrega realmente a la caché. De lo contrario, el método devolverá false
. El método add
es una operación atómica:
Cache::add('key', 'value', $seconds);
El método forever
se puede utilizar para almacenar un elemento en la caché permanentemente. Dado que estos elementos no expirarán, deben eliminarse manualmente de la caché utilizando el método forget
:
Cache::forever('key', 'value');
Nota Si estás utilizando el controlador Memcached, los elementos almacenados "para siempre" pueden eliminarse cuando la caché alcanza su límite de tamaño.
Puedes eliminar elementos de la caché utilizando el método forget
:
Cache::forget('key');
También puedes eliminar elementos proporcionando un número de segundos de expiración cero o negativo:
Cache::put('key', 'value', 0); Cache::put('key', 'value', -5);
Puedes borrar toda la caché utilizando el método flush
:
Cache::flush();
Advertencia Vaciar la caché no respeta tu "prefijo" de caché configurado y eliminará todas las entradas de la caché. Considera esto cuidadosamente al borrar una caché que es compartida por otras aplicaciones.
Además de utilizar el facade Cache
, también puedes usar la función global cache
para recuperar y almacenar datos a través de la caché. Cuando se llama a la función cache
con un solo argumento de tipo cadena, devolverá el valor de la clave proporcionada:
$value = cache('key');
Si proporcionas una matriz de pares clave/valor y un tiempo de vencimiento a la función, almacenará los valores en la caché durante la duración especificada:
cache(['key' => 'value'], $seconds); cache(['key' => 'value'], now()->addMinutes(10));
Cuando se llama a la función cache
sin argumentos, devuelve una instancia de la implementación de Illuminate\Contracts\Cache\Factory
, lo que te permite llamar a otros métodos de caché:
cache()->remember('users', $seconds, function () { return DB::table('users')->get();});
Nota Cuando estás probando la llamada a la función global
cache
, puedes usar el métodoCache::shouldReceive
de la misma manera que si estuvieras probando el facade.
Advertencia Para utilizar esta función, tu aplicación debe estar utilizando el controlador de caché predeterminado
memcached
,redis
,dynamodb
,database
,file
oarray
. Además, todos los servidores deben comunicarse con el mismo servidor central de caché.
Al usar el controlador de caché database
, deberás configurar una tabla para contener los bloqueos de caché de tu aplicación. Encontrarás un ejemplo de declaración de Schema
para la tabla a continuación:
Schema::create('cache_locks', function (Blueprint $table) { $table->string('key')->primary(); $table->string('owner'); $table->integer('expiration');});
Nota Si utilizaste el comando Artisan
cache:table
para crear la tabla de caché del controlador de la base de datos, la migración creada por ese comando ya incluye una definición para la tablacache_locks
.
Los bloqueos atómicos permiten la manipulación de bloqueos distribuidos sin preocuparse por las condiciones de carrera. Por ejemplo, Laravel Forge utiliza bloqueos atómicos para asegurarse de que solo se esté ejecutando una tarea remota en un servidor en un momento dado. Puedes crear y gestionar bloqueos utilizando el método Cache::lock
:
use Illuminate\Support\Facades\Cache; $lock = Cache::lock('foo', 10); if ($lock->get()) { // Bloqueo adquirido durante 10 segundos... $lock->release();}
El método get
también acepta una clausura. Después de que se ejecute la clausura, Laravel liberará automáticamente el bloqueo:
Cache::lock('foo', 10)->get(function () { // Bloqueo adquirido durante 10 segundos y liberado automáticamente...});
Si el bloqueo no está disponible en el momento en que lo solicitas, puedes indicarle a Laravel que espere durante un número especificado de segundos. Si no se puede adquirir el bloqueo dentro del límite de tiempo especificado, se lanzará una Illuminate\Contracts\Cache\LockTimeoutException
:
use Illuminate\Contracts\Cache\LockTimeoutException; $lock = Cache::lock('foo', 10); try { $lock->block(5); // Bloqueo adquirido después de esperar un máximo de 5 segundos...} catch (LockTimeoutException $e) { // No se pudo adquirir el bloqueo...} finally { $lock?->release();}
El ejemplo anterior se puede simplificar pasando una clausura al método block
. Cuando se pasa una clausura a este método, Laravel intentará adquirir el bloqueo durante el número especificado de segundos y automáticamente liberará el bloqueo una vez que se haya ejecutado la clausura:
Cache::lock('foo', 10)->block(5, function () { // Bloqueo adquirido después de esperar un máximo de 5 segundos...});
A veces, puedes querer adquirir un bloqueo en un proceso y liberarlo en otro proceso. Por ejemplo, puedes adquirir un bloqueo durante una solicitud web y desear liberar el bloqueo al final de un trabajo en cola que es activado por esa solicitud. En este escenario, debes pasar el "token de propietario" del bloqueo al trabajo en cola para que el trabajo pueda reinstantáneo el bloqueo usando el token dado.
En el ejemplo a continuación, despacharemos un trabajo en cola si se adquiere el bloqueo correctamente. Además, pasaremos el "token de propietario" del bloqueo al trabajo en cola mediante el método owner
del bloqueo:
$podcast = Podcast::find($id); $lock = Cache::lock('processing', 120); if ($lock->get()) { ProcessPodcast::dispatch($podcast, $lock->owner());}
Dentro del trabajo ProcessPodcast
de nuestra aplicación, podemos restaurar y liberar el bloqueo usando el token de propietario:
Cache::restoreLock('processing', $this->owner)->release();
Si deseas liberar un bloqueo sin respetar a su propietario actual, puedes usar el método forceRelease
:
Cache::lock('processing')->forceRelease();
Para crear nuestro controlador de caché personalizado, primero debemos implementar el contrato Illuminate\Contracts\Cache\Store
. Entonces, una implementación de caché de MongoDB podría verse algo así:
<?php namespace App\Extensions; use Illuminate\Contracts\Cache\Store; class MongoStore implements Store{ public function get($key) {} public function many(array $keys) {} public function put($key, $value, $seconds) {} public function putMany(array $values, $seconds) {} public function increment($key, $value = 1) {} public function decrement($key, $value = 1) {} public function forever($key, $value) {} public function forget($key) {} public function flush() {} public function getPrefix() {}}
Solo necesitamos implementar cada uno de estos métodos utilizando una conexión de MongoDB. Para ver un ejemplo de cómo implementar cada uno de estos métodos, echa un vistazo a Illuminate\Cache\MemcachedStore
en el código fuente del framework Laravel. Una vez que nuestra implementación esté completa, podemos finalizar el registro de nuestro controlador de forma llamando al método extend
del facade Cache
:
Cache::extend('mongo', function (Application $app) { return Cache::repository(new MongoStore);});
Nota Si te preguntas dónde poner tu código personalizado del controlador de caché, podrías crear un espacio de nombres
Extensions
dentro de tu directorioapp
. Sin embargo, ten en cuenta que Laravel no tiene una estructura de aplicación rígida y eres libre de organizar tu aplicación según tus preferencias.
Para registrar el controlador de caché personalizado con Laravel, utilizaremos el método extend
en el facade Cache
. Dado que otros proveedores de servicios pueden intentar leer valores en caché dentro de su método boot
, registraremos nuestro controlador personalizado dentro de un callback booting
. Al usar el callback booting
, podemos asegurarnos de que el controlador personalizado se registre justo antes de que se llame al método boot
en los proveedores de servicios de nuestra aplicación, pero después de que se llame al método register
en todos los proveedores de servicios. Registraremos nuestro callback booting
dentro del método register
de la clase App\Providers\AppServiceProvider
de la aplicación:
<?php namespace App\Providers; use App\Extensions\MongoStore;use Illuminate\Contracts\Foundation\Application;use Illuminate\Support\Facades\Cache;use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider{ /** * Registrar cualquier servicio de la aplicación. */ public function register(): void { $this->app->booting(function () { Cache::extend('mongo', function (Application $app) { return Cache::repository(new MongoStore); }); }); } /** * Inicializar cualquier servicio de la aplicación. */ public function boot(): void { // ... }}
El primer argumento pasado al método extend
es el nombre del controlador. Esto corresponderá a tu opción driver
en el archivo de configuración config/cache.php
. El segundo argumento es una clausura que debe devolver una instancia de Illuminate\Cache\Repository
. La clausura recibirá una instancia $app
, que es una instancia del contenedor de servicios.
Una vez que tu extensión esté registrada, actualiza la opción driver
del archivo de configuración config/cache.php
con el nombre de tu extensión.
Para ejecutar código en cada operación de caché, puedes escuchar los eventos emitidos por la caché. Por lo general, deberías colocar estos escuchadores de eventos dentro de la clase App\Providers\EventServiceProvider
de tu aplicación:
use App\Listeners\LogCacheHit;use App\Listeners\LogCacheMissed;use App\Listeners\LogKeyForgotten;use App\Listeners\LogKeyWritten;use Illuminate\Cache\Events\CacheHit;use Illuminate\Cache\Events\CacheMissed;use Illuminate\Cache\Events\KeyForgotten;use Illuminate\Cache\Events\KeyWritten; /** * Las asignaciones de escuchadores de eventos para la aplicación. * * @var array */protected $listen = [ CacheHit::class => [ LogCacheHit::class, ], CacheMissed::class => [ LogCacheMissed::class, ], KeyForgotten::class => [ LogKeyForgotten::class, ], KeyWritten::class => [ LogKeyWritten::class, ],];