Cache::extend() es el método de creación, y Laravel no envuelve automáticamente en un Repository el Store que devuelvas.
Esta página se basa en la revisión de la implementación de Laravel Framework v13.39.0. Para las operaciones básicas, consulta Caché, y para preparar el provider, Desarrollo de paquetes.
Separa el nombre del driver del nombre del store
Si existe un creador personalizado para el
driver de la configuración, CacheManager::build() lo llama antes que a los drivers integrados. No reutilices nombres como redis o array; usa un nombre propio del paquete.
Regístralo antes del boot de otros providers
Si otro paquete usa la caché en suboot(), registrar el driver en tu propio boot() puede llegar tarde según el orden. Siguiendo la documentación oficial, registra en register() un callback booting de la aplicación.
El siguiente es un ejemplo mínimo que usa el ArrayStore estándar para comprobar el flujo de registro sin servicios externos. Colócalo en src/MemoServiceProvider.php del paquete Acme\Memo.
- El
bootingde la aplicación se ejecuta, en un arranque normal, después de que terminen losregister()de todos los providers y antes de cadaboot(). Es distinto del$this->booting()del propio provider. - El callback de
extend()recibe la aplicación y el array de configuración del store. Coloca la generación del Store y las conexiones externas en este callback de creación. - Este momento de registro no garantiza el uso de la caché dentro del
register()de otros providers. Separa el registro de servicios de su uso real.
CacheManager::extend() vuelve a enlazar el ámbito del closure anónimo al Manager. No asumas que $this en un closure no estático es el provider; usa, como en el ejemplo, un closure estático y el argumento $app.
Añade el store a la aplicación que usa el paquete
Añádelo al arraystores existente de config/cache.php. No diseñes el paquete para que sobrescriba el default ni todo el array stores de la aplicación.
CACHE_STORE es también el nombre del store, catalog, no el nombre del driver. Si creas varias configuraciones con el mismo driver, se genera un Repository distinto para cada nombre de store.
Construye el Repository tú mismo
CacheManager::callCustomCreator() devuelve tal cual el valor de retorno del callback. Si devuelves solo el Store, aunque get() y put() funcionen, no podrás usar remember() y otros métodos del Repository, y la interpretación del TTL también cambia.
El repository($store, $config) del ejemplo se encarga de lo siguiente:
- Envuelve el Store con
Illuminate\Cache\Repository. - Pasa al Repository el nombre
storeque el Manager añadió a la configuración. - Si hay un Dispatcher de eventos registrado y la opción
eventsno está desactivada, asigna el Dispatcher al Repository.
serialize, que el ejemplo lee de la configuración.
Contrasta el contrato Store con la implementación actual
Implementa los métodos que exigeIlluminate\Contracts\Cache\Store en Laravel 13. No distribuyas como driver funcional una lista de métodos vacíos copiada de ejemplos antiguos.
El Repository trata
null como un fallo de caché. Implementa el Store de forma que false o 0 no se traten como inexistentes. Guardar null no sirve como marca para evitar que remember() vuelva a calcular el valor.
Verifica el TTL a través del Repository
Repository::put() procesa el TTL antes de pasarlo al Store.
Comprueba por separado add, locks y etiquetas
Implementar el contrato Store no garantiza por sí solo la compatibilidad con todas las funciones de la caché.add()atómico: no forma parte del contrato Store. Si se llama con un TTL positivo y el Store tieneadd(), el Repository lo usa. Si no, recurre aget()yput(), así que envolverlo en un Repository no garantiza la atomicidad. En backends compartidos, impleméntalo con las operaciones atómicas de ese backend y verifica también la ejecución concurrente.- Locks:
lock()yrestoreLock()deIlluminate\Contracts\Cache\LockProviderson un contrato aparte. Verifica la adquisición, la coincidencia del propietario, la expiración y que no se liberen locks de otros propietarios. Los locks delArrayStoredel ejemplo no proporcionan exclusión mutua entre procesos distintos. - Etiquetas: el Repository comprueba si el Store tiene
tags(). Por lo general se necesita una implementación basada enTaggableStoreu otra similar, y no se activan automáticamente solo con el contrato Store.
flush() es un borrado parcial que respeta el prefix de la configuración. Comprueba el alcance del borrado en backends compartidos y explícalo a los usuarios, incluido php artisan cache:clear.
Distingue la retención de instancias del borrado de datos
CacheManager es un singleton, y también retiene el resultado de store('catalog') por nombre de store. Cambiar la configuración o volver a registrar extend() no actualiza los Repository ya generados.
$same es el mismo objeto que $before. Al obtenerlo después de forgetDriver(), $after se genera a partir de la nueva configuración.
forgetDriver() no borra todo el backend. Sin embargo, como el ArrayStore del ejemplo guarda los datos dentro de la instancia, el nuevo Store no ve los datos antiguos. Además, no se sustituyen el $before del código que lo usa ni las referencias al Repository antiguo que retiene el singleton cache.store ya resuelto.
En producción, actualiza la caché de configuración siguiendo el despliegue habitual y reinicia los workers de larga duración. Ten en cuenta también el ciclo de vida de los servicios, y no trates la nueva resolución como una actualización simultánea de todos los procesos.
Prueba el flujo de creación, no solo mocks de facades
En el entorno de pruebas del paquete, pasa por el Manager y el Repository reales. El siguiente ejemplo de Testbench comprueba que el driver también puede usarse desde elboot() de otro provider registrado antes. En el ejemplo se guarda un array sin cambiar la restricción de restauración de cache.serializable_classes, y se comprueba también el valor guardado en bruto con ArrayStore::all(false).
many(), el ida y vuelta de false y 0, touch(), los fallos de conexión, las actualizaciones concurrentes, y el prefix y el alcance del borrado. Que un simple Cache::shouldReceive('get') tenga éxito no es prueba del registro del driver ni de la compatibilidad con servicios externos.
Lista de comprobación para el mantenimiento a largo plazo
- Haz que el nombre del driver, la configuración del store, el formato de serialización, las excepciones y los valores de retorno en caso de fallo formen parte de la especificación pública.
- Comprueba los métodos del contrato Store y las funciones opcionales, como etiquetas y locks, para cada versión de Laravel compatible.
- Verifica que el driver se registra incluso en un arranque nuevo con la caché de configuración activa, y que puede usarse desde el
boot()de otros providers. - Al anunciar cambios de compatibilidad en los datos guardados, incluye la política de migración o descarte de las claves existentes.
- Distingue la retención de instancias dentro del proceso, los datos del backend y la caché de configuración.
Fuentes primarias consultadas
- Documentación oficial de Laravel: drivers de caché personalizados
- CacheManager: build, repository, extend y forgetDriver
- Repository: conversión del TTL, add, tags y eventos
- Contrato Store / Contrato LockProvider
- ArrayStore: almacenamiento, expiración y serialización
- CacheServiceProvider: registro singleton del Manager y de cache.store
- Application: booting de la aplicación y boot de los providers
- Pruebas oficiales de Laravel: CacheManagerTest / CacheRepositoryTest