Last active
August 29, 2015 14:13
-
-
Save tlode/6f1fa559d67c8461ba42 to your computer and use it in GitHub Desktop.
TransactionTrait
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Model; | |
use PommProject\Foundation\Session\Connection; | |
use PommProject\ModelManager\Exception\ModelException; | |
use PommProject\ModelManager\ModelLayer\ModelLayer; | |
trait BbTransactionTrait | |
{ | |
private $savePointStack = []; | |
/** | |
* startTransaction | |
* | |
* Start a new transaction. | |
* | |
* @access protected | |
* @return ModelLayer $this | |
*/ | |
protected function startTransaction() | |
{ | |
if($this->isInTransaction()) | |
{ | |
$className = join('_', explode('\\', get_class($this))); | |
$savePoint = 'sp_'. $className.'_'. count($this->savePointStack); | |
array_push($this->savePointStack, $savePoint); | |
$this->setSavePoint($savePoint); | |
} | |
else | |
{ | |
$this->executeAnonymousQuery('begin transaction'); | |
} | |
return $this; | |
} | |
/** | |
* setSavePoint | |
* | |
* Set a savepoint in a transaction. | |
* | |
* @access protected | |
* @param string $name | |
* @return ModelLayer $this | |
*/ | |
protected function setSavepoint($name) | |
{ | |
return $this->sendParameter( | |
"savepoint %s", | |
$name | |
); | |
} | |
/** | |
* releaseSavepoint | |
* | |
* Drop a savepoint. | |
* | |
* @access protected | |
* @param string $name | |
* @return ModelLayer $this | |
*/ | |
protected function releaseSavepoint($name) | |
{ | |
return $this->sendParameter( | |
"release savepoint %s", | |
$name | |
); | |
} | |
/** | |
* rollbackTransaction | |
* | |
* Rollback a transaction. If a name is specified, the transaction is | |
* rollback to the given savepoint. Otherwise, the whole transaction is | |
* rollback. | |
* | |
* @access protected | |
* @param string|null $name | |
* @return ModelLayer $this | |
*/ | |
protected function rollbackTransaction($name = null) | |
{ | |
if(count($this->savePointStack) && $this->isInTransaction()) | |
{ | |
if ($name !== null) { | |
do { | |
$savePoint = array_pop($this->savePointStack); | |
} while ($savePoint && $savePoint !== $name); | |
$savePoint = $name; | |
} else { | |
$savePoint = array_pop($this->savePointStack); | |
} | |
$sql = sprintf("rollback to savepoint %s", $this->escapeIdentifier($savePoint)); | |
} | |
else | |
{ | |
$this->savePointStack = array(); | |
$sql = "rollback transaction"; | |
} | |
$this->executeAnonymousQuery($sql); | |
return $this; | |
} | |
/** | |
* commitTransaction | |
* | |
* Commit a transaction. | |
* | |
* @access protected | |
* @return ModelLayer $this | |
*/ | |
protected function commitTransaction() | |
{ | |
if(count($this->savePointStack) && $this->isInTransaction()) | |
{ | |
$savePoint = array_pop($this->savePointStack); | |
$this->releaseSavePoint($savePoint); | |
} | |
else | |
{ | |
$this->savePointStack = array(); | |
$this->executeAnonymousQuery('commit transaction'); | |
} | |
return $this; | |
} | |
/** | |
* isInTransaction | |
* | |
* Tell if a transaction is open or not. | |
* | |
* @see Cient | |
* @access protected | |
* @return bool | |
*/ | |
protected function isInTransaction() | |
{ | |
$status = $this | |
->getSession() | |
->getConnection() | |
->getTransactionStatus(); | |
return (bool) ($status === \PGSQL_TRANSACTION_INTRANS || $status === \PGSQL_TRANSACTION_INERROR || $status === \PGSQL_TRANSACTION_ACTIVE); | |
} | |
/** | |
* isTransactionOk | |
* | |
* In Postgresql, an error during a transaction cancels all the queries and | |
* rollback the transaction on commit. This method returns the current | |
* transaction's status. If no transactions are open, it returns null. | |
* | |
* @access public | |
* @return bool|null | |
*/ | |
protected function isTransactionOk() | |
{ | |
if (!$this->isInTransaction()) { | |
return null; | |
} | |
$status = $this | |
->getSession() | |
->getConnection() | |
->getTransactionStatus(); | |
return (bool) ($status === \PGSQL_TRANSACTION_INTRANS); | |
} | |
/** | |
* setDeferrable | |
* | |
* Set given constraints to deferred/immediate in the current transaction. | |
* This applies to constraints being deferrable or deferred by default. | |
* If the keys is an empty arrays, ALL keys will be set at the given state. | |
* | |
* @see http://www.postgresql.org/docs/9.0/static/sql-set-constraints.html | |
* | |
* @access protected | |
* @param array $keys | |
* @param string $state | |
* @return ModelLayer $this | |
* @throws ModelException if not valid state | |
*/ | |
protected function setDeferrable(array $keys = [], $state) | |
{ | |
if (count($keys) === 0) { | |
$string = 'ALL'; | |
} else { | |
$string = join( | |
', ', | |
array_map( | |
function ($key) { | |
$this->escapeIdentifier($key); | |
}, | |
$keys | |
) | |
); | |
} | |
if (!in_array($state, [Connection::CONSTRAINTS_DEFERRED, Connection::CONSTRAINTS_IMMEDIATE])) { | |
throw new ModelException(sprintf("'%s' is not a valid constraints modifier.", $state)); | |
} | |
$this->executeAnonymousQuery( | |
sprintf( | |
"set constraints %s %s", | |
$string, | |
$state | |
) | |
); | |
return $this; | |
} | |
/** | |
* setTransactionIsolationLevel | |
* | |
* Transaction isolation level tells postgresql how to manage with the | |
* current transaction. The default is "READ COMMITED". | |
* | |
* @see http://www.postgresql.org/docs/9.0/static/sql-set-transaction.html | |
* | |
* @access protected | |
* @param $isolaton_level | |
* @return ModelLayer $this | |
* @throws ModelException | |
* @internal param string $state | |
* @throw ModelException if not valid isolation level | |
*/ | |
protected function setTransactionIsolationLevel($isolaton_level) | |
{ | |
if (!in_array( | |
$isolaton_level, | |
[ | |
Connection::ISOLATION_READ_COMMITTED, | |
Connection::ISOLATION_READ_REPEATABLE, | |
Connection::ISOLATION_SERIALIZABLE | |
] | |
) | |
) { | |
throw new ModelException(sprintf("'%s' is not a valid transaction isolation level.")); | |
} | |
return $this->sendParameter( | |
"set transaction isolation level %s", | |
'', | |
$isolaton_level | |
); | |
} | |
/** | |
* setTransactionAccessMode | |
* | |
* Transaction access modes tell Postgresql if transaction are able to | |
* write or read only. | |
* | |
* @see http://www.postgresql.org/docs/9.0/static/sql-set-transaction.html | |
* | |
* @access protected | |
* @param string $access_mode | |
* @return ModelLayer $this | |
* @throws ModelException | |
* @throw ModelException if not valid access mode | |
*/ | |
protected function setTransactionAccessMode($access_mode) | |
{ | |
if (!in_array( | |
$access_mode, | |
[Connection::ACCESS_MODE_READ_ONLY, Connection::ACCESS_MODE_READ_WRITE] | |
) | |
) { | |
throw new ModelException(sprintf("'%s' is not a valid transaction access mode.", $access_mode)); | |
} | |
return $this->sendParameter( | |
"set transaction %s", | |
'', | |
$access_mode | |
); | |
} | |
/** | |
* sendParameter | |
* | |
* Send a parameter to the server. | |
* The parameter MUST have been properly checked and escpaed if needed as | |
* it is going to be passed AS IS to the server. Sending untrusted | |
* parameters may lead to potential SQL injection. | |
* | |
* @access private | |
* @param string $sql | |
* @param string $identifier | |
* @param string $parameter | |
* @return ModelLayer $this | |
*/ | |
private function sendParameter($sql, $identifier, $parameter = null) | |
{ | |
$this | |
->executeAnonymousQuery( | |
sprintf( | |
$sql, | |
$this->escapeIdentifier($identifier), | |
$parameter | |
) | |
); | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment