v13.39.0. Para las operaciones básicas, consulta Sesión, y para la carga automática de providers, Descubrimiento de paquetes.
extend recibe un handler, no un Store
El callback deSession::extend() devuelve un handler de almacenamiento que implementa la SessionHandlerInterface de PHP. No es una API para devolver directamente un Store que implemente Illuminate\Contracts\Session\Session ni un Repository de caché.
SessionManager::callCustomCreator() pasa el valor devuelto por el callback a buildSession(), que lo envuelve en un Store o en un EncryptedStore según session.encrypt. En ese momento también aplica el nombre de la cookie y session.serialization.
En el procesamiento HTTP habitual, el middleware StartSession gestiona el inicio y el guardado de la sesión. Para ofrecer un handler, tu paquete no necesita llamar a session_start() ni a session_set_save_handler().
Considera el contrato de almacenamiento por partes
Si implementas tu propio backend, cumple las siguientes funciones.
Como el
Store se encarga de la serialización y la restauración, el handler no debe volver a aplicar serialize() ni json_encode() al array de la sesión. Con el cifrado activado, guarda tal cual la cadena procesada por EncryptedStore.
Registra solo la lógica de creación en boot
El siguiente ejemplo mínimo reutiliza elCacheBasedSessionHandler integrado. No implementa un nuevo protocolo de almacenamiento, sino que muestra cómo registrar un driver propio que usa un store de caché con nombre. Acme\SessionBridge\ corresponde a src/ mediante PSR-4 de Composer.
Crea el provider en src/SessionBridgeServiceProvider.php.
Session::extend() obtiene el SessionManager y registra la lógica de creación, pero en ese momento todavía no resuelve el store de caché del callback. El almacenamiento se crea cuando ese driver se selecciona por primera vez. No ejecutes comprobaciones de conexión ni guardes datos en el boot() del provider.
Si usas tu propia implementación de SessionHandlerInterface, sustituye el handler que devuelve el callback. Si llegas a hacer new Store(...), el valor devuelto deja de coincidir con lo que espera el SessionManager.
- Carga el provider como un provider normal, no diferido.
- Completa el registro antes de que la sesión se use por primera vez. Si otro provider resuelve tu driver antes, revisa también el orden de carga.
- Usa un nombre de driver propio del paquete. Un
extend()con el mismo nombre sobrescribe la lógica de creación, y registrar el nombre de un driver integrado tiene prioridad sobre la implementación integrada.
La aplicación consumidora lo selecciona explícitamente
Los usuarios cambian las claves correspondientes de suconfig/session.php existente y conservan el resto de la configuración.
stores existente de config/cache.php. El siguiente ejemplo usa la conexión Redis default. La aplicación se encarga de preparar la configuración de conexión de Redis y el cliente necesario.
createRedisDriver() del driver de sesión Redis integrado, añadir session.connection o session.prefix no hace que este callback los aplique automáticamente.
Este callback no modifica el Repository ni la configuración del almacenamiento; usa el store con nombre tal cual. Incluso un store array de pruebas comparte el mismo espacio de almacenamiento dentro de la misma aplicación.
No sobrescribas incondicionalmente desde tu paquete session.driver, el nombre de la cookie ni el prefijo de caché de toda la aplicación. Confirma también con los usuarios que el almacenamiento no se comparte con otros usos y que varios servidores pueden usar el mismo almacenamiento.
Mantén la unidad del TTL y el formato de almacenamiento
El constructor deCacheBasedSessionHandler recibe la duración en minutos. write() pasa $minutes * 60 a put() del Repository de caché en cada llamada, de modo que en el ejemplo anterior el TTL se renueva con cada escritura. gc() devuelve 0 y delega la expiración en la caché.
En cambio, la duración que StartSession pasa a gc($lifetime) del handler está en segundos. No implementes nada que guarde el valor de session.lifetime tal cual como si fueran segundos.
Además, los siguientes cambios no se resuelven solo cambiando el nombre de un ajuste.
Si una actualización del paquete cambia alguno de estos elementos, considera cómo avisar de la reautenticación, si hace falta una migración y los despliegues en los que conviven la versión antigua y la nueva. Igual que en Gestión de la compatibilidad de versiones de paquetes, incluye el formato de almacenamiento y las claves de configuración en la especificación pública que mantienes.
Cambiar solo la configuración no reemplaza un Store ya creado
Manager, la clase padre de SessionManager, retiene por nombre los drivers que ha creado. Además, SessionServiceProvider registra session.store como singleton.
forgetDrivers() tampoco es una API para eliminar datos de sesión. Recrear el Store durante una petición en curso provoca incoherencias con los datos ya cargados y con otras referencias.
El CacheManager de este ejemplo también retiene stores con nombre. Si cambias su configuración de conexión, no basta con volver a resolver solo el SessionManager.
En despliegues que usan la caché de configuración, reconstruye la caché y reinicia los workers de larga duración para que carguen el código y la configuración nuevos. Reiniciar la aplicación y migrar los datos guardados son tareas distintas.
El almacenamiento de la sesión y el bloqueo de peticiones son cosas distintas
Implementar un handler propio no serializa por sí solo las peticiones concurrentes a la misma sesión. El bloqueo deStartSession usa los locks del store de caché seleccionado con session.block_store, que no es necesariamente el mismo que el almacenamiento de la propia sesión.
Si lo controlas con algo como Route::post(...)->block(), verifica por separado un store de caché compatible con locks, el uso compartido entre varios servidores y los tiempos de espera y retención. No dejes que tu paquete active por su cuenta la configuración de bloqueo de toda la aplicación.
Prueba hasta el guardado y la recarga
En los paquetes que usan Orchestra Testbench, carga el provider y escribe pruebas que seleccionen realmente tu driver propio. El siguiente es un ejemplo detests/SessionDriverTest.php. La caché array de pruebas no usa conexiones externas.
array como almacenamiento compartido en producción.
Antes de publicar tu propio handler, añade también lo siguiente.
- Los IDs no guardados o expirados devuelven una cadena vacía
- La cadena guardada se restaura sin cambios y no se puede recuperar tras eliminarla
- La unidad y la renovación del TTL, y la expiración en el backend real
- Los fallos de lectura, escritura y eliminación producen los valores devueltos o las excepciones definidos
- El ida y vuelta con
session.encryptactivado y los formatos de serialización admitidos - Cargar el provider por sí solo no accede al almacenamiento ni se apropia de la selección de los drivers integrados
- Si hace falta, pruebas HTTP que pasen por el middleware
webreal y las cookies, y los locks para peticiones concurrentes
Páginas relacionadas
Sesión
Revisa la lectura y escritura de sesiones, los datos flash y la regeneración de IDs.
Implementación interna de Manager
Revisa la creación y retención de drivers personalizados y la delegación al driver predeterminado.
Stores de caché personalizados en paquetes
Revisa el reparto de funciones entre el Store de caché y el Repository que sirven de almacenamiento, y el contrato del TTL.
Ciclo de vida de los servicios de paquetes
Revisa las dependencias retenidas por los workers de larga duración y el aislamiento del estado.
Fuentes primarias consultadas
- Documentación oficial de HTTP Session: drivers personalizados y bloqueo
- Documentación oficial de desarrollo de paquetes
- SessionManager: creación personalizada y construcción del Store
- Store: carga, serialización, guardado y regeneración de IDs
- CacheBasedSessionHandler: conversión del TTL y contrato de almacenamiento
- CacheManager: stores con nombre y configuración de Redis
- Manager: extend, driver, forgetDrivers
- SessionServiceProvider: registro singleton del Manager y session.store
- StartSession: guardado, GC y bloqueo mediante la caché
- CacheBasedSessionHandlerTest oficial: verificación de datos inexistentes, TTL y eliminación