NFC - Short array syntax - auto-convert Civi dir
[civicrm-core.git] / Civi / Core / Transaction / Frame.php
CommitLineData
5bb8417a
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
5bb8417a 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
5bb8417a
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
5bb8417a
TO
27
28namespace Civi\Core\Transaction;
29
30/**
31 * A "frame" is a layer in a series of nested transactions. Generally,
32 * the outermost frame is a normal SQL transaction (BEGIN/ROLLBACK/COMMIT)
33 * and any nested frames are SQL savepoints (SAVEPOINT foo/ROLLBACK TO SAVEPOINT).
34 *
35 * @package Civi
6b83d5bd 36 * @copyright CiviCRM LLC (c) 2004-2019
5bb8417a
TO
37 */
38class Frame {
39
40 const F_NEW = 0, F_ACTIVE = 1, F_DONE = 2, F_FORCED = 3;
41
42 /**
43 * @var \CRM_Core_DAO
44 */
45 private $dao;
46
47 /**
48 * @var string|null e.g. "BEGIN" or "SAVEPOINT foo"
49 */
50 private $beginStmt;
51
52 /**
53 * @var string|null e.g. "COMMIT"
54 */
55 private $commitStmt;
56
57 /**
58 * @var string|null e.g. "ROLLBACK" or "ROLLBACK TO SAVEPOINT foo"
59 */
60 private $rollbackStmt;
61
62 /**
63 * @var int
64 */
65 private $refCount = 0;
66 private $callbacks;
67 private $doCommit = TRUE;
68
69 /**
70 * @var int
71 */
72 private $state = self::F_NEW;
73
74 /**
75 * @param \CRM_Core_DAO $dao
76 * @param string|null $beginStmt e.g. "BEGIN" or "SAVEPOINT foo"
77 * @param string|null $commitStmt e.g. "COMMIT"
78 * @param string|null $rollbackStmt e.g. "ROLLBACK" or "ROLLBACK TO SAVEPOINT foo"
79 */
80 public function __construct($dao, $beginStmt, $commitStmt, $rollbackStmt) {
81 $this->dao = $dao;
82 $this->beginStmt = $beginStmt;
83 $this->commitStmt = $commitStmt;
84 $this->rollbackStmt = $rollbackStmt;
85
c64f69d9
CW
86 $this->callbacks = [
87 \CRM_Core_Transaction::PHASE_PRE_COMMIT => [],
88 \CRM_Core_Transaction::PHASE_POST_COMMIT => [],
89 \CRM_Core_Transaction::PHASE_PRE_ROLLBACK => [],
90 \CRM_Core_Transaction::PHASE_POST_ROLLBACK => [],
91 ];
5bb8417a
TO
92 }
93
94 public function inc() {
95 $this->refCount++;
96 }
97
98 public function dec() {
99 $this->refCount--;
100 }
101
7fe37828
EM
102 /**
103 * @return bool
104 */
5bb8417a
TO
105 public function isEmpty() {
106 return ($this->refCount == 0);
107 }
108
7fe37828
EM
109 /**
110 * @return bool
111 */
5bb8417a
TO
112 public function isRollbackOnly() {
113 return !$this->doCommit;
114 }
115
116 public function setRollbackOnly() {
46bcf597 117 $this->doCommit = FALSE;
5bb8417a
TO
118 }
119
0dbbb8e7 120 /**
121 * Begin frame processing.
122 *
123 * @throws \CRM_Core_Exception
124 */
5bb8417a 125 public function begin() {
0dbbb8e7 126 if ($this->state !== self::F_NEW) {
127 throw new \CRM_Core_Exception('State is not F_NEW');
128 };
129
5bb8417a
TO
130 $this->state = self::F_ACTIVE;
131 if ($this->beginStmt) {
132 $this->dao->query($this->beginStmt);
133 }
134 }
135
136 /**
0dbbb8e7 137 * Finish frame processing.
138 *
2241036a 139 * @param int $newState
0dbbb8e7 140 *
141 * @throws \CRM_Core_Exception
5bb8417a
TO
142 */
143 public function finish($newState = self::F_DONE) {
144 if ($this->state == self::F_FORCED) {
145 return;
146 }
0dbbb8e7 147 if ($this->state !== self::F_ACTIVE) {
148 throw new \CRM_Core_Exception('State is not F_ACTIVE');
149 };
150
5bb8417a
TO
151 $this->state = $newState;
152
153 if ($this->doCommit) {
154 $this->invokeCallbacks(\CRM_Core_Transaction::PHASE_PRE_COMMIT);
155 if ($this->commitStmt) {
156 $this->dao->query($this->commitStmt);
157 }
158 $this->invokeCallbacks(\CRM_Core_Transaction::PHASE_POST_COMMIT);
159 }
160 else {
161 $this->invokeCallbacks(\CRM_Core_Transaction::PHASE_PRE_ROLLBACK);
162 if ($this->rollbackStmt) {
163 $this->dao->query($this->rollbackStmt);
164 }
165 $this->invokeCallbacks(\CRM_Core_Transaction::PHASE_POST_ROLLBACK);
166 }
167 }
168
169 public function forceRollback() {
170 $this->setRollbackOnly();
171 $this->finish(self::F_FORCED);
172 }
173
174 /**
fe482240 175 * Add a transaction callback.
5bb8417a
TO
176 *
177 * Pre-condition: isActive()
178 *
04855556
TO
179 * @param int $phase
180 * A constant; one of: self::PHASE_{PRE,POST}_{COMMIT,ROLLBACK}.
181 * @param mixed $callback
182 * A PHP callback.
5bb8417a
TO
183 * @param array|NULL $params Optional values to pass to callback.
184 * See php manual call_user_func_array for details.
257e7666 185 * @param null $id
5bb8417a 186 */
46bcf597 187 public function addCallback($phase, $callback, $params = NULL, $id = NULL) {
5bb8417a 188 if ($id) {
c64f69d9 189 $this->callbacks[$phase][$id] = [
5bb8417a 190 'callback' => $callback,
c64f69d9
CW
191 'parameters' => (is_array($params) ? $params : [$params]),
192 ];
5bb8417a
TO
193 }
194 else {
c64f69d9 195 $this->callbacks[$phase][] = [
5bb8417a 196 'callback' => $callback,
c64f69d9
CW
197 'parameters' => (is_array($params) ? $params : [$params]),
198 ];
5bb8417a
TO
199 }
200 }
201
202 /**
203 * @param int $phase
204 */
205 public function invokeCallbacks($phase) {
206 if (is_array($this->callbacks[$phase])) {
207 foreach ($this->callbacks[$phase] as $cb) {
208 call_user_func_array($cb['callback'], $cb['parameters']);
209 }
210 }
211 }
212
213}