Skip to content

Instantly share code, notes, and snippets.

@neoascetic
Last active August 1, 2016 13:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save neoascetic/5269127 to your computer and use it in GitHub Desktop.
Save neoascetic/5269127 to your computer and use it in GitHub Desktop.
[Laravel] Nested transactions wrapper class
<?php
/**
* Class for Laravel 3.x that provides ability to use nested transactions via SAVEPOINTs
* (inspired from http://www.kennynet.co.uk/2008/12/02/php-pdo-nested-transactions/).
* For now, only the default connection is supported.
*
* Useful in testing, when you want to start a transaction before running a test
* and revert all its changes after it finished.
*
* To use this, you need to replace value under "DB" key in `application.aliases` config
* with this class name. After this, you can continue to use Laravel-style transactions
* (`DB::transaction`), but you need to replace all "raw PDO" transaction calls
* (such as `DB::connection()->pdo->beginTransaction()`) with alternatives provided
* by this class.
*/
class NestedTransactor extends \Laravel\Database {
protected static $supported_drivers = ['pgsql', 'mysql', 'mysqli', 'sqlite'];
protected static $transaction_level = 0;
protected static function get_pdo() {
return static::connection()->pdo;
}
protected static function nestable() {
$current_driver = static::get_pdo()->getAttribute(\PDO::ATTR_DRIVER_NAME);
return in_array($current_driver, static::$supported_drivers);
}
protected static function process_pdo($pdo_method, $sql) {
$pdo = static::get_pdo();
if (static::$transaction_level == 0 || !static::nestable()) {
$pdo->{$pdo_method}();
} else {
$pdo->exec($sql);
}
}
public static function begin_transaction() {
static::process_pdo('beginTransaction', 'SAVEPOINT LEVEL'.static::$transaction_level);
static::$transaction_level++;
}
public static function commit_transaction() {
static::$transaction_level--;
static::process_pdo('commit', 'RELEASE SAVEPOINT LEVEL'.static::$transaction_level);
}
public static function rollback_transaction() {
static::$transaction_level--;
static::process_pdo('rollBack', 'ROLLBACK TO SAVEPOINT LEVEL'.static::$transaction_level);
}
/**
* Redefined transaction method of Laravel\Database\Connection
* @param callback $callback
* @return void
*/
public static function transaction($callback) {
static::begin_transaction();
try {
call_user_func($callback);
} catch (\Exception $e) {
static::rollback_transaction();
throw $e;
}
return static::commit_transaction();
}
}
@neoascetic
Copy link
Author

Thanks for the note, @jan-j. Just have added global namespace prefix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment