Ver índice de contenidos del libro

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-17. 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-17 - El objeto sfUser puede contener atributos personalizados del usuario disponibles en todas las peticiones

class mimoduloActions extends sfActions
{
  public function executePrimeraPagina()
  {
    $nombre = $this->getRequestParameter('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');
  }
}

Advertencia Puedes guardar objetos en la sesión del usuario, pero no se recomienda hacerlo. El motivo es que el objeto de la sesión se serializa entre una petición y otra y se guarda en un archivo. Cuando la sesión se deserializa, la clase del objeto guardado debe haber sido previamente cargada y este no es siempre el caso. Además, puede haber objetos de tipo "stalled" si se guardan objetos de Propel.

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-18.

Listado 6-18 - 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-19.

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

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

Nota Si se necesita guardar la información solamente durante la petición actual (por ejemplo, para pasar información a través de una sucesión de llamadas a acciones) es preferible utilizar la clase sfRequest, que también tiene métodos getAttribute() y setAttribute(). Solo los atributos del objeto sfUser son persistentes entre peticiones.

6.4.2. Atributos Flash

Un problema recurrente con los atributos del usuario es la limpieza de la sesión del usuario una vez que el atributo no se necesita más. Por ejemplo, puede ser necesario 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. Pero una vez que se muestra el mensaje, es necesario borrar el atributo; ya que de otra forma, permanecerá en la sesión hasta que esta expire.

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->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->getFlash('atributo');

Luego te puedes olvidar de ese parámetro. Después de mostrar la segunda página, el atributo flash 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_flash:

<?php if ($sf_flash->has('atributo')): ?>
  <?php echo $sf_flash->get('atributo') ?>
<?php endif; ?>

O simplemente:

<?php echo $sf_flash->get('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-20.

Listado 6-20 - Cambiando el nombre de la cookie de sesión, en apps/miaplicacion/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-21.

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

all:
  storage:
    class: sfMySQLSessionStorage
    param:
      db_table: SESSION_TABLE_NAME      # Nombre de la tabla que guarda las sesiones
      database: DATABASE_CONNECTION     # Nombre de la conexión a base de datos que se utiliza

Las clases de almacenamiento de sesiones disponibles son sfMySQLSessionStorage, sfPostgreSQLSessionStorage y sfPDOSessionStorage. La clase recomendada es sfPDOSessionStorage. 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).

La expiración de la sesión se produce automáticamente después de sf_timeout segundos. El valor de esta constante es 30 minutos por defecto y puede ser modificado para cada entorno en el archivo de configuración settings.yml, como se muestra en el Listado 6-22.

Listado 6-22 - Cambiando el tiempo de vida de la sesión, en apps/miaplicacion/config/settings.yml

default:
  .settings:
    timeout:     1800           # Tiempo de vida de la sesión en segundos