Add mongodb session storage

Some changes based on @stof and @stloyd suggestions

Some changes based on @vicb suggestions

Some changes based on @vicb suggestions

Add changes
This commit is contained in:
Markus Bachmann 2012-04-19 20:34:49 +02:00
parent 4d8461f243
commit 40df3bf86f
2 changed files with 242 additions and 0 deletions

View File

@ -0,0 +1,145 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* MongoDB session handler
*
* @author Markus Bachmann <markus.bachmann@bachi.biz>
*/
class MongoDbSessionHandler implements \SessionHandlerInterface
{
/**
* @var \Mongo
*/
private $mongo;
/**
* @var \MongoCollection
*/
private $collection;
/**
* @var array
*/
private $options;
/**
* Constructor.
*
* @param \Mongo $mongo A "Mongo" instance
* @param array $options An associative array of field options
*
* @throws \InvalidArgumentException When "database" or "collection" not provided
*/
public function __construct(\Mongo $mongo, array $options)
{
if (!isset($options['database']) || !isset($options['collection'])) {
throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler');
}
$this->mongo = $mongo;
$this->options = array_merge(array(
'id_field' => 'sess_id',
'data_field' => 'sess_data',
'time_field' => 'sess_time',
), $options);
}
/**
* {@inheritDoc}
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* {@inheritDoc}
*/
public function close()
{
return true;
}
/**
* {@inheritDoc}
*/
public function destroy($sessionId)
{
$this->getCollection()->remove(
array($this->options['id_field'] => $sessionId),
array('justOne' => true)
);
return true;
}
/**
* {@inheritDoc}
*/
public function gc($lifetime)
{
$time = new \MongoTimestamp(time() - $lifetime);
$this->getCollection()->remove(array(
$this->options['time_field'] => array('$lt' => $time),
));
}
/**
* {@inheritDoc]
*/
public function write($sessionId, $data)
{
$data = array(
$this->options['id_field'] => $sessionId,
$this->options['data_field'] => new \MongoBinData($data),
$this->options['time_field'] => new \MongoTimestamp()
);
$this->getCollection()->update(
array($this->options['id_field'] => $sessionId),
array('$set' => $data),
array('upsert' => true)
);
return true;
}
/**
* {@inheritDoc}
*/
public function read($sessionId)
{
$dbData = $this->getCollection()->findOne(array(
$this->options['id_field'] => $sessionId,
));
return null === $dbData ? '' : $dbData[$this->options['data_field']]->bin;
}
/**
* Return a "MongoCollection" instance
*
* @return \MongoCollection
*/
private function getCollection()
{
if (null === $this->collection) {
$this->collection = $this->mongo->selectDB($this->options['database'])->selectCollection($this->options['collection']);
}
return $this->collection;
}
}

View File

@ -0,0 +1,97 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler;
/**
* @author Markus Bachmann <markus.bachmann@bachi.biz>
*/
class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
private static $mongo;
public static function setUpBeforeClass()
{
if (class_exists('\Mongo')) {
try {
self::$mongo = new \Mongo();
} catch (\Exception $e) {
}
}
}
protected function setUp()
{
if (null === self::$mongo) {
$this->markTestSkipped('MongoDbSessionHandler requires the php "mongo" extension and a mongodb server on localhost');
}
$this->options = array('database' => 'sf2-test', 'collection' => 'session-test');
$this->options = array('database' => 'sf2-test', 'collection' => 'session-test');
$this->storage = new MongoDbSessionHandler(self::$mongo, $this->options);
}
protected function tearDown()
{
self::$mongo->dropDB($this->options['database']);
}
public function testOpenMethodAlwaysReturnTrue()
{
$this->assertTrue($this->storage->open('test', 'test'), 'The "open" method should always return true');
}
public function testCloseMethodAlwaysReturnTrue()
{
$this->assertTrue($this->storage->close(), 'The "close" method should always return true');
}
public function testWrite()
{
$this->assertTrue($this->storage->write('foo', 'bar'));
$this->assertEquals('bar', $this->storage->read('foo'));
}
public function testReplaceSessionData()
{
$this->storage->write('foo', 'bar');
$this->storage->write('foo', 'foobar');
$coll = self::$mongo->selectDB($this->options['database'])->selectCollection($this->options['collection']);
$this->assertEquals('foobar', $this->storage->read('foo'));
$this->assertEquals(1, $coll->find(array('sess_id' => 'foo'))->count());
}
public function testDestroy()
{
$this->storage->write('foo', 'bar');
$this->storage->destroy('foo');
$this->assertEquals('', $this->storage->read('foo'));
}
public function testGc()
{
$this->storage->write('foo', 'bar');
$this->storage->write('bar', 'foo');
$coll = self::$mongo->selectDB($this->options['database'])->selectCollection($this->options['collection']);
$this->assertEquals(2, $coll->count());
$this->storage->gc(-1);
$this->assertEquals(0, $coll->count());
}
}