Skip to content

[WIP] Added DBAL session storaged based on PDO Session storage page #3914

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,153 @@
.. index::
single: Session; Database Storage

How to Use PdoSessionHandler to Store Sessions in the Database
==============================================================
How to Store Session in the Database
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sessions

====================================

The default Symfony session storage writes the session information to
file(s). Most medium to large websites use a database to store the session
values instead of files, because databases are easier to use and scale in a
multi-webserver environment.

Symfony has a built-in solution for database session storage called
:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler`.
To use it, you just need to change some parameters in ``config.yml`` (or the
configuration format of your choice):
Symfony2 has two built-in solutions for database session storage one uses doctrine
:class:`Symfony\\Bridge\\Doctrine\\HttpFoundation\\HttpFoundation\\DbalSessionHandler`
and the other uses PDO :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the differences here? Do we have any idea why we should pick one versus the other? I just realized that we're giving the user a choice, and choices suck unless we can help them decide :).

Also, I would love to put these into a numbered list and link them to the individual headers. Something like this (but with different language, I'm being lazy):

  1. Storing via PDO
  2. Storing via Doctrine's DBAL

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weaverryan Well, wish I could help you there. Not a lot of people know about the doctrine option (I found out this existed after implementing it myself)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the PHPdoc of the DbalHandler class:

This implementation is very similar to Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler but uses a Doctrine connection and thus also works with non-PDO-based drivers like mysqli and OCI8

From the PR introducing this feature:

cleaner code, potentially better support for niche RDBMS, centralized logging and finally afaik DoctrineDBAL has emulation for nested transactions.

The benefits (for me) are:

  • logging queries
  • better interoperability with existing build processes (migrations)
  • better database interoperability
  • re-using existing connection (I don't have the problem that Stof mentioned above)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wouterj I don't understand your statement re-using existing connection (I don't have the problem that Stof mentioned above). If you use the same connection for your session storage and for your application logic, you will suffer from the issue when a transaction is rollbacked. there is no way you cannot be affected

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stof I was just quoting people for that issue, not sure why schmittjoh didn't have that issue :)


Using Doctrine to Store the Session in the Database
---------------------------------------------------

To use The DBAL session storage, you need to register a new service and configure
Symfony's session handling to use it:
.. configuration-block::

.. code-block:: yaml

# app/config/config.yml
framework:
session:
# ...
handler_id: session.handler.dbal_handler

services:

session.handler.dbal_handler:
class: Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler
arguments: ["@doctrine.dbal.default_connection"]

.. code-block:: xml

<!-- app/config/config.xml -->
<framework:config>
<framework:session handler-id="session.handler.dbal_handler" cookie-lifetime="3600" auto-start="true"/>
</framework:config>

<services>
<service id="session.handler.dbal_handler" class="Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler">
<argument type="service" id="doctrine.dbal.default_connection" />
</service>
</services>

.. code-block:: php

// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

$container->loadFromExtension('framework', array(
...,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use // ... (same on line 61)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which line?

'session' => array(
// ...,
'handler_id' => 'session.handler.dbal_handler',
),
));

$storageDefinition = new Definition('Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler', array(
new Reference('doctrine.dbal.default_connection'),
));
$container->setDefinition('session.handler.dbal_handler', $storageDefinition);

You can pass a second parameter to the constructor to set the table name.

``db_table``
The name of the session table in your database
``db_id_col``
The name of the id column in your session table (VARCHAR(255) or larger)
``db_data_col``
The name of the value column in your session table (TEXT or CLOB)
``db_time_col``
The name of the time column in your session table (INTEGER)

Configuring your Database Connection Information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

With the given configuration, the database connection settings are the ones you've
set for the default doctrine connection. This is OK if you're storing everything
in the same database. If you want to store the sessions in another database you just have
to configure a new doctrine connection.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


.. note::

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra line break here

How to configure multiple entity managers is covered in the :doc:`/cookbook/doctrine/multiple_entity_managers` page of the book.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should add a line break after the first word that crosses the 72th character (same below)


Table Structure and Example SQL Statements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Because of the way this is implemented in the php class you can only configure the table name (The default is sessions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you said earlier (https://github.com/symfony/symfony-docs/pull/3914/files#diff-9766d74d9af6412387790b658b586329R72) that you can configure the column names too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should add an empty line before the paragraph (and wrap it, see my previous comment)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where should the empty line go?

Here are a couple of SQL statements to help you create a table that will work with this
MySQL
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line missing before this headline too

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

.....

The SQL statement for creating the needed database table might look like the
following (MySQL):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these the same statements as what we have below for PDO? Or are they different?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they seem to be the same


.. code-block:: sql

CREATE TABLE `sessions` (
`sess_id` varchar(255) NOT NULL,
`sess_data` text NOT NULL,
`sess_time` int(11) NOT NULL,
PRIMARY KEY (`sess_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PostgreSQL
..........

For PostgreSQL, the statement should look like this:

.. code-block:: sql

CREATE TABLE sessions (
sess_id character varying(255) NOT NULL,
sess_data text NOT NULL,
sess_time integer NOT NULL,
CONSTRAINT session_pkey PRIMARY KEY (sess_id)
);

Microsoft SQL Server
....................

For MSSQL, the statement might look like the following:

.. code-block:: sql

CREATE TABLE [dbo].[sessions](
[sess_id] [nvarchar](255) NOT NULL,
[sess_data] [ntext] NOT NULL,
[sess_time] [int] NOT NULL,
PRIMARY KEY CLUSTERED(
[sess_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]


Using PDO to Store the Session in the Database
----------------------------------------------
.. versionadded:: 2.1
In Symfony 2.1 the class and namespace are slightly modified. You can now
find the session storage classes in the ``Session\Storage`` namespace:
Expand Down Expand Up @@ -126,7 +260,7 @@ configuration format of your choice):
* ``db_time_col``: The name of the time column in your session table (INTEGER)

Sharing your Database Connection Information
--------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

With the given configuration, the database connection settings are defined for
the session storage connection only. This is OK when you use a separate
Expand Down Expand Up @@ -165,10 +299,10 @@ of your project's data, you can use the connection settings from the
));

Example SQL Statements
----------------------
~~~~~~~~~~~~~~~~~~~~~~

MySQL
~~~~~
.....

The SQL statement for creating the needed database table might look like the
following (MySQL):
Expand All @@ -183,7 +317,7 @@ following (MySQL):
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PostgreSQL
~~~~~~~~~~
..........

For PostgreSQL, the statement should look like this:

Expand All @@ -197,7 +331,7 @@ For PostgreSQL, the statement should look like this:
);

Microsoft SQL Server
~~~~~~~~~~~~~~~~~~~~
....................

For MSSQL, the statement might look like the following:

Expand All @@ -216,4 +350,4 @@ For MSSQL, the statement might look like the following:
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
134 changes: 134 additions & 0 deletions cookbook/configuration/dbal_session_storage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
.. index::
single: Session; Database Storage

How to use PdoSessionHandler to Store Session in the Database
==============================================================

The default session storage of Symfony2 writes the session information to
file(s). Most medium to large websites use a database to store the session
values instead of files, because databases are easier to use and scale in a
multi-webserver environment.

Symfony2 has a built-in solution for database session storage called
:class:`Symfony\\Bridge\\Doctrine\\HttpFoundation\\HttpFoundation\\DbalSessionHandler`.
To use it, you just need to inject this class as a service in ``config.yml``:

.. versionadded:: 2.1

.. configuration-block::

.. code-block:: yaml

# app/config/config.yml
framework:
session:
# ...
handler_id: session.handler.dbal_handler

services:

session.handler.dbal_handler:
class: Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler
arguments: ["@doctrine.dbal.default_connection"]

.. code-block:: xml

<!-- app/config/config.xml -->
<framework:config>
<framework:session handler-id="session.handler.dbal_handler" cookie-lifetime="3600" auto-start="true"/>
</framework:config>

<services>
<service id="session.handler.dbal_handler" class="Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler">
<argument type="service" id="doctrine.dbal.default_connection" />
</service>
</services>

.. code-block:: 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.dbal_handler',
),
));

$storageDefinition = new Definition('Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler', array(
new Reference('doctrine.dbal.default_connection'),
));
$container->setDefinition('session.handler.dbal_handler', $storageDefinition);

You can pass a second parameter to the constructor to set the table name.
* ``db_table``: The name of the session table in your database
* ``db_id_col``: The name of the id column in your session table (VARCHAR(255) or larger)
* ``db_data_col``: The name of the value column in your session table (TEXT or CLOB)
* ``db_time_col``: The name of the time column in your session table (INTEGER)

Configuring your Database Connection Information
-------------------------------------------------

With the given configuration, the database connection settings are the ones you've
set for the default doctrine connection. This is OK if you're storing everything
in the same database. If you want to store the sessions in another database you just have
to configure a new doctrine connection.


Table structure and example SQL Statements
------------------------------------------
Because of the way this is implemented in the php class you can only configure the table name (The default is sessions)
Here are a couple of SQL statements to help you create a table that will work with this
MySQL
~~~~~

The SQL statement for creating the needed database table might look like the
following (MySQL):

.. code-block:: sql

CREATE TABLE `sessions` (
`sess_id` varchar(255) NOT NULL,
`sess_data` text NOT NULL,
`sess_time` int(11) NOT NULL,
PRIMARY KEY (`sess_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PostgreSQL
~~~~~~~~~~

For PostgreSQL, the statement should look like this:

.. code-block:: sql

CREATE TABLE sessions (
sess_id character varying(255) NOT NULL,
sess_data text NOT NULL,
sess_time integer NOT NULL,
CONSTRAINT session_pkey PRIMARY KEY (sess_id)
);

Microsoft SQL Server
~~~~~~~~~~~~~~~~~~~~

For MSSQL, the statement might look like the following:

.. code-block:: sql

CREATE TABLE [dbo].[sessions](
[sess_id] [nvarchar](255) NOT NULL,
[sess_data] [ntext] NOT NULL,
[sess_time] [int] NOT NULL,
PRIMARY KEY CLUSTERED(
[sess_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]
4 changes: 3 additions & 1 deletion cookbook/configuration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ Configuration
using_parameters_in_dic
front_controllers_and_kernel
external_parameters
pdo_session_storage
database_session_storage

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also update the redirection_map file since the URL will now be changed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I learn how to do that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add this line in that file:

cookbook/configuration/pdo_session_storage cookbook/configuration/database_session_storage

apache_router
web_server_configuration
configuration_organization
cookbook/configuration/pdo_session_storage cookbook/configuration/database_session_storage
1 change: 1 addition & 0 deletions redirection_map
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
/cookbook/console/generating_urls /cookbook/console/sending_emails
/components/yaml /components/yaml/introduction
/components/templating /components/templating/introduction
/cookbook/configuration/pdo_session_storage /cookbook/configuration/database_session_storage