Skip to content
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

Add cookbook article for using MongoDB to store session data #5478

Merged
1 change: 1 addition & 0 deletions cookbook/configuration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Configuration
apache_router
web_server_configuration
configuration_organization
mongodb_session_storage
171 changes: 171 additions & 0 deletions cookbook/configuration/mongodb_session_storage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
How to Use MongoDbSessionHandler to Store Sessions in a MongoDB Database
========================================================================

The default Symfony session storage writes the session information to files.
Some medium to large websites use a NoSQL database called MongoDB 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 NoSQL database session storage called
:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MongoDbSessionHandler`.
MongoDB is an open-source document database that provides high performance,
high availability and automatic scaling. This article assumes that you have
already `installed and configured a MongoDB server`_. To use it, you just
need to change/add some parameters in the main configuration file:

.. configuration-block::

.. code-block:: yaml
Copy link
Member

Choose a reason for hiding this comment

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

Most (all?) Symfony documentation shows how to define things using three different formats (YAML, XML and PHP). I know firsthand how demanding this is (specially for XML) but I'm afraid we have no option here. If you have any troubles with some of the other formats, I'm sure that our doc managers (@wouterj and @xabbuh) will be glad to help you. Thanks.

Copy link
Member

Choose a reason for hiding this comment

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

XML

<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

    <framework:config>
        <!-- ... -->

        <!-- cookie-lifetime and gc-maxlifetime are optional and set to
             30 days in this example -->
        <framework:session handler-id="session.handler.mongo"
            cookie-lifetime="2592000"
            gc-maxlifetime="2592000"
        />
    </framework:config>

    <parameters>
        <parameter key="mongo.session.options" type="collection">
            <!-- your MongoDB database name -->
            <parameter key="database">session_db</parameter>
            <!-- your MongoDB collection name -->
            <parameter key="collection">session</parameter>
        </parameter>
        <!-- your MongoDB server's IP -->
        <parameter key="mongodb_host">1.2.3.4</parameter>
        <parameter key="mongodb_username">my_username</parameter>
        <parameter key="mongodb_password">my_password</parameter>
    </parameters>

    <services>
        <service id="mongo_client" class="MongoClient">
            <!-- if using a username and password -->
            <argument>mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017</argument>

            <!-- if not using a username and password -->
            <argument>mongodb://%mongodb_host%:27017</argument>
        </service>

        <service id="session.handler.mongo" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler">
            <argument type="service">mongo_client</argument>
            <argument>%mongo.session.options%</argument>
        </service>
</container>

PHP

use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;

$container->loadFromExtension('framework', array(
    'session' => array(
        // ...
        'handler_id'      => 'session.handler.mongo',
        'cookie_lifetime' => 2592000, // optional, it is set to 30 days here
        'gc_maxlifetime'  => 2592000, // optional, it is set to 30 days here
    ),
));

$container->setParameter(

parameters:
    # ...
$container->setParameter('mongo.session.options', array(
    'database'   => 'session_db', // your MongoDB database name
    'collection' => 'session',  // your MongoDB collection name
));
$container->setParameter('mongodb_host', '1.2.3.4'); // your MongoDB server's IP
$container->setParameter('mongodb_username', 'my_username');
$container->setParameter('mongodb_password', 'my_password');

$container->setDefinition('mongo_client', new Definition('MongoClient', array(
    // if using a username and password
    array('mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017'),
    // if not using a username and password
    array('mongodb://%mongodb_host%:27017'),
)));

$container->setDefinition('session.handler.mongo', new Definition(
    'Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler',
    array(new Reference('mongo_client'), '%mongo.session.options%')
));

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if we should configure the parameters in all code examples. Usually one would simply put them in their parameters.yml file and just refers to them in the service configuration. Imho we should simply show the service configurations and add an explanation that these parameters need to be defined somewhere (like you do with other database connections as well).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, however, I do think it would add clarity to show how this is done, so I moved the parameter definitions to a separate section of the article in my latest commit. @wouterj would you please review the XML and PHP sections of the new addition?


# app/config/config.yml
framework:
session:
# ...
handler_id: session.handler.mongo
cookie_lifetime: 2592000 # optional, it is set to 30 days here
gc_maxlifetime: 2592000 # optional, it is set to 30 days here

services:
# ...
mongo_client:
class: MongoClient
# if using a username and password
arguments: [mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017]
# if not using a username and password
arguments: [mongodb://%mongodb_host%:27017]
session.handler.mongo:
class: Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler
arguments: [@mongo_client, %mongo.session.options%]
Copy link
Member

Choose a reason for hiding this comment

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

% is a reserved first character in older versions of the Yaml spec. Unfortunately, the syntax highlighter used on symfony.com follows this spec and breaks. Can you please wrap it in double quotes, "%mongo.session.options%"?


.. code-block:: xml

<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony
http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config>
<!-- ... -->

<!-- cookie-lifetime and gc-maxlifetime are optional and set to
30 days in this example -->
<framework:session handler-id="session.handler.mongo"
cookie-lifetime="2592000"
gc-maxlifetime="2592000"
/>
</framework:config>

<services>
<service id="mongo_client" class="MongoClient">
<!-- if using a username and password -->
<argument>mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017</argument>

<!-- if not using a username and password -->
<argument>mongodb://%mongodb_host%:27017</argument>
</service>

<service id="session.handler.mongo" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler">
<argument type="service">mongo_client</argument>
<argument>%mongo.session.options%</argument>
</service>
</container>

.. code-block:: php

use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;

$container->loadFromExtension('framework', array(
'session' => array(
// ...
'handler_id' => 'session.handler.mongo',
'cookie_lifetime' => 2592000, // optional, it is set to 30 days here
'gc_maxlifetime' => 2592000, // optional, it is set to 30 days here
),
));

$container->setDefinition('mongo_client', new Definition('MongoClient', array(
// if using a username and password
array('mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017'),
// if not using a username and password
array('mongodb://%mongodb_host%:27017'),
)));

$container->setDefinition('session.handler.mongo', new Definition(
'Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler',
array(new Reference('mongo_client'), '%mongo.session.options%')
));

The parameters used above should be defined somewhere in your application, often in your main
parameters configuration:

.. configuration-block::

.. code-block:: yaml

# app/config/parameters.yml
parameters:
# ...
mongo.session.options:
database: session_db # your MongoDB database name
collection: session # your MongoDB collection name
mongodb_host: 1.2.3.4 # your MongoDB server's IP
mongodb_username: my_username
mongodb_password: my_password

.. code-block:: xml

<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony
http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<parameters>
<parameter key="mongo.session.options" type="collection">
<!-- your MongoDB database name -->
<parameter key="database">session_db</parameter>
<!-- your MongoDB collection name -->
<parameter key="collection">session</parameter>
</parameter>
<!-- your MongoDB server's IP -->
<parameter key="mongodb_host">1.2.3.4</parameter>
<parameter key="mongodb_username">my_username</parameter>
<parameter key="mongodb_password">my_password</parameter>
</parameters>
</container>

.. code-block:: php

use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;

$container->setParameter('mongo.session.options', array(
'database' => 'session_db', // your MongoDB database name
'collection' => 'session', // your MongoDB collection name
));
$container->setParameter('mongodb_host', '1.2.3.4'); // your MongoDB server's IP
$container->setParameter('mongodb_username', 'my_username');
$container->setParameter('mongodb_password', 'my_password');

Setting Up the MongoDB Collection
---------------------------------
Copy link
Member

Choose a reason for hiding this comment

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

Minor issue: please leave an empty line after the headline underline. Thanks.


Because MongoDB uses dynamic collection schemas, you do not need to do anything to initialize your
session collection. However, you may want to add an index to improve garbage collection performance.
From the `MongoDB shell`_:

.. code-block:: sql

use session_db
db.session.ensureIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )

.. _installed and configured a MongoDB server: http://docs.mongodb.org/manual/installation/
.. _MongoDB shell: http://docs.mongodb.org/v2.2/tutorial/getting-started-with-the-mongo-shell/
2 changes: 2 additions & 0 deletions cookbook/map.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* :doc:`/cookbook/configuration/apache_router`
* :doc:`/cookbook/configuration/web_server_configuration`
* :doc:`/cookbook/configuration/configuration_organization`
* :doc:`/cookbook/configuration/mongodb_session_storage`

* :doc:`/cookbook/console/index`

Expand Down Expand Up @@ -187,6 +188,7 @@
* :doc:`/cookbook/session/sessions_directory`
* :doc:`/cookbook/session/php_bridge`
* (configuration) :doc:`/cookbook/configuration/pdo_session_storage`
* (configuration) :doc:`/cookbook/configuration/mongodb_session_storage`
* :doc:`/cookbook/session/avoid_session_start`

* **symfony1**
Expand Down
5 changes: 3 additions & 2 deletions cookbook/session/sessions_directory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ that your current sessions aren't lost when you clear Symfony's cache.
Using a different session save handler is an excellent (yet more complex)
method of session management available within Symfony. See
:doc:`/components/http_foundation/session_configuration` for a
discussion of session save handlers. There is also an entry in the cookbook
about storing sessions in the :doc:`database </cookbook/configuration/pdo_session_storage>`.
discussion of session save handlers. There are also entries in the cookbook
about storing sessions in a :doc:`relational database </cookbook/configuration/pdo_session_storage>`
or a :doc:`NoSQL database </cookbook/configuration/mongodb_session_storage>`.

To change the directory in which Symfony saves session data, you only need
change the framework configuration. In this example, you will change the
Expand Down