Gestión de la sesión

El componente HttpFoundation de Symfony2 tiene un subsistema de sesión muy potente y flexible, que está diseñado para proporcionar la gestión de sesiones a través de una sencilla interfaz orientada a objetos, utilizando una variedad de controladores para el almacenamiento de la sesión.

Nuevo en la versión 2.1: La interfaz Symfony\Component\HttpFoundation\Session\SessionInterface, así como una serie de otros cambios, son nuevas a partir de Symfony 2.1.

Las sesiones se utilizan a través de la simple clase Symfony\Component\HttpFoundation\Session\Session que implementa la interfaz Symfony\Component\HttpFoundation\Session\SessionInterface.

Ejemplo rápido:

use Symfony\Component\HttpFoundation\Session\Session;

$session = new Session();
$session->start();

// establece y obtiene atributos de sesión
$session->set('name', 'Drak');
$session->get('name');

// configura mensajes flash
$session->getFlashBag()->add('notice', 'Profile updated');

// recupera mensajes
foreach ($session->getFlashBag()->get('notice', array()) as $message) {
    echo "<div class='flash-notice'>$message</div>";
}

Nota

Las sesiones Symfony están diseñadas para sustituir varias funciones nativas de PHP. Las aplicaciones deben evitar el uso de session_start(), session_regenerate_id(), `` session_id()``, session_name(), y session_destroy(), y en su lugar usar la API en la siguiente sección.

Nota

Si bien se recomienda empezar una sesión explícitamente, unas sesiones de hecho empezarán bajo demanda, es decir, si se hace alguna petición de sesión para leer/escribir dato de sesión.

Prudencia

Las sesiones de Symfony son incompatibles con la directiva ini session.auto_start = 1 de PHP. Esta directiva se debe apagar en php.ini, en las directivas del servidor web o en .htaccess.

API de sesión

La clase Symfony\Component\HttpFoundation\Session\Session implementa la interfaz Symfony\Component\HttpFoundation\Session\SessionInterface.

La clase Symfony\Component\HttpFoundation\Session\Session tiene una API sencilla subdividida en un par de grupos.

Flujo de trabajo en la sesión

  • start(): Inicia la sesión — no usa session_start().
  • migrate(): Regenera el id de la sesión — no usa session_regenerate_id()—. Opcionalmente, este método puede cambiar el tiempo de vida de la nueva cookie que será emitida al llamar a este método.
  • invalidate(): Limpia todos los datos de la sesión y regenera el id de la sesión. No usa session_destroy().
  • getId(): Recupera el id de la sesión. Sin usar session_id().
  • setId(): Establece el id de la sesión. Sin usar session_id().
  • getName(): Recupera el nombre de la sesión. Sin usar session_name().
  • setName(): Establece el nombre de la sesión. Sin usar session_name().

Atributos de la sesión

  • set(): Establece un atributo por su clave;
  • get(): Recupera un atributo por su clave;
  • all(): Recupera todos los atributos como un arreglo de clave => valor;
  • has(): Devuelve true si el atributo existe;
  • keys(): Devuelve un arreglo de claves de atributo guardadas;
  • replace(): Establece múltiples atributos simultáneamente: toma un arreglo indexado y configura cada pareja clave => valor.
  • remove(): Elimina un atributo por clave;
  • clear(): Limpia todos los atributos;

Internamente los atributos se almacenan en una «Bag» (‘Bolsa’, en adelante), un objeto PHP que actúa como un arreglo. Unos cuantos métodos existentes para gestionar una «Bolsa»:

  • registerBag(): Registra una Symfony\Component\HttpFoundation\Session\SessionBagInterface
  • getBag(): Consigue una Symfony\Component\HttpFoundation\Session\SessionBagInterface por medio del nombre de la «Bolsa».
  • getFlashBag(): Recupera la Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface. Esta, únicamente es un conveniente atajo.

Metadatos de sesión

  • getMetadataBag(): Obtiene la clase Symfony\Component\HttpFoundation\Session\StorageMetadataBag la cual contiene información de la sesión.

Gestionando datos de sesión

La gestión de sesiones PHP requiere el uso de la superglobal $_SESSION, sin embargo, esto interfiere un poco con la comprobabilidad y encapsulación de código en un paradigma de programación orientado a objetos. Para ayudar a superar esta situación, Symfony2 usa ‘bolsas de sesión’ vinculadas a la sesión para encapsular un conjunto de datos específico a los ‘atributos’ o ‘mensajes flash’.

Este enfoque también mitiga la contaminación del espacio de nombres dentro de la superglobal $_SESSION, porque cada bolsa almacena todos sus datos bajo un único espacio de nombres. Esto le permite a Symfony2 coexistir pacíficamente con otras aplicaciones o bibliotecas que puedan usar la superglobal $_SESSION y todos los datos siguen siendo totalmente compatibles con la gestión de sesiones de Symfony2.

Symfony2 ofrece 2 tipos de bolsas para almacenamiento, con dos implementaciones independientes. Todo está escrito contra interfaces para que las puedas ampliar o crear tus propios tipos de bolsa si es necesario.

Symfony\Component\HttpFoundation\Session\SessionBagInterface tiene la siguiente API destinada principalmente para uso interno:

  • getStorageKey(): Devuelve la clave, que en última instancia es la bolsa que va a almacenar tu arreglo bajo $_SESSION. En general, puedes dejar este valor en su predefinido y es para uso interno.
  • initialize(): Symfony2 llama internamente a este método para almacenar clases de sesión con datos para vincularlos a la bolsa de la sesión.
  • getName(): Devuelve el nombre de la bolsa de sesión.

Atributos

El propósito de la implementación de la Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface de bolsas, es manejar el almacenamiento de los atributos de la sesión. Esto puede incluir cosas como el id de usuario, y la funcionalidad «recuérdame» en la configuración del inicio de sesión u otra información basada en el estado del usuario.

  • Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag Esta es la implementación estándar predeterminada.
  • Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag Esta implementación permite que los atributos sean almacenados en un espacio de nombres estructurado.

Cualquier sistema de almacenamiento sencillo clave => valor está limitado en la medida en que se puedan almacenar datos complejos, ya que cada clave debe ser única. Lo puedes lograr introduciendo una convención a la nomenclatura de los espacios de nombres para que las claves sean partes diferentes de tu aplicación lo cual podría funcionar sin colisiones. Por ejemplo, modulo1.foo y modulo2.foo. Sin embargo, a veces esto no es muy práctico cuando los datos de los atributos están en un arreglo, por ejemplo, un conjunto de iniciales. En este caso, la gestión del arreglo se convierte en una carga porque hay que recuperar el arreglo, luego, procesarlo y almacenarlo de nuevo:

$tokens = array('tokens' => array('a' => 'a6c1e0b6',
                                  'b' => 'f4a7b1f3'));

Así que cualquier procesamiento de este tipo rápidamente se puede poner feo, aunque sólo añadas un elemento al arreglo:

$tokens = $session->get('tokens');
$tokens['c'] = $value;
$session->set('tokens', $tokens);

Con el espacio de nombre estructurado, la clave se puede trasladar a la estructura del arreglo tal cual usando un carácter del espacio de nombres (por omisión es /):

$session->set('tokens/c', $value);

De esta manera puedes acceder a una clave dentro del arreglo almacenado directa y fácilmente.

La Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface cuenta con una API sencilla

  • set(): Establece un atributo por su clave;
  • get(): Recupera un atributo por su clave;
  • all(): Recupera todos los atributos como un arreglo de clave => valor;
  • has(): Devuelve true si el atributo existe;
  • keys(): Devuelve un arreglo de claves de atributo guardadas;
  • replace(): Establece múltiples atributos simultáneamente: toma un arreglo indexado y configura cada pareja clave => valor.
  • remove(): Elimina un atributo por clave;
  • clear(): Vacía la bolsa;

Mensajes flash

El propósito de la Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface es proporcionar una forma de configurar y recuperar mensajes basándose en la sesión. El flujo de trabajo habitual de los mensajes flash se encuentra en una Petición, y se muestran después de redirigir a una página. Por ejemplo, un usuario envía un formulario que llegará a un controlador de actualización, y después de procesar el controlador redirige al usuario o bien a la página actualizada o a una página de error. Los mensajes flash establecidos en la Petición de página anterior se muestran inmediatamente al cargar la siguiente página en esa sesión. Esta, sin embargo, sólo es una aplicación para los mensajes flash.

  • Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag Esta implementación de mensajes se ajusta al cargar la página para que esté disponible para visualizarlo al cargar la siguiente página. Estos mensajes expirarán automáticamente independientemente de si se recuperan o no.
  • Symfony\Component\HttpFoundation\Session\Flash\FlashBag En esta implementación, los mensajes se mantendrán en la sesión hasta que se recuperen o borren explícitamente. Esto hace posible el uso de la caché ESI.

La Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface tiene una sencilla API

  • add(): Añade un mensaje flash a la pila del tipo especificado;
  • set(): Configura mensajes flash por tipo; Este método toma ambos, mensajes como una cadena o varios mensajes en un arreglo.
  • get(): Recupera mensajes por tipo y los quita de la bolsa;
  • setAll(): Establece todos los flashes, acepta un arreglo de arreglos indexado tipo => array(mensajes);
  • all(): Recupera todos los mensajes flash (en forma de arreglo de arreglos indexado) y quita los mensajes de la bolsa;
  • peek(): Recupera mensajes flash por tipo (sólo lectura);
  • peekAll(): Recupera todos los mensajes flash (sólo lectura) como arreglo de arreglos indexado;
  • has(): Devuelve true si el tipo existe, false en caso contrario;
  • keys(): Devuelve un arreglo de tipos flash guardados;
  • clear(): Limpia la bolsa;

Para aplicaciones simples por lo general es suficiente tener un mensaje flash por tipo, por ejemplo, un aviso de confirmación después de enviar un formulario. Sin embargo, los mensajes Flash se almacenan en un arreglo indexado por el $tipo del flash, lo cual significa que tu aplicación puede emitir varios mensajes de un determinado tipo. Esto te permite utilizar la API para mensajes más complejos en tu aplicación.

Ejemplos de configuración de múltiples mensajes flash:

use Symfony\Component\HttpFoundation\Session\Session;

$session = new Session();
$session->start();

// añade mensajes flash
$session->getFlashBag()->add(
    'warning',
    'Your config file is writable, it should be set read-only'
);
$session->getFlashBag()->add('error', 'Failed to update name');
$session->getFlashBag()->add('error', 'Another error');

Para exhibir los mensajes flash puedes usar algo como esto:

Simple, muestra un tipo de mensaje:

// muestra advertencias
foreach ($session->getFlashBag()->get('warning', array()) as $message) {
    echo "<div class='flash-warning'>$message</div>";
}

// muestra errores
foreach ($session->getFlashBag()->get('error', array()) as $message) {
    echo "<div class='flash-error'>$message</div>";
}

Método compacto para procesar la exhibición simultánea de todos los mensajes:

foreach ($session->getFlashBag()->all() as $type => $messages) {
    foreach ($messages as $message) {
        echo "<div class='flash-$type'>$message</div>\n";
    }
}
Bifúrcame en GitHub