Skip to content

Instantly share code, notes, and snippets.

@onatskyy
Forked from makasim/DbIsolationExtension.php
Created March 14, 2016 15:15
Show Gist options
  • Save onatskyy/5ece0eab572fc39ea6a6 to your computer and use it in GitHub Desktop.
Save onatskyy/5ece0eab572fc39ea6a6 to your computer and use it in GitHub Desktop.
Persisted connection.
<?php
namespace Base\Doctrine\DBAL;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
/**
* Connection wrapper sharing the same db handle across multiple requests
*
* Allows multiple Connection instances to run in the same transaction
*/
class PersistedConnection extends Connection
{
/**
* @var DriverConnection[]
*/
protected static $persistedConnections;
/**
* @var int[]
*/
protected static $persistedTransactionNestingLevels;
/**
* {@inheritDoc}
*/
public function connect()
{
if ($this->isConnected()) {
return false;
}
if ($this->hasPersistedConnection()) {
$this->_conn = $this->getPersistedConnection();
$this->setConnected(true);
} else {
parent::connect();
$this->setPersistedConnection($this->_conn);
}
return true;
}
/**
* {@inheritDoc}
*/
public function close($force = false)
{
if ($force) {
parent::close();
$this->unsetPersistedConnection();
}
}
/**
* {@inheritDoc}
*/
public function beginTransaction()
{
$this->wrapTransactionNestingLevel('beginTransaction');
}
/**
* {@inheritDoc}
*/
public function commit()
{
$this->wrapTransactionNestingLevel('commit');
}
/**
* {@inheritDoc}
*/
public function rollBack()
{
$this->wrapTransactionNestingLevel('rollBack');
}
/**
* {@inheritDoc}
*/
public function isTransactionActive()
{
$this->setTransactionNestingLevel($this->getPersistedTransactionNestingLevel());
return parent::isTransactionActive();
}
/**
* @param int $level
*/
private function setTransactionNestingLevel($level)
{
$rp = new \ReflectionProperty(Connection::class, '_transactionNestingLevel');
$rp->setAccessible(true);
$rp->setValue($this, $level);
$rp->setAccessible(false);
}
/**
* @param string $method
*
* @throws \Exception
*/
private function wrapTransactionNestingLevel($method)
{
$e = null;
$this->setTransactionNestingLevel($this->getPersistedTransactionNestingLevel());
try {
call_user_func(array('parent', $method));
} catch (\Exception $e) {
$var = 1;
}
$this->setPersistedTransactionNestingLevel($this->getTransactionNestingLevel());
if ($e) {
throw $e;
}
}
/**
* @param bool $connected
*/
protected function setConnected($connected)
{
$rp = new \ReflectionProperty(Connection::class, '_isConnected');
$rp->setAccessible(true);
$rp->setValue($this, $connected);
$rp->setAccessible(false);
}
/**
* @return int
*/
protected function getPersistedTransactionNestingLevel()
{
if (isset(static::$persistedTransactionNestingLevels[$this->getConnectionId()])) {
return static::$persistedTransactionNestingLevels[$this->getConnectionId()];
}
return 0;
}
/**
* @param int $level
*/
protected function setPersistedTransactionNestingLevel($level)
{
static::$persistedTransactionNestingLevels[$this->getConnectionId()] = $level;
}
/**
* @param DriverConnection $connection
*/
protected function setPersistedConnection(DriverConnection $connection)
{
static::$persistedConnections[$this->getConnectionId()] = $connection;
}
/**
* @return bool
*/
protected function hasPersistedConnection()
{
return isset(static::$persistedConnections[$this->getConnectionId()]);
}
/**
* @return DriverConnection
*/
protected function getPersistedConnection()
{
return static::$persistedConnections[$this->getConnectionId()];
}
/**
* @return DriverConnection
*/
protected function unsetPersistedConnection()
{
unset(static::$persistedConnections[$this->getConnectionId()]);
unset(static::$persistedTransactionNestingLevels[$this->getConnectionId()]);
}
/**
* @return string
*/
protected function getConnectionId()
{
return md5(serialize($this->getParams()));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment