Introduced the concept of DBAL\Transaction and ORM\EntityTransaction.
This commit is contained in:
parent
50f3435e84
commit
6705d9b9cc
@ -44,26 +44,6 @@ use PDO, Closure,
|
|||||||
*/
|
*/
|
||||||
class Connection implements DriverConnection
|
class Connection implements DriverConnection
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Constant for transaction isolation level READ UNCOMMITTED.
|
|
||||||
*/
|
|
||||||
const TRANSACTION_READ_UNCOMMITTED = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant for transaction isolation level READ COMMITTED.
|
|
||||||
*/
|
|
||||||
const TRANSACTION_READ_COMMITTED = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant for transaction isolation level REPEATABLE READ.
|
|
||||||
*/
|
|
||||||
const TRANSACTION_REPEATABLE_READ = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant for transaction isolation level SERIALIZABLE.
|
|
||||||
*/
|
|
||||||
const TRANSACTION_SERIALIZABLE = 4;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The wrapped driver connection.
|
* The wrapped driver connection.
|
||||||
*
|
*
|
||||||
@ -88,20 +68,6 @@ class Connection implements DriverConnection
|
|||||||
*/
|
*/
|
||||||
private $_isConnected = false;
|
private $_isConnected = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* The transaction nesting level.
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $_transactionNestingLevel = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently active transaction isolation level.
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $_transactionIsolationLevel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parameters used during creation of the Connection instance.
|
* The parameters used during creation of the Connection instance.
|
||||||
*
|
*
|
||||||
@ -130,14 +96,14 @@ class Connection implements DriverConnection
|
|||||||
* @var Doctrine\DBAL\Driver
|
* @var Doctrine\DBAL\Driver
|
||||||
*/
|
*/
|
||||||
protected $_driver;
|
protected $_driver;
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag that indicates whether the current transaction is marked for rollback only.
|
|
||||||
*
|
|
||||||
* @var boolean
|
|
||||||
*/
|
|
||||||
private $_isRollbackOnly = false;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DBAL Transaction.
|
||||||
|
*
|
||||||
|
* @var Doctrine\DBAL\Transaction
|
||||||
|
*/
|
||||||
|
protected $_transaction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of the Connection class.
|
* Initializes a new instance of the Connection class.
|
||||||
*
|
*
|
||||||
@ -168,6 +134,7 @@ class Connection implements DriverConnection
|
|||||||
|
|
||||||
$this->_config = $config;
|
$this->_config = $config;
|
||||||
$this->_eventManager = $eventManager;
|
$this->_eventManager = $eventManager;
|
||||||
|
|
||||||
if ( ! isset($params['platform'])) {
|
if ( ! isset($params['platform'])) {
|
||||||
$this->_platform = $driver->getDatabasePlatform();
|
$this->_platform = $driver->getDatabasePlatform();
|
||||||
} else if ($params['platform'] instanceof Platforms\AbstractPlatform) {
|
} else if ($params['platform'] instanceof Platforms\AbstractPlatform) {
|
||||||
@ -175,7 +142,8 @@ class Connection implements DriverConnection
|
|||||||
} else {
|
} else {
|
||||||
throw DBALException::invalidPlatformSpecified();
|
throw DBALException::invalidPlatformSpecified();
|
||||||
}
|
}
|
||||||
$this->_transactionIsolationLevel = $this->_platform->getDefaultTransactionIsolationLevel();
|
|
||||||
|
$this->_transaction = new Transaction($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -278,6 +246,16 @@ class Connection implements DriverConnection
|
|||||||
return $this->_platform;
|
return $this->_platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the DBAL Transaction instance.
|
||||||
|
*
|
||||||
|
* @return Doctrine\DBAL\Transaction
|
||||||
|
*/
|
||||||
|
public function getTransaction()
|
||||||
|
{
|
||||||
|
return $this->_transaction;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the connection with the database.
|
* Establishes the connection with the database.
|
||||||
*
|
*
|
||||||
@ -356,16 +334,6 @@ class Connection implements DriverConnection
|
|||||||
return $this->_isConnected;
|
return $this->_isConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether a transaction is currently active.
|
|
||||||
*
|
|
||||||
* @return boolean TRUE if a transaction is currently active, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
public function isTransactionActive()
|
|
||||||
{
|
|
||||||
return $this->_transactionNestingLevel > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes an SQL DELETE statement on a table.
|
* Executes an SQL DELETE statement on a table.
|
||||||
*
|
*
|
||||||
@ -400,28 +368,6 @@ class Connection implements DriverConnection
|
|||||||
$this->_isConnected = false;
|
$this->_isConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the transaction isolation level.
|
|
||||||
*
|
|
||||||
* @param integer $level The level to set.
|
|
||||||
*/
|
|
||||||
public function setTransactionIsolation($level)
|
|
||||||
{
|
|
||||||
$this->_transactionIsolationLevel = $level;
|
|
||||||
|
|
||||||
return $this->executeUpdate($this->_platform->getSetTransactionIsolationSQL($level));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the currently active transaction isolation level.
|
|
||||||
*
|
|
||||||
* @return integer The current transaction isolation level.
|
|
||||||
*/
|
|
||||||
public function getTransactionIsolation()
|
|
||||||
{
|
|
||||||
return $this->_transactionIsolationLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes an SQL UPDATE statement on a table.
|
* Executes an SQL UPDATE statement on a table.
|
||||||
*
|
*
|
||||||
@ -585,10 +531,10 @@ class Connection implements DriverConnection
|
|||||||
* represents a row of the result set.
|
* represents a row of the result set.
|
||||||
* @return mixed The projected result of the query.
|
* @return mixed The projected result of the query.
|
||||||
*/
|
*/
|
||||||
public function project($query, array $params = array(), Closure $function)
|
public function project($query, array $params, Closure $function)
|
||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$stmt = $this->executeQuery($query, $params);
|
$stmt = $this->executeQuery($query, $params ?: array());
|
||||||
|
|
||||||
while ($row = $stmt->fetch()) {
|
while ($row = $stmt->fetch()) {
|
||||||
$result[] = $function($row);
|
$result[] = $function($row);
|
||||||
@ -659,16 +605,6 @@ class Connection implements DriverConnection
|
|||||||
return $this->_conn->exec($statement);
|
return $this->_conn->exec($statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current transaction nesting level.
|
|
||||||
*
|
|
||||||
* @return integer The nesting level. A value of 0 means there's no active transaction.
|
|
||||||
*/
|
|
||||||
public function getTransactionNestingLevel()
|
|
||||||
{
|
|
||||||
return $this->_transactionNestingLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the SQLSTATE associated with the last database operation.
|
* Fetch the SQLSTATE associated with the last database operation.
|
||||||
*
|
*
|
||||||
@ -708,73 +644,6 @@ class Connection implements DriverConnection
|
|||||||
return $this->_conn->lastInsertId($seqName);
|
return $this->_conn->lastInsertId($seqName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a transaction by suspending auto-commit mode.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function beginTransaction()
|
|
||||||
{
|
|
||||||
$this->connect();
|
|
||||||
|
|
||||||
if ($this->_transactionNestingLevel == 0) {
|
|
||||||
$this->_conn->beginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
++$this->_transactionNestingLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commits the current transaction.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @throws ConnectionException If the commit failed due to no active transaction or
|
|
||||||
* because the transaction was marked for rollback only.
|
|
||||||
*/
|
|
||||||
public function commit()
|
|
||||||
{
|
|
||||||
if ($this->_transactionNestingLevel == 0) {
|
|
||||||
throw ConnectionException::commitFailedNoActiveTransaction();
|
|
||||||
}
|
|
||||||
if ($this->_isRollbackOnly) {
|
|
||||||
throw ConnectionException::commitFailedRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->connect();
|
|
||||||
|
|
||||||
if ($this->_transactionNestingLevel == 1) {
|
|
||||||
$this->_conn->commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
--$this->_transactionNestingLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel any database changes done during the current transaction.
|
|
||||||
*
|
|
||||||
* this method can be listened with onPreTransactionRollback and onTransactionRollback
|
|
||||||
* eventlistener methods
|
|
||||||
*
|
|
||||||
* @throws ConnectionException If the rollback operation failed.
|
|
||||||
*/
|
|
||||||
public function rollback()
|
|
||||||
{
|
|
||||||
if ($this->_transactionNestingLevel == 0) {
|
|
||||||
throw ConnectionException::rollbackFailedNoActiveTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->connect();
|
|
||||||
|
|
||||||
if ($this->_transactionNestingLevel == 1) {
|
|
||||||
$this->_transactionNestingLevel = 0;
|
|
||||||
$this->_conn->rollback();
|
|
||||||
$this->_isRollbackOnly = false;
|
|
||||||
} else {
|
|
||||||
$this->_isRollbackOnly = true;
|
|
||||||
--$this->_transactionNestingLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the wrapped driver connection.
|
* Gets the wrapped driver connection.
|
||||||
*
|
*
|
||||||
@ -802,34 +671,6 @@ class Connection implements DriverConnection
|
|||||||
return $this->_schemaManager;
|
return $this->_schemaManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks the current transaction so that the only possible
|
|
||||||
* outcome for the transaction to be rolled back.
|
|
||||||
*
|
|
||||||
* @throws ConnectionException If no transaction is active.
|
|
||||||
*/
|
|
||||||
public function setRollbackOnly()
|
|
||||||
{
|
|
||||||
if ($this->_transactionNestingLevel == 0) {
|
|
||||||
throw ConnectionException::noActiveTransaction();
|
|
||||||
}
|
|
||||||
$this->_isRollbackOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the current transaction is marked for rollback only.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
* @throws ConnectionException If no transaction is active.
|
|
||||||
*/
|
|
||||||
public function getRollbackOnly()
|
|
||||||
{
|
|
||||||
if ($this->_transactionNestingLevel == 0) {
|
|
||||||
throw ConnectionException::noActiveTransaction();
|
|
||||||
}
|
|
||||||
return $this->_isRollbackOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a given value to its database representation according to the conversion
|
* Converts a given value to its database representation according to the conversion
|
||||||
* rules of a specific DBAL mapping type.
|
* rules of a specific DBAL mapping type.
|
||||||
|
@ -36,9 +36,6 @@ interface Connection
|
|||||||
function quote($input, $type=\PDO::PARAM_STR);
|
function quote($input, $type=\PDO::PARAM_STR);
|
||||||
function exec($statement);
|
function exec($statement);
|
||||||
function lastInsertId($name = null);
|
function lastInsertId($name = null);
|
||||||
function beginTransaction();
|
|
||||||
function commit();
|
|
||||||
function rollBack();
|
|
||||||
function errorCode();
|
function errorCode();
|
||||||
function errorInfo();
|
function errorInfo();
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ namespace Doctrine\DBAL\Driver\OCI8;
|
|||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class OCI8Connection implements \Doctrine\DBAL\Driver\Connection
|
class OCI8Connection implements \Doctrine\DBAL\Driver\Connection, \Doctrine\DBAL\Driver\Transaction
|
||||||
{
|
{
|
||||||
private $_dbh;
|
private $_dbh;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ use \PDO;
|
|||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class PDOConnection extends PDO implements Connection
|
class PDOConnection extends PDO implements Connection, Transaction
|
||||||
{
|
{
|
||||||
public function __construct($dsn, $user = null, $password = null, array $options = null)
|
public function __construct($dsn, $user = null, $password = null, array $options = null)
|
||||||
{
|
{
|
||||||
|
@ -26,7 +26,7 @@ namespace Doctrine\DBAL\Driver\PDOMsSql;
|
|||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection
|
class Connection extends \Doctrine\DBAL\Driver\PDOConnection
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Performs the rollback.
|
* Performs the rollback.
|
||||||
|
42
lib/Doctrine/DBAL/Driver/Transaction.php
Normal file
42
lib/Doctrine/DBAL/Driver/Transaction.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\DBAL\Driver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transaction interface.
|
||||||
|
* Each Driver Connection must implement this interface.
|
||||||
|
*
|
||||||
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
|
* @link www.doctrine-project.org
|
||||||
|
* @since 2.0
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
|
* @author Jonathan Wage <jonwage@gmail.com>
|
||||||
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
|
*/
|
||||||
|
interface Transaction
|
||||||
|
{
|
||||||
|
function beginTransaction();
|
||||||
|
function commit();
|
||||||
|
function rollBack();
|
||||||
|
}
|
@ -23,6 +23,7 @@ namespace Doctrine\DBAL\Platforms;
|
|||||||
|
|
||||||
use Doctrine\DBAL\DBALException,
|
use Doctrine\DBAL\DBALException,
|
||||||
Doctrine\DBAL\Connection,
|
Doctrine\DBAL\Connection,
|
||||||
|
Doctrine\DBAL\Transaction,
|
||||||
Doctrine\DBAL\Types,
|
Doctrine\DBAL\Types,
|
||||||
Doctrine\DBAL\Schema\Table,
|
Doctrine\DBAL\Schema\Table,
|
||||||
Doctrine\DBAL\Schema\Index,
|
Doctrine\DBAL\Schema\Index,
|
||||||
@ -1445,13 +1446,13 @@ abstract class AbstractPlatform
|
|||||||
protected function _getTransactionIsolationLevelSQL($level)
|
protected function _getTransactionIsolationLevelSQL($level)
|
||||||
{
|
{
|
||||||
switch ($level) {
|
switch ($level) {
|
||||||
case Connection::TRANSACTION_READ_UNCOMMITTED:
|
case Transaction::READ_UNCOMMITTED:
|
||||||
return 'READ UNCOMMITTED';
|
return 'READ UNCOMMITTED';
|
||||||
case Connection::TRANSACTION_READ_COMMITTED:
|
case Transaction::READ_COMMITTED:
|
||||||
return 'READ COMMITTED';
|
return 'READ COMMITTED';
|
||||||
case Connection::TRANSACTION_REPEATABLE_READ:
|
case Transaction::REPEATABLE_READ:
|
||||||
return 'REPEATABLE READ';
|
return 'REPEATABLE READ';
|
||||||
case Connection::TRANSACTION_SERIALIZABLE:
|
case Transaction::SERIALIZABLE:
|
||||||
return 'SERIALIZABLE';
|
return 'SERIALIZABLE';
|
||||||
default:
|
default:
|
||||||
throw new \InvalidArgumentException('Invalid isolation level:' . $level);
|
throw new \InvalidArgumentException('Invalid isolation level:' . $level);
|
||||||
@ -1584,11 +1585,11 @@ abstract class AbstractPlatform
|
|||||||
* Gets the default transaction isolation level of the platform.
|
* Gets the default transaction isolation level of the platform.
|
||||||
*
|
*
|
||||||
* @return integer The default isolation level.
|
* @return integer The default isolation level.
|
||||||
* @see Doctrine\DBAL\Connection\TRANSACTION_* constants.
|
* @see Doctrine\DBAL\Transaction constants.
|
||||||
*/
|
*/
|
||||||
public function getDefaultTransactionIsolationLevel()
|
public function getDefaultTransactionIsolationLevel()
|
||||||
{
|
{
|
||||||
return Connection::TRANSACTION_READ_COMMITTED;
|
return Transaction::READ_COMMITTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* supports*() metods */
|
/* supports*() metods */
|
||||||
|
@ -146,12 +146,12 @@ class OraclePlatform extends AbstractPlatform
|
|||||||
protected function _getTransactionIsolationLevelSQL($level)
|
protected function _getTransactionIsolationLevelSQL($level)
|
||||||
{
|
{
|
||||||
switch ($level) {
|
switch ($level) {
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
|
case \Doctrine\DBAL\Transaction::READ_UNCOMMITTED:
|
||||||
return 'READ UNCOMMITTED';
|
return 'READ UNCOMMITTED';
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
|
case \Doctrine\DBAL\Transaction::READ_COMMITTED:
|
||||||
return 'READ COMMITTED';
|
return 'READ COMMITTED';
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
|
case \Doctrine\DBAL\Transaction::REPEATABLE_READ:
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
|
case \Doctrine\DBAL\Transaction::SERIALIZABLE:
|
||||||
return 'SERIALIZABLE';
|
return 'SERIALIZABLE';
|
||||||
default:
|
default:
|
||||||
return parent::_getTransactionIsolationLevelSQL($level);
|
return parent::_getTransactionIsolationLevelSQL($level);
|
||||||
|
@ -130,11 +130,11 @@ class SqlitePlatform extends AbstractPlatform
|
|||||||
protected function _getTransactionIsolationLevelSQL($level)
|
protected function _getTransactionIsolationLevelSQL($level)
|
||||||
{
|
{
|
||||||
switch ($level) {
|
switch ($level) {
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
|
case \Doctrine\DBAL\Transaction::READ_UNCOMMITTED:
|
||||||
return 0;
|
return 0;
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
|
case \Doctrine\DBAL\Transaction::READ_COMMITTED:
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
|
case \Doctrine\DBAL\Transaction::REPEATABLE_READ:
|
||||||
case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
|
case \Doctrine\DBAL\Transaction::SERIALIZABLE:
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
return parent::_getTransactionIsolationLevelSQL($level);
|
return parent::_getTransactionIsolationLevelSQL($level);
|
||||||
|
229
lib/Doctrine/DBAL/Transaction.php
Normal file
229
lib/Doctrine/DBAL/Transaction.php
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\DBAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Transaction class is the central access point to DBAL Transaction functionality.
|
||||||
|
*
|
||||||
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
|
* @link www.doctrine-project.org
|
||||||
|
* @since 2.0
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
|
* @author Jonathan Wage <jonwage@gmail.com>
|
||||||
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
|
*/
|
||||||
|
class Transaction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constant for transaction isolation level READ UNCOMMITTED.
|
||||||
|
*/
|
||||||
|
const READ_UNCOMMITTED = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for transaction isolation level READ COMMITTED.
|
||||||
|
*/
|
||||||
|
const READ_COMMITTED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for transaction isolation level REPEATABLE READ.
|
||||||
|
*/
|
||||||
|
const REPEATABLE_READ = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for transaction isolation level SERIALIZABLE.
|
||||||
|
*/
|
||||||
|
const SERIALIZABLE = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The transaction nesting level.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $_transactionNestingLevel = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active transaction isolation level.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $_transactionIsolationLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag that indicates whether the current transaction is marked for rollback only.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private $_isRollbackOnly = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param Connection $conn The DBAL Connection
|
||||||
|
*/
|
||||||
|
public function __construct(Connection $conn)
|
||||||
|
{
|
||||||
|
$this->_conn = $conn;
|
||||||
|
|
||||||
|
$this->_transactionIsolationLevel = $conn->getDatabasePlatform()->getDefaultTransactionIsolationLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a transaction is currently active.
|
||||||
|
*
|
||||||
|
* @return boolean TRUE if a transaction is currently active, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public function isTransactionActive()
|
||||||
|
{
|
||||||
|
return $this->_transactionNestingLevel > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the transaction isolation level.
|
||||||
|
*
|
||||||
|
* @param integer $level The level to set.
|
||||||
|
*/
|
||||||
|
public function setTransactionIsolation($level)
|
||||||
|
{
|
||||||
|
$this->_transactionIsolationLevel = $level;
|
||||||
|
|
||||||
|
return $this->executeUpdate($this->_conn->getDatabasePlatform()->getSetTransactionIsolationSQL($level));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currently active transaction isolation level.
|
||||||
|
*
|
||||||
|
* @return integer The current transaction isolation level.
|
||||||
|
*/
|
||||||
|
public function getTransactionIsolation()
|
||||||
|
{
|
||||||
|
return $this->_transactionIsolationLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current transaction nesting level.
|
||||||
|
*
|
||||||
|
* @return integer The nesting level. A value of 0 means there's no active transaction.
|
||||||
|
*/
|
||||||
|
public function getTransactionNestingLevel()
|
||||||
|
{
|
||||||
|
return $this->_transactionNestingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a transaction by suspending auto-commit mode.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function begin()
|
||||||
|
{
|
||||||
|
$conn = $this->_conn->getWrappedConnection();
|
||||||
|
|
||||||
|
if ($this->_transactionNestingLevel == 0) {
|
||||||
|
$conn->beginTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
++$this->_transactionNestingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commits the current transaction.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws ConnectionException If the commit failed due to no active transaction or
|
||||||
|
* because the transaction was marked for rollback only.
|
||||||
|
*/
|
||||||
|
public function commit()
|
||||||
|
{
|
||||||
|
if ($this->_transactionNestingLevel == 0) {
|
||||||
|
throw ConnectionException::commitFailedNoActiveTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->_isRollbackOnly) {
|
||||||
|
throw ConnectionException::commitFailedRollbackOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn = $this->_conn->getWrappedConnection();
|
||||||
|
|
||||||
|
if ($this->_transactionNestingLevel == 1) {
|
||||||
|
$conn->commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
--$this->_transactionNestingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel any database changes done during the current transaction.
|
||||||
|
*
|
||||||
|
* this method can be listened with onPreTransactionRollback and onTransactionRollback
|
||||||
|
* eventlistener methods
|
||||||
|
*
|
||||||
|
* @throws ConnectionException If the rollback operation failed.
|
||||||
|
*/
|
||||||
|
public function rollback()
|
||||||
|
{
|
||||||
|
if ($this->_transactionNestingLevel == 0) {
|
||||||
|
throw ConnectionException::rollbackFailedNoActiveTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->_transactionNestingLevel == 1) {
|
||||||
|
$this->_transactionNestingLevel = 0;
|
||||||
|
$this->_conn->getWrappedConnection()->rollback();
|
||||||
|
$this->_isRollbackOnly = false;
|
||||||
|
} else {
|
||||||
|
$this->_isRollbackOnly = true;
|
||||||
|
--$this->_transactionNestingLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the current transaction so that the only possible
|
||||||
|
* outcome for the transaction to be rolled back.
|
||||||
|
*
|
||||||
|
* @throws ConnectionException If no transaction is active.
|
||||||
|
*/
|
||||||
|
public function setRollbackOnly()
|
||||||
|
{
|
||||||
|
if ($this->_transactionNestingLevel == 0) {
|
||||||
|
throw ConnectionException::noActiveTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_isRollbackOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the current transaction is marked for rollback only.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
* @throws ConnectionException If no transaction is active.
|
||||||
|
*/
|
||||||
|
public function getRollbackOnly()
|
||||||
|
{
|
||||||
|
if ($this->_transactionNestingLevel == 0) {
|
||||||
|
throw ConnectionException::noActiveTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_isRollbackOnly;
|
||||||
|
}
|
||||||
|
}
|
@ -107,6 +107,13 @@ class EntityManager
|
|||||||
*/
|
*/
|
||||||
private $_closed = false;
|
private $_closed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ORM Entity Transaction.
|
||||||
|
*
|
||||||
|
* @var Doctrine\ORM\EntityTransaction
|
||||||
|
*/
|
||||||
|
protected $_transaction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new EntityManager that operates on the given database connection
|
* Creates a new EntityManager that operates on the given database connection
|
||||||
* and uses the given Configuration and EventManager implementations.
|
* and uses the given Configuration and EventManager implementations.
|
||||||
@ -127,6 +134,7 @@ class EntityManager
|
|||||||
$config->getProxyDir(),
|
$config->getProxyDir(),
|
||||||
$config->getProxyNamespace(),
|
$config->getProxyNamespace(),
|
||||||
$config->getAutoGenerateProxyClasses());
|
$config->getAutoGenerateProxyClasses());
|
||||||
|
$this->_transaction = new EntityTransaction($conn->getTransaction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,6 +157,16 @@ class EntityManager
|
|||||||
return $this->_metadataFactory;
|
return $this->_metadataFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ORM Transaction instance.
|
||||||
|
*
|
||||||
|
* @return Doctrine\ORM\EntityTransaction
|
||||||
|
*/
|
||||||
|
public function getTransaction()
|
||||||
|
{
|
||||||
|
return $this->_transaction;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an ExpressionBuilder used for object-oriented construction of query expressions.
|
* Gets an ExpressionBuilder used for object-oriented construction of query expressions.
|
||||||
*
|
*
|
||||||
@ -175,7 +193,7 @@ class EntityManager
|
|||||||
*/
|
*/
|
||||||
public function beginTransaction()
|
public function beginTransaction()
|
||||||
{
|
{
|
||||||
$this->_conn->beginTransaction();
|
$this->getTransaction()->begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,7 +201,7 @@ class EntityManager
|
|||||||
*/
|
*/
|
||||||
public function commit()
|
public function commit()
|
||||||
{
|
{
|
||||||
$this->_conn->commit();
|
$this->getTransaction()->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,7 +210,7 @@ class EntityManager
|
|||||||
*/
|
*/
|
||||||
public function rollback()
|
public function rollback()
|
||||||
{
|
{
|
||||||
$this->_conn->rollback();
|
$this->getTransaction()->rollback();
|
||||||
$this->close();
|
$this->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
154
lib/Doctrine/ORM/EntityTransaction.php
Normal file
154
lib/Doctrine/ORM/EntityTransaction.php
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Transaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Transaction class is the central access point to ORM Transaction functionality.
|
||||||
|
* This class acts more as a delegate class to the DBAL Transaction functionality.
|
||||||
|
*
|
||||||
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
|
* @link www.doctrine-project.org
|
||||||
|
* @since 2.0
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
|
* @author Jonathan Wage <jonwage@gmail.com>
|
||||||
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
|
*/
|
||||||
|
class EntityTransaction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The wrapped DBAL Transaction.
|
||||||
|
*
|
||||||
|
* @var Doctrine\DBAL\Transaction
|
||||||
|
*/
|
||||||
|
protected $_wrappedTransaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param Transaction $transaction
|
||||||
|
*/
|
||||||
|
public function __construct(Transaction $transaction)
|
||||||
|
{
|
||||||
|
$this->_wrappedTransaction = $transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a transaction is currently active.
|
||||||
|
*
|
||||||
|
* @return boolean TRUE if a transaction is currently active, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public function isTransactionActive()
|
||||||
|
{
|
||||||
|
return $this->_wrappedTransaction->isTransactionActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the transaction isolation level.
|
||||||
|
*
|
||||||
|
* @param integer $level The level to set.
|
||||||
|
*/
|
||||||
|
public function setTransactionIsolation($level)
|
||||||
|
{
|
||||||
|
return $this->_wrappedTransaction->setTransactionIsolation($level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currently active transaction isolation level.
|
||||||
|
*
|
||||||
|
* @return integer The current transaction isolation level.
|
||||||
|
*/
|
||||||
|
public function getTransactionIsolation()
|
||||||
|
{
|
||||||
|
return $this->_wrappedTransaction->getTransactionIsolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current transaction nesting level.
|
||||||
|
*
|
||||||
|
* @return integer The nesting level. A value of 0 means there's no active transaction.
|
||||||
|
*/
|
||||||
|
public function getTransactionNestingLevel()
|
||||||
|
{
|
||||||
|
return $this->_wrappedTransaction->getTransactionNestingLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a transaction by suspending auto-commit mode.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function begin()
|
||||||
|
{
|
||||||
|
$this->_wrappedTransaction->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commits the current transaction.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws Doctrine\DBAL\ConnectionException If the commit failed due to no active transaction or
|
||||||
|
* because the transaction was marked for rollback only.
|
||||||
|
*/
|
||||||
|
public function commit()
|
||||||
|
{
|
||||||
|
$this->_wrappedTransaction->commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel any database changes done during the current transaction.
|
||||||
|
*
|
||||||
|
* this method can be listened with onPreTransactionRollback and onTransactionRollback
|
||||||
|
* eventlistener methods
|
||||||
|
*
|
||||||
|
* @throws Doctrine\DBAL\ConnectionException If the rollback operation failed.
|
||||||
|
*/
|
||||||
|
public function rollback()
|
||||||
|
{
|
||||||
|
$this->_wrappedTransaction->rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the current transaction so that the only possible
|
||||||
|
* outcome for the transaction to be rolled back.
|
||||||
|
*
|
||||||
|
* @throws ConnectionException If no transaction is active.
|
||||||
|
*/
|
||||||
|
public function setRollbackOnly()
|
||||||
|
{
|
||||||
|
$this->_wrappedTransaction->setRollbackOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the current transaction is marked for rollback only.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
* @throws ConnectionException If no transaction is active.
|
||||||
|
*/
|
||||||
|
public function getRollbackOnly()
|
||||||
|
{
|
||||||
|
return $this->_wrappedTransaction->getRollbackOnly();
|
||||||
|
}
|
||||||
|
}
|
@ -281,11 +281,12 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
|
|
||||||
// Now we need a commit order to maintain referential integrity
|
// Now we need a commit order to maintain referential integrity
|
||||||
$commitOrder = $this->_getCommitOrder();
|
$commitOrder = $this->_getCommitOrder();
|
||||||
|
|
||||||
|
$tx = $this->_em->getTransaction();
|
||||||
|
|
||||||
$conn = $this->_em->getConnection();
|
try {
|
||||||
|
$tx->begin();
|
||||||
|
|
||||||
$conn->beginTransaction();
|
|
||||||
try {
|
|
||||||
if ($this->_entityInsertions) {
|
if ($this->_entityInsertions) {
|
||||||
foreach ($commitOrder as $class) {
|
foreach ($commitOrder as $class) {
|
||||||
$this->_executeInserts($class);
|
$this->_executeInserts($class);
|
||||||
@ -321,11 +322,10 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$conn->commit();
|
$tx->commit();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$conn->setRollbackOnly();
|
$tx->rollback();
|
||||||
$conn->rollback();
|
|
||||||
$this->_em->close();
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +56,11 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
|
|||||||
|
|
||||||
public function testCustomWrapper()
|
public function testCustomWrapper()
|
||||||
{
|
{
|
||||||
$wrapperMock = $this->getMock('\Doctrine\DBAL\Connection', array(), array(), '', false);
|
$wrapperClass = 'Doctrine\Tests\Mocks\ConnectionMock';
|
||||||
$wrapperClass = get_class($wrapperMock);
|
|
||||||
|
|
||||||
$options = array(
|
$options = array(
|
||||||
'pdo' => new \PDO('sqlite::memory:'),
|
'pdo' => new \PDO('sqlite::memory:'),
|
||||||
'wrapperClass' => $wrapperClass
|
'wrapperClass' => $wrapperClass,
|
||||||
);
|
);
|
||||||
|
|
||||||
$conn = \Doctrine\DBAL\DriverManager::getConnection($options);
|
$conn = \Doctrine\DBAL\DriverManager::getConnection($options);
|
||||||
|
@ -25,7 +25,7 @@ class AllTests
|
|||||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\MySqlSchemaManagerTest');
|
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\MySqlSchemaManagerTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\PostgreSqlSchemaManagerTest');
|
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\PostgreSqlSchemaManagerTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\OracleSchemaManagerTest');
|
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\OracleSchemaManagerTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\ConnectionTest');
|
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\TransactionTest');
|
||||||
|
|
||||||
return $suite;
|
return $suite;
|
||||||
}
|
}
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Doctrine\Tests\DBAL\Functional;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\ConnectionException;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../../TestInit.php';
|
|
||||||
|
|
||||||
class ConnectionTest extends \Doctrine\Tests\DbalFunctionalTestCase
|
|
||||||
{
|
|
||||||
|
|
||||||
public function testTransactionNestingBehavior()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->_conn->beginTransaction();
|
|
||||||
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->_conn->beginTransaction();
|
|
||||||
$this->assertEquals(2, $this->_conn->getTransactionNestingLevel());
|
|
||||||
throw new \Exception;
|
|
||||||
$this->_conn->commit(); // never reached
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->_conn->rollback();
|
|
||||||
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
|
|
||||||
//no rethrow
|
|
||||||
}
|
|
||||||
$this->assertTrue($this->_conn->getRollbackOnly());
|
|
||||||
|
|
||||||
$this->_conn->commit(); // should throw exception
|
|
||||||
$this->fail('Transaction commit after failed nested transaction should fail.');
|
|
||||||
} catch (ConnectionException $e) {
|
|
||||||
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
|
|
||||||
$this->_conn->rollback();
|
|
||||||
$this->assertEquals(0, $this->_conn->getTransactionNestingLevel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTransactionBehavior()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->_conn->beginTransaction();
|
|
||||||
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
|
|
||||||
|
|
||||||
throw new \Exception;
|
|
||||||
|
|
||||||
$this->_conn->commit(); // never reached
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
|
|
||||||
$this->_conn->rollback();
|
|
||||||
$this->assertEquals(0, $this->_conn->getTransactionNestingLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->_conn->beginTransaction();
|
|
||||||
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
|
|
||||||
$this->_conn->commit();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->_conn->rollback();
|
|
||||||
$this->assertEquals(0, $this->_conn->getTransactionNestingLevel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
68
tests/Doctrine/Tests/DBAL/Functional/TransactionTest.php
Normal file
68
tests/Doctrine/Tests/DBAL/Functional/TransactionTest.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\DBAL\Functional;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ConnectionException;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../TestInit.php';
|
||||||
|
|
||||||
|
class TransactionTest extends \Doctrine\Tests\DbalFunctionalTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testTransactionNestingBehavior()
|
||||||
|
{
|
||||||
|
$tx = $this->_conn->getTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$tx->begin();
|
||||||
|
$this->assertEquals(1, $tx->getTransactionNestingLevel());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$tx->begin();
|
||||||
|
$this->assertEquals(2, $tx->getTransactionNestingLevel());
|
||||||
|
throw new \Exception;
|
||||||
|
$tx->commit(); // never reached
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$tx->rollback();
|
||||||
|
$this->assertEquals(1, $tx->getTransactionNestingLevel());
|
||||||
|
//no rethrow
|
||||||
|
}
|
||||||
|
$this->assertTrue($tx->getRollbackOnly());
|
||||||
|
|
||||||
|
$tx->commit(); // should throw exception
|
||||||
|
$this->fail('Transaction commit after failed nested transaction should fail.');
|
||||||
|
} catch (ConnectionException $e) {
|
||||||
|
$this->assertEquals(1, $tx->getTransactionNestingLevel());
|
||||||
|
$tx->rollback();
|
||||||
|
$this->assertEquals(0, $tx->getTransactionNestingLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTransactionBehavior()
|
||||||
|
{
|
||||||
|
$tx = $this->_conn->getTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$tx->begin();
|
||||||
|
$this->assertEquals(1, $tx->getTransactionNestingLevel());
|
||||||
|
|
||||||
|
throw new \Exception;
|
||||||
|
|
||||||
|
$tx->commit(); // never reached
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->assertEquals(1, $tx->getTransactionNestingLevel());
|
||||||
|
$tx->rollback();
|
||||||
|
$this->assertEquals(0, $tx->getTransactionNestingLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$tx->begin();
|
||||||
|
$this->assertEquals(1, $tx->getTransactionNestingLevel());
|
||||||
|
$tx->commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$tx->rollback();
|
||||||
|
$this->assertEquals(0, $tx->getTransactionNestingLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -44,19 +44,19 @@ class MsSqlPlatformTest extends AbstractPlatformTestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_UNCOMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_COMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ',
|
'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::REPEATABLE_READ)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::SERIALIZABLE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,20 +53,20 @@ class MySqlPlatformTest extends AbstractPlatformTestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED),
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_UNCOMMITTED),
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_COMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ',
|
'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::REPEATABLE_READ)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::SERIALIZABLE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,19 +55,19 @@ class OraclePlatformTest extends AbstractPlatformTestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_UNCOMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_COMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::REPEATABLE_READ)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE)
|
$this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::SERIALIZABLE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ namespace Doctrine\Tests\DBAL\Platforms;
|
|||||||
|
|
||||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||||
use Doctrine\DBAL\Types\Type;
|
use Doctrine\DBAL\Types\Type;
|
||||||
use Doctrine\DBAL\Connection;
|
use Doctrine\DBAL\Transaction;
|
||||||
|
|
||||||
require_once __DIR__ . '/../../TestInit.php';
|
require_once __DIR__ . '/../../TestInit.php';
|
||||||
|
|
||||||
@ -74,19 +74,19 @@ class PostgreSqlPlatformTest extends AbstractPlatformTestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_READ_UNCOMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(Transaction::READ_UNCOMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_READ_COMMITTED)
|
$this->_platform->getSetTransactionIsolationSQL(Transaction::READ_COMMITTED)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ',
|
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_REPEATABLE_READ)
|
$this->_platform->getSetTransactionIsolationSQL(Transaction::REPEATABLE_READ)
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE',
|
||||||
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_SERIALIZABLE)
|
$this->_platform->getSetTransactionIsolationSQL(Transaction::SERIALIZABLE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ class SqlitePlatformTest extends AbstractPlatformTestCase
|
|||||||
|
|
||||||
public function testGeneratesTransactionCommands()
|
public function testGeneratesTransactionCommands()
|
||||||
{
|
{
|
||||||
$this->assertEquals('PRAGMA read_uncommitted = 0', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED));
|
$this->assertEquals('PRAGMA read_uncommitted = 0', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_UNCOMMITTED));
|
||||||
$this->assertEquals('PRAGMA read_uncommitted = 1', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED));
|
$this->assertEquals('PRAGMA read_uncommitted = 1', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::READ_COMMITTED));
|
||||||
$this->assertEquals('PRAGMA read_uncommitted = 1', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ));
|
$this->assertEquals('PRAGMA read_uncommitted = 1', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::REPEATABLE_READ));
|
||||||
$this->assertEquals('PRAGMA read_uncommitted = 1', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE));
|
$this->assertEquals('PRAGMA read_uncommitted = 1', $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Transaction::SERIALIZABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPrefersIdentityColumns()
|
public function testPrefersIdentityColumns()
|
||||||
|
@ -11,8 +11,11 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
|
|||||||
|
|
||||||
public function __construct(array $params, $driver, $config = null, $eventManager = null)
|
public function __construct(array $params, $driver, $config = null, $eventManager = null)
|
||||||
{
|
{
|
||||||
parent::__construct($params, $driver, $config, $eventManager);
|
|
||||||
$this->_platformMock = new DatabasePlatformMock();
|
$this->_platformMock = new DatabasePlatformMock();
|
||||||
|
|
||||||
|
parent::__construct($params, $driver, $config, $eventManager);
|
||||||
|
|
||||||
|
// Override possible assignment of platform to database platform mock
|
||||||
$this->_platform = $this->_platformMock;
|
$this->_platform = $this->_platformMock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user