added a dbal session storage
This commit is contained in:
parent
c5e0c80a76
commit
a1888b2f01
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\HttpFoundation;
|
||||
|
||||
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||
|
||||
use Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage;
|
||||
use Doctrine\DBAL\Driver\Connection;
|
||||
|
||||
/**
|
||||
* DBAL based session storage.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class DbalSessionStorage extends NativeSessionStorage
|
||||
{
|
||||
private $con;
|
||||
private $tableName;
|
||||
|
||||
public function __construct(Connection $con, $tableName = 'sessions', array $options = array())
|
||||
{
|
||||
parent::__construct($options);
|
||||
|
||||
$this->con = $con;
|
||||
$this->tableName = $tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the session.
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
if (self::$sessionStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// use this object as the session handler
|
||||
session_set_save_handler(
|
||||
array($this, 'sessionOpen'),
|
||||
array($this, 'sessionClose'),
|
||||
array($this, 'sessionRead'),
|
||||
array($this, 'sessionWrite'),
|
||||
array($this, 'sessionDestroy'),
|
||||
array($this, 'sessionGC')
|
||||
);
|
||||
|
||||
parent::start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a session.
|
||||
*
|
||||
* @param string $path (ignored)
|
||||
* @param string $name (ignored)
|
||||
*
|
||||
* @return Boolean true, if the session was opened, otherwise an exception is thrown
|
||||
*/
|
||||
public function sessionOpen($path = null, $name = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a session.
|
||||
*
|
||||
* @return Boolean true, if the session was closed, otherwise false
|
||||
*/
|
||||
public function sessionClose()
|
||||
{
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a session.
|
||||
*
|
||||
* @param string $id A session ID
|
||||
*
|
||||
* @return Boolean true, if the session was destroyed, otherwise an exception is thrown
|
||||
*
|
||||
* @throws \RuntimeException If the session cannot be destroyed
|
||||
*/
|
||||
public function sessionDestroy($id)
|
||||
{
|
||||
try {
|
||||
$this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_id = :id", array(
|
||||
'id' => $id,
|
||||
));
|
||||
} catch (\PDOException $e) {
|
||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up old sessions.
|
||||
*
|
||||
* @param int $lifetime The lifetime of a session
|
||||
*
|
||||
* @return Boolean true, if old sessions have been cleaned, otherwise an exception is thrown
|
||||
*
|
||||
* @throws \RuntimeException If any old sessions cannot be cleaned
|
||||
*/
|
||||
public function sessionGC($lifetime)
|
||||
{
|
||||
try {
|
||||
$this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_time < :time", array(
|
||||
'time' => time() - $this->options['lifetime'],
|
||||
));
|
||||
} catch (\PDOException $e) {
|
||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a session.
|
||||
*
|
||||
* @param string $id A session ID
|
||||
*
|
||||
* @return string The session data if the session was read or created, otherwise an exception is thrown
|
||||
*
|
||||
* @throws \RuntimeException If the session cannot be read
|
||||
*/
|
||||
public function sessionRead($id)
|
||||
{
|
||||
try {
|
||||
$data = $this->con->executeQuery("SELECT sess_data FROM {$this->tableName} WHERE sess_id = :id", array(
|
||||
'id' => $id,
|
||||
))->fetchColumn();
|
||||
|
||||
if (false !== $data) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// session does not exist, create it
|
||||
$this->createNewSession($id);
|
||||
|
||||
return '';
|
||||
} catch (\PDOException $e) {
|
||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes session data.
|
||||
*
|
||||
* @param string $id A session ID
|
||||
* @param string $data A serialized chunk of session data
|
||||
*
|
||||
* @return Boolean true, if the session was written, otherwise an exception is thrown
|
||||
*
|
||||
* @throws \RuntimeException If the session data cannot be written
|
||||
*/
|
||||
public function sessionWrite($id, $data)
|
||||
{
|
||||
$platform = $this->con->getDatabasePlatform();
|
||||
|
||||
// this should maybe be abstracted in Doctrine DBAL
|
||||
if ($platform instanceof MySqlPlatform) {
|
||||
$sql = "INSERT INTO {$this->tableName} (sess_id, sess_data, sess_time) VALUES (:id, :data, :time) "
|
||||
."ON DUPLICATE KEY UPDATE sess_data = VALUES(sess_data), sess_time = CASE WHEN sess_time = :time THEN (VALUES(sess_time) + 1) ELSE VALUES(sess_time) END";
|
||||
} else {
|
||||
$sql = "UPDATE {$this->tableName} SET sess_data = :data, sess_time = :time WHERE sess_id = :id";
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $this->con->executeQuery($sql, array(
|
||||
'id' => $id,
|
||||
'data' => $data,
|
||||
'time' => time(),
|
||||
));
|
||||
|
||||
if (!$stmt->rowCount()) {
|
||||
// No session exists in the database to update. This happens when we have called
|
||||
// session_regenerate_id()
|
||||
$this->createNewSession($id, $data);
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session with the given $id and $data
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $data
|
||||
*/
|
||||
private function createNewSession($id, $data = '')
|
||||
{
|
||||
$this->con->executeQuery("INSERT INTO {$this->tableName} (sess_id, sess_data, sess_time) VALUES (:id, :data, :time)", array(
|
||||
'id' => $id,
|
||||
'data' => $data,
|
||||
'time' => time(),
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\HttpFoundation;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
/**
|
||||
* DBAL Session Storage Schema.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
final class DbalSessionStorageSchema extends Schema
|
||||
{
|
||||
private $tableName;
|
||||
|
||||
public function __construct($tableName = 'sessions')
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->tableName = $tableName;
|
||||
$this->addSessionTable();
|
||||
}
|
||||
|
||||
public function addToSchema(Schema $schema)
|
||||
{
|
||||
foreach ($this->getTables() as $table) {
|
||||
$schema->_addTable($table);
|
||||
}
|
||||
}
|
||||
|
||||
private function addSessionTable()
|
||||
{
|
||||
$table = $this->createTable($this->tableName);
|
||||
$table->addColumn('sess_id', 'string');
|
||||
$table->addColumn('sess_data', 'text')->setNotNull(true);
|
||||
$table->addColumn('sess_time', 'integer')->setNotNull(true)->setUnsigned(true);
|
||||
$table->setPrimaryKey(array('sess_id'));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user