Passed
Pull Request — master (#46)
by Jean-Christophe
07:05
created

DatabaseTransactionsTrait::rollBackToLevel()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 3
1
<?php
2
3
namespace Ubiquity\db\traits;
4
5
use Ubiquity\exceptions\DBException;
6
7
/**
8
 * Manages database transactions.
9
 * Ubiquity\db\traits$DatabaseTransactionsTrait
10
 * This class is part of Ubiquity
11
 *
12
 * @author jcheron <[email protected]>
13
 * @version 1.0.0
14
 * @property \PDO $pdoObject
15
 * @property string $dbType
16
 */
17
trait DatabaseTransactionsTrait {
18
	protected static $savepointsDrivers = [ 'pgsql' => true,'mysql' => true,'sqlite' => true ];
19
	protected $transactionLevel = 0;
20
21 4
	protected function nestable() {
22 4
		return isset ( self::$savepointsDrivers [$this->dbType] );
23
	}
24
25
	/**
26
	 * Initiates a transaction
27
	 *
28
	 * @return boolean true on success or false on failure
29
	 */
30 8
	public function beginTransaction() {
31 8
		if ($this->transactionLevel == 0 || ! $this->nestable ()) {
32 8
			$ret = $this->pdoObject->beginTransaction ();
33 8
			$this->transactionLevel ++;
34 8
			return $ret;
35
		}
36 4
		$this->pdoObject->exec ( 'SAVEPOINT LEVEL' . $this->transactionLevel );
37 4
		$this->transactionLevel ++;
38 4
		return true;
39
	}
40
41
	/**
42
	 * Commits a transaction
43
	 *
44
	 * @return boolean true on success or false on failure
45
	 */
46 4
	public function commit() {
47 4
		$this->transactionLevel --;
48 4
		if ($this->transactionLevel == 0 || ! $this->nestable ()) {
49 4
			return $this->pdoObject->commit ();
50
		}
51 2
		$this->pdoObject->exec ( 'RELEASE SAVEPOINT LEVEL' . $this->transactionLevel );
52 2
		return true;
53
	}
54
55
	/**
56
	 * Commits nested transactions up to level $transactionLevel
57
	 *
58
	 * @param int $transactionLevel
59
	 * @return boolean true on success or false on failure
60
	 */
61 1
	public function commitToLevel($transactionLevel) {
62 1
		$res = true;
63 1
		while ( $res && $this->transactionLevel > $transactionLevel ) {
64 1
			$res = $this->commit ();
65
		}
66 1
		return $res;
67
	}
68
69
	/**
70
	 * Commits all nested transactions (up to level 0)
71
	 *
72
	 * @return boolean true on success or false on failure
73
	 */
74 1
	public function commitAll() {
75 1
		return $this->commitToLevel ( 0 );
76
	}
77
78
	/**
79
	 * Rolls back a transaction
80
	 *
81
	 * @return boolean true on success or false on failure
82
	 */
83 3
	public function rollBack() {
84 3
		$this->transactionLevel --;
85
86 3
		if ($this->transactionLevel == 0 || ! $this->nestable ()) {
87 3
			return $this->pdoObject->rollBack ();
88
		}
89 2
		$this->pdoObject->exec ( 'ROLLBACK TO SAVEPOINT LEVEL' . $this->transactionLevel );
90 2
		return true;
91
	}
92
93
	/**
94
	 * Rolls back nested transactions up to level $transactionLevel
95
	 *
96
	 * @param int $transactionLevel
97
	 * @return boolean true on success or false on failure
98
	 */
99 1
	public function rollBackToLevel($transactionLevel) {
100 1
		$res = true;
101 1
		while ( $res && $this->transactionLevel > $transactionLevel ) {
102 1
			$res = $this->rollBack ();
103
		}
104 1
		return $res;
105
	}
106
107
	/**
108
	 * Rolls back all nested transactions (up to level 0)
109
	 *
110
	 * @return boolean true on success or false on failure
111
	 */
112 1
	public function rollBackAll() {
113 1
		return $this->rollBackToLevel ( 0 );
114
	}
115
116
	/**
117
	 * Checks if inside a transaction
118
	 *
119
	 * @return boolean
120
	 */
121
	public function inTransaction() {
122
		return $this->pdoObject->inTransaction ();
123
	}
124
125
	/**
126
	 * Call a callback with an array of parameters in a transaction
127
	 *
128
	 * @param callable $callback
129
	 * @param mixed ...$parameters
130
	 * @throws \Exception
131
	 * @return mixed
132
	 */
133
	public function callInTransaction($callback, ...$parameters) {
134
		if ($this->beginTransaction ()) {
135
			try {
136
				$ret = call_user_func_array ( $callback, $parameters );
137
			} catch ( \Exception $e ) {
138
				$this->rollBack ();
139
				throw $e;
140
			}
141
142
			if ($ret) {
143
				if (! $this->commit ())
144
					throw new DBException ( 'Transaction was not committed.' );
145
			} else {
146
				$this->rollBack ();
147
			}
148
149
			return $ret;
150
		}
151
		throw new DBException ( 'Transaction was not started.' );
152
	}
153
}
154