[Doctrine Bridge] simplify session handler by using main connection

This commit is contained in:
Tobias Schultze 2014-04-19 23:32:54 +02:00
parent 567213fea9
commit 6518b74995
2 changed files with 24 additions and 43 deletions

View File

@ -12,21 +12,12 @@
namespace Symfony\Bridge\Doctrine\HttpFoundation; namespace Symfony\Bridge\Doctrine\HttpFoundation;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\Mysqli\MysqliConnection;
use Doctrine\DBAL\Driver\OCI8\OCI8Connection;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\SQLSrv\SQLSrvConnection;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
/** /**
* DBAL based session storage. * DBAL based session storage.
* *
* This implementation is very similar to Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler * This implementation is very similar to Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
* but uses the Doctrine driver connection interface and thus also works with non-PDO-based drivers like mysqli and OCI8. * but uses a Doctrine connection and thus also works with non-PDO-based drivers like mysqli and OCI8.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
@ -35,7 +26,7 @@ use Doctrine\DBAL\Platforms\SQLServerPlatform;
class DbalSessionHandler implements \SessionHandlerInterface class DbalSessionHandler implements \SessionHandlerInterface
{ {
/** /**
* @var DriverConnection * @var Connection
*/ */
private $con; private $con;
@ -62,10 +53,10 @@ class DbalSessionHandler implements \SessionHandlerInterface
/** /**
* Constructor. * Constructor.
* *
* @param DriverConnection $con A driver connection, preferably a wrapper Doctrine\DBAL\Connection for lazy connections * @param Connection $con A connection
* @param string $tableName Table name * @param string $tableName Table name
*/ */
public function __construct(DriverConnection $con, $tableName = 'sessions') public function __construct(Connection $con, $tableName = 'sessions')
{ {
$this->con = $con; $this->con = $con;
$this->table = $tableName; $this->table = $tableName;
@ -74,7 +65,7 @@ class DbalSessionHandler implements \SessionHandlerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function open($path = null, $name = null) public function open($savePath, $sessionName)
{ {
return true; return true;
} }
@ -90,14 +81,14 @@ class DbalSessionHandler implements \SessionHandlerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function destroy($id) public function destroy($sessionId)
{ {
// delete the record associated with this id // delete the record associated with this id
$sql = "DELETE FROM $this->table WHERE $this->idCol = :id"; $sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
try { try {
$stmt = $this->con->prepare($sql); $stmt = $this->con->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$stmt->execute(); $stmt->execute();
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \RuntimeException(sprintf('Exception was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e); throw new \RuntimeException(sprintf('Exception was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e);
@ -109,14 +100,14 @@ class DbalSessionHandler implements \SessionHandlerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function gc($lifetime) public function gc($maxlifetime)
{ {
// delete the session records that have expired // delete the session records that have expired
$sql = "DELETE FROM $this->table WHERE $this->timeCol < :time"; $sql = "DELETE FROM $this->table WHERE $this->timeCol < :time";
try { try {
$stmt = $this->con->prepare($sql); $stmt = $this->con->prepare($sql);
$stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT); $stmt->bindValue(':time', time() - $maxlifetime, \PDO::PARAM_INT);
$stmt->execute(); $stmt->execute();
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \RuntimeException(sprintf('Exception was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e); throw new \RuntimeException(sprintf('Exception was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e);
@ -128,13 +119,13 @@ class DbalSessionHandler implements \SessionHandlerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function read($id) public function read($sessionId)
{ {
$sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id"; $sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id";
try { try {
$stmt = $this->con->prepare($sql); $stmt = $this->con->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$stmt->execute(); $stmt->execute();
// We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed // We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed
@ -153,7 +144,7 @@ class DbalSessionHandler implements \SessionHandlerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function write($id, $data) public function write($sessionId, $data)
{ {
// Session data can contain non binary safe characters so we need to encode it. // Session data can contain non binary safe characters so we need to encode it.
$encoded = base64_encode($data); $encoded = base64_encode($data);
@ -166,7 +157,7 @@ class DbalSessionHandler implements \SessionHandlerInterface
if (null !== $mergeSql) { if (null !== $mergeSql) {
$mergeStmt = $this->con->prepare($mergeSql); $mergeStmt = $this->con->prepare($mergeSql);
$mergeStmt->bindParam(':id', $id, \PDO::PARAM_STR); $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); $mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
$mergeStmt->execute(); $mergeStmt->execute();
@ -180,13 +171,13 @@ class DbalSessionHandler implements \SessionHandlerInterface
$deleteStmt = $this->con->prepare( $deleteStmt = $this->con->prepare(
"DELETE FROM $this->table WHERE $this->idCol = :id" "DELETE FROM $this->table WHERE $this->idCol = :id"
); );
$deleteStmt->bindParam(':id', $id, \PDO::PARAM_STR); $deleteStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$deleteStmt->execute(); $deleteStmt->execute();
$insertStmt = $this->con->prepare( $insertStmt = $this->con->prepare(
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)" "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"
); );
$insertStmt->bindParam(':id', $id, \PDO::PARAM_STR); $insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); $insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT); $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
$insertStmt->execute(); $insertStmt->execute();
@ -211,32 +202,24 @@ class DbalSessionHandler implements \SessionHandlerInterface
*/ */
private function getMergeSql() private function getMergeSql()
{ {
$platform = $pdoDriver = null; $platform = $this->con->getDatabasePlatform()->getName();
if ($this->con instanceof Connection) { switch ($platform) {
$platform = $this->con->getDatabasePlatform(); case 'mysql':
} elseif ($this->con instanceof PDOConnection) {
$pdoDriver = $this->con->getAttribute(\PDO::ATTR_DRIVER_NAME);
}
switch (true) {
case $this->con instanceof MysqliConnection || $platform instanceof MySqlPlatform || 'mysql' === $pdoDriver:
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " . return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " .
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)"; "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)";
case $this->con instanceof OCI8Connection || $platform instanceof OraclePlatform || 'oci' === $pdoDriver: case 'oracle':
// DUAL is Oracle specific dummy table // DUAL is Oracle specific dummy table
return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) " . return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) " .
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " . "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " .
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data"; "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data";
case $this->con instanceof SQLSrvConnection || $platform instanceof SQLServerPlatform || 'sqlsrv' === $pdoDriver: case 'mssql':
// MS SQL Server requires MERGE be terminated by semicolon // MS SQL Server requires MERGE be terminated by semicolon
return "MERGE INTO $this->table USING (SELECT 'x' AS dummy) AS src ON ($this->idCol = :id) " . return "MERGE INTO $this->table USING (SELECT 'x' AS dummy) AS src ON ($this->idCol = :id) " .
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " . "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " .
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data;"; "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data;";
case $platform instanceof SqlitePlatform || 'sqlite' === $pdoDriver: case 'sqlite':
return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"; return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)";
} }
return null;
} }
} }

View File

@ -29,9 +29,7 @@ class DbalSessionHandlerTest extends \PHPUnit_Framework_TestCase
public function testConstruct() public function testConstruct()
{ {
$this->connection = $this->getMock('Doctrine\DBAL\Driver\Connection'); $connection = $this->getMockBuilder('Doctrine\DBAL\Connection')->disableOriginalConstructor()->getMock();
$mock = $this->getMockBuilder('Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler'); $handler = new DbalSessionHandler($connection);
$mock->setConstructorArgs(array($this->connection));
$this->driver = $mock->getMock();
} }
} }