6
votes

I'll try to be as detailed as possible because I was searching for now , 75 hours for a solution ..

Brace yourselves.. here we go :

I'm trying to implement the MemcacheD session handler for Symfony2 :
I have downloaded the necessary libraries and then configured Symfony2 as follows:

In app/config.yml :

imports:
    # ....
    - { resource: services/session.yml }

framework:
    # ....
    session:
      handler_id:     session.handler.memcached

app/config/parameters.yml:

session_memcached_host:     127.0.0.1
session_memcached_port:     11211
session_memcached_prefix:   ng_
session_memcached_expire:   43200

app/services/session.yml :

services:
    session.memcached:
        class: Memcached
        arguments:
            persistent_id: %session_memcached_prefix%
        calls:
            - [ addServer, [ %session_memcached_host%, %session_memcached_port% ]]

    session.handler.memcached:
        class:     Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler
        arguments: [@session.memcached, { prefix: %session_memcached_prefix%, expiretime: %session_memcached_expire% }]

My biggest Question so far is : How do you start a session ?

Normally, you would have $session = new Session(); but not for handlers, since the documentation states (code converted to Memcached):

$storage = new NativeSessionStorage(array(), new MemcachedSessionHandler());
$session = new Session($storage); 

and this is some really weird, because the constructor needs a Memcached instance for argument, which is not given in the example of the official docs

What I did was to get the instance from the service running :

$memcached = $this->get('session.memcached');
$storage = new NativeSessionStorage(array(), new MemcachedSessionHandler($memcached));
$session = new Session($storage); 

This didn't throw any exception but then again, so I filled the session with data:

$session->set('userName', $name);
$session->set('userfName', $fname);
$session->set('userPass', $pass);
$session->set('userId', $userId);
$session->set('userPost', $userPost);
$session->set('userImage', $userImage);
$session->set('logged', true);

Everything is perfect? Wait for it...I go on another controller and run the following:

$session = $this->get('session');
var_dump($session->get('userId')); // returns null

This means that either the session was not persisted (Memcached log says otherwise) or I don't do it right, which leads to my second question: How do I read sessions from the Memcached Server?

Please, I really need this to work because I need them in websockets project.

Following the comments this is what I did:

app/config/config.yml:

session:
    cookie_lifetime: 43200
    # handler_id set to null will use default session handler from php.ini
    handler_id:  session
    save_path: ~

app/config/services.yml:

services:
    session.memcached:
        class: Memcached
        arguments:
            persistent_id: %session_memcached_prefix%
        calls:
            - [ addServer, [ %session_memcached_host%, %session_memcached_port% ]]

session:
    class:     Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler
    arguments: [@session.memcached, { prefix: %session_memcached_prefix%, expiretime: %session_memcached_expire% }]

The error I get:

PHP Catchable fatal error: Argument 1 passed to Symfony\Component\HttpFoundation\Request::setSession() must implement interface Symfony\Component\HttpFoundation\Session\SessionInterface, instance of Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler given

2
$session = $this->get('session'); =/= $memcached = $this->get('session.memcached'); - better configure your session service as session (not as session.memcached), then you don't run into such mistakes.hakre
the first command gets the Session instance , the second gets the Memcached instance , I don't get your comment right .. can you explain ?Aysennoussi
Configure the session service to already use the memcached session. Then you only need to use $session = $this->get('session') (or better use parameter injection) and you do not need to care about whether it's memcached, on disk or stored engraved into stones on the moon.hakre
You're funny , I like you :D but help here "Configure the session service" what do you mean ?Aysennoussi
When you write $this->get('session') you're accessing an object that has been configured as "session service". It is configured in the service configuration for the entry "session". See Service Containerhakre

2 Answers

14
votes

Symfony full stack framework

If you use the full stack Symfony framework, than configuring memcached as a session handler is as simple as specifying it in your php.ini:

session.save_handler=memcached
session.save_path=localhost:11211

Make sure that the handler_id is set to null (~) in your app/config/config.yml. This way Symfony will use the native php handler:

framework:
    session:
        # handler_id set to null will use default session handler from php.ini
        handler_id:  ~

Now you can start using your session. It is going to be stored in memcached.

Accessing the session

Session can be accessed from the Request object:

$request->getSession()->set('name', 'Kuba');

HttpFoundation component

The same can be set up outside of a full stack framework with the HttpFoundation component alone:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;

$storage = new NativeSessionStorage(array());
$session = new Session($storage, new NamespacedAttributeBag());

$request = Request::createFromGlobals();
$request->setSession($session);

The above snippet sets the session up just like the full stack framework does (by default). This way, the script you'll put this code in, will share the session with a full Symfony application.

2
votes

There is a nice gist that will help you to start using MemcachedSessionHandler in your Symfony 2 project.