Symfony 1.4, la guía definitiva

6.4. Sesiones de Usuario

Symfony maneja automáticamente las sesiones del usuario y es capaz de almacenar datos de forma persistente entre peticiones. Utiliza el mecanismo de manejo de sesiones incluido en PHP y lo mejora para hacerlo mas configurable y más fácil de usar.

6.4.1. Accediendo a la Sesión de Usuario

El objeto sesión del usuario actual se accede en la acción con el método getUser(), que es una instancia de la clase sfUser. Esta clase dispone de un contenedor de parámetros que permite guardar cualquier atributo del usuario en el. Esta información estará disponible en otras peticiones hasta terminar la sesión del usuario, como se muestra en el Listado 6-14. Los atributos de usuarios pueden guardar cualquier tipo de información (cadenas de texto, arrays y arrays asociativos). Se pueden utilizar para cualquier usuario, incluso si ese usuario no se ha identificado.

Listado 6-14 - El objeto sfUser puede contener atributos personalizados del usuario disponibles en todas las peticiones

class mimoduloActions extends sfActions
{
  public function executePrimeraPagina($request)
  {
    $nombre = $request->getParameter('nombre');

    // Guardar información en la sesión del usuario
    $this->getUser()->setAttribute('nombre', $nombre);
  }

  public function executeSegundaPagina()
  {
    // Obtener información de la sesión del usuario con un valor por defecto
    $nombre = $this->getUser()->getAttribute('nombre', 'Anónimo');
  }
}

Nota Puedes guardar objetos en la sesión del usuario, pero no se recomienda hacerlo. El motivo es que los objetos de sesión se serializan entre una petición y otra. Cuando después se deserializa la sesión, es posible que no se haya cargado la clase correspondiente al objeto que se está recuperando. Además, pueden producirse errores si guardas objetos de Propel o Doctrine.

Como muchos otros getters en Symfony, el método getAttribute() acepta un segundo parámetro, especificando el valor por defecto a ser utilizado cuando el atributo no está definido. Para verificar si un atributo ha sido definido para un usuario, se utiliza el método hasAttribute(). Los atributos se guardan en un contenedor de parámetros que puede ser accedido por el método getAttributeHolder(). También permite un borrado rápido de los atributos del usuario con los métodos usuales del contenedor de parámetros, como se muestra en el listado 6-15.

Listado 6-15 - Eliminando información de la sesión del usuario

class mimoduloActions extends sfActions
{
  public function executeBorraNombre()
  {
    $this->getUser()->getAttributeHolder()->remove('nombre');
  }

  public function executeLimpia()
  {
    $this->getUser()->getAttributeHolder()->clear();
  }
}

Los atributos de la sesión del usuario también están disponibles por defecto en las plantillas mediante la variable $sf_user, que almacena el objeto sfUser actual, como se muestra en el listado 6-16.

Listado 6-16 - Las plantillas también tienen acceso a los atributos de la sesión del usuario

<p>
  Hola, <?php echo $sf_user->getAttribute('nombre') ?>
</p>

6.4.2. Atributos Flash

Un problema habitual con los atributos del usuario es la limpieza de la sesión una vez que el atributo ya no se necesita. Imagina que quieres mostrar un mensaje de confirmación después de actualizar información mediante un formulario. Como la acción que maneja el formulario realiza una redirección, la única forma de pasar información desde esta acción a la acción que ha sido redireccionada es almacenar la información en la sesión del usuario. El problema es que después de mostrar el mensaje de confirmación una vez, es necesario que lo borres de la sesión. Si no lo haces, el atributo permanecerá hasta que expire la sesión y por tanto se mostrará el mensaje de confirmación una y otra vez.

El atributo de tipo flash es un atributo fugaz que permite definirlo y olvidarse de el, sabiendo que desaparece automáticamente después de la siguiente petición y que deja la sesión limpia para las futuras peticiones. En la acción, se define el atributo flash de la siguiente manera:

$this->getUser()->setFlash('atributo', $valor);

La plantilla se procesa y se envía al usuario, quien después realiza una nueva petición hacia otra acción. En esta segunda acción, es posible obtener el valor del atributo flash de esta forma:

$valor = $this->getUser()->getFlash('atributo');

Luego ya te puedes olvidar de ese parámetro. Después de mostrar la segunda página, el atributo flash llamado atributo desaparece automáticamente. Incluso si no se utiliza el atributo durante la segunda acción, el atributo desaparece igualmente de la sesión.

Si necesitas acceder a un atributo flash desde la plantilla, puedes utilizar el objeto $sf_user:

<?php if ($sf_user->hasFlash('atributo')): ?>
  <?php echo $sf_user->getFlash('atributo') ?>
<?php endif; ?>

O simplemente:

<?php echo $sf_user->getFlash('atributo') ?>

Los atributos de tipo flash son una forma limpia de pasar información a la próxima petición.

6.4.3. Manejo de Sesiones

El manejo de sesiones de Symfony se encarga de gestionar automáticamente el almacenamiento de los IDs de sesión tanto en el cliente como en el servidor. Sin embargo, si se necesita modificar este comportamiento por defecto, es posible hacerlo. Se trata de algo que solamente lo necesitan los usuarios más avanzados.

En el lado del cliente, las sesiones son manejadas por cookies. La cookie de Symfony se llama Symfony, pero se puede cambiar su nombre editando el archivo de configuración factories.yml, como se muestra en el Listado 6-17.

Listado 6-17 - Cambiando el nombre de la cookie de sesión, en apps/frontend/config/factories.yml

all:
  storage:
    class: sfSessionStorage
    param:
      session_name: mi_nombre_cookie

Nota La sesión se inicializa (con la función de PHP session_start()) solo si el parámetro auto_start de factories.yml tiene un valor de true (que es el caso por defecto). Si se quiere iniciar la sesión manualmente, se debe cambiar el valor de esa opción de configuración del archivo factories.yml.

El manejo de sesiones de Symfony esta basado en las sesiones de PHP. Por tanto, si la gestión de la sesión en la parte del cliente se quiere realizar mediante parámetros en la URL en lugar de cookies, se debe modificar el valor de la directiva use_trans_sid en el archivo de configuración php.ini. No obstante, se recomienda no utilizar esta técnica.

session.use_trans_sid = 1

En el lado del servidor, Symfony guarda por defecto las sesiones de usuario en archivos. Se pueden almacenar en la base de datos cambiando el valor del parámetro class en factories.yml, como se muestra en el Listado 6-18.

Listado 6-18 - Cambiando el almacenamiento de las sesiones en el servidor, en apps/frontend/config/factories.yml

all:
  storage:
    class: sfMySQLSessionStorage
    param:
      # Nombre de la tabla que guarda las sesiones
      db_table:    session
      # Nombre de la conexión a base de datos que se utiliza
      database:    propel
      # (opcional) Nombre de la columna que guarda el identificador de la sesión
      db_id_col:   sess_id
      # (opcional) Nombre de la columna que guarda los datos de la sesión
      db_data_col: sess_data
      # (opcional) Nombre de la columna que guarda el timestamp de la sesión
      db_time_col: sess_time

La opción database define el nombre de la conexión a base de datos que se utiliza. Posteriormente, Symfony utiliza el archivo databases.yml (ver capítulo 8) para determinar los parámetros con los que realiza la conexión (host, nombre de la base de datos, usuario y password).

Las clases disponibles para el almacenamiento de sesiones son sfCacheSessionStorage, sfMySQLSessionStorage, sfMySQLiSessionStorage, sfPostgreSQLSessionStorage y sfPDOSessionStorage. La clase recomendada es sfPDOSessionStorage. Para deshabilitar completamente el almacenamiento de las sesiones, se puede utilizar la clase sfNoStorage.

La expiración de la sesión se produce automáticamente después de 30 minutos. El valor de esta opción se puede modificar para cada entorno en el mismo archivo de configuración factories.yml, concretamente en la factoría correspondiente al usuario (user), tal y como muestra el listado 6-19.

Listado 6-19 - Cambiando el tiempo de vida de la sesión, en apps/frontend/config/factories.yml

all:
  user:
    class:       myUser
    param:
      timeout:   1800           # Tiempo de vida de la sesión en segundos

El capítulo 19 explica detalladamente todas las opciones de las factorías.