Cómo utilizar PdoSessionHandler para almacenar sesiones en la base de datos

El almacenamiento de sesiones predeterminado de Symfony2 escribe la información de la sesión en archivo(s). La mayoría desde medianos hasta grandes sitios web utilizan una base de datos para almacenar valores de sesión en lugar de archivos, porque las bases de datos son más fáciles de usar y escalar en un entorno web multiservidor.

Symfony2 ha incorporado una solución para el almacenamiento de la sesión en la base de datos denominada Symfony\Component\HttpFoundation\SessionStorage\PdoSessionStorage. Para usarla, sólo tienes que cambiar algunos parámetros en config.yml (o el formato de configuración de tu elección):

Nuevo en la versión 2.1: En Symfony 2.1 la clase y el espacio de nombres se han modificado significativamente. Ahora puedes encontrar las clases de almacenamiento de sesión en el espacio de nombres Session\Storage: Symfony\Component\HttpFoundation\Session\Storage. Además ten en cuenta que en Symfony 2.1 debes configurar handler_id no storage_id como en Symfony2.0. Abajo, notarás que ya no se utiliza %sesión.storage.options%.

  • YAML
    # app/config/config.yml
    framework:
        session:
            # ...
            handler_id:     session.handler.pdo
    
    parameters:
        pdo.db_options:
            db_table:    session
            db_id_col:   session_id
            db_data_col: session_value
            db_time_col: session_time
    
    services:
        pdo:
            class: PDO
            arguments:
                dsn:      "mysql:dbname=mydatabase"
                user:     myuser
                password: mypassword
    
        session.handler.pdo:
            class:     Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
            arguments: ["@pdo", "%pdo.db_options%"]
    
  • XML
    <!-- app/config/config.xml -->
    <framework:config>
        <framework:session handler-id="session.handler.pdo" cookie-lifetime="3600" auto-start="true"/>
    </framework:config>
    
    <parameters>
        <parameter key="pdo.db_options" type="collection">
            <parameter key="db_table">session</parameter>
            <parameter key="db_id_col">session_id</parameter>
            <parameter key="db_data_col">session_value</parameter>
            <parameter key="db_time_col">session_time</parameter>
        </parameter>
    </parameters>
    
        <services>
        <service id="pdo" class="PDO">
            <argument>mysql:dbname=mydatabase</argument>
            <argument>myuser</argument>
            <argument>mypassword</argument>
        </service>
    
        <service id="session.handler.pdo" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler">
            <argument type="service" id="pdo" />
            <argument>%pdo.db_options%</argument>
        </service>
        </services>
    
  • PHP
    // app/config/config.php
    use Symfony\Component\DependencyInjection\Definition;
    use Symfony\Component\DependencyInjection\Reference;
    
    $container->loadFromExtension('framework', array(
        ...,
        'session' => array(
            // ...,
            'handler_id' => 'session.handler.pdo',
        ),
    ));
    
    $container->setParameter('pdo.db_options', array(
        'db_table'      => 'session',
        'db_id_col'     => 'session_id',
        'db_data_col'   => 'session_value',
        'db_time_col'   => 'session_time',
    ));
    
    $pdoDefinition = new Definition('PDO', array(
        'mysql:dbname=mydatabase',
        'myuser',
        'mypassword',
    ));
    $container->setDefinition('pdo', $pdoDefinition);
    
    $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array(
        new Reference('pdo'),
        '%pdo.db_options%',
    ));
    $container->setDefinition('session.handler.pdo', $storageDefinition);
    
  • db_table: El nombre de la tabla de sesiones en tu base de datos
  • db_id_col: El nombre de la columna id en la tabla de sesiones (VARCHAR (255) o más grande)
  • db_data_col: El nombre de la columna de valores en tu tabla de sesiones (TEXT o CLOB)
  • db_time_col: El nombre de la columna de tiempo en tu tabla de sesiones (INTEGER)

Compartiendo información de conexión a tu base de datos

Con la configuración dada, la configuración de conexión de la base de datos únicamente se define para la conexión de almacenamiento de sesión. Esto está bien cuando utilizas una base de datos para los datos de sesión.

Pero si deseas almacenar los datos de sesión en la misma base que el resto de los datos de tu proyecto, puedes utilizar la configuración de conexión de parameters.yml refiriendo los parámetros relacionados con la base de datos definidos allí:

  • YAML
    pdo:
        class: PDO
        arguments:
            - "mysql:host=%database_host%;port=%database_port%;dbname=%database_name%"
            - "%database_user%"
            - "%database_password%"
    
  • XML
    <service id="pdo" class="PDO">
        <argument>mysql:host=%database_host%;port=%database_port%;dbname=%database_name%</argument>
        <argument>%database_user%</argument>
        <argument>%database_password%</argument>
    </service>
    
  • PHP
    $pdoDefinition = new Definition('PDO', array(
        'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%',
        '%database_user%',
        '%database_password%',
    ));
    

Instrucciones SQL de ejemplo

MySQL

La declaración SQL necesaria para crear la tabla en la base de datos podría ser similar a la siguiente (MySQL):

CREATE TABLE `session` (
    `session_id` varchar(255) NOT NULL,
    `session_value` text NOT NULL,
    `session_time` int(11) NOT NULL,
    PRIMARY KEY (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PostgreSQL

Para PostgreSQL, la declaración debe tener este aspecto:

CREATE TABLE session (
    session_id character varying(255) NOT NULL,
    session_value text NOT NULL,
    session_time integer NOT NULL,
    CONSTRAINT session_pkey PRIMARY KEY (session_id)
);

«Microsoft SQL Server»

Para MSSQL, la declaración se podría parecer a la siguiente:

CREATE TABLE [dbo].[session](
    [session_id] [nvarchar](255) NOT NULL,
    [session_value] [ntext] NOT NULL,
    [session_time] [int] NOT NULL,
    PRIMARY KEY CLUSTERED(
        [session_id] ASC
    ) WITH (
        PAD_INDEX  = OFF,
        STATISTICS_NORECOMPUTE  = OFF,
        IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS  = ON,
        ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Bifúrcame en GitHub