3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2018 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
28 namespace Civi\Core\Transaction
;
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).
36 * @copyright CiviCRM LLC (c) 2004-2018
40 const F_NEW
= 0, F_ACTIVE
= 1, F_DONE
= 2, F_FORCED
= 3;
48 * @var string|null e.g. "BEGIN" or "SAVEPOINT foo"
53 * @var string|null e.g. "COMMIT"
58 * @var string|null e.g. "ROLLBACK" or "ROLLBACK TO SAVEPOINT foo"
60 private $rollbackStmt;
65 private $refCount = 0;
67 private $doCommit = TRUE;
72 private $state = self
::F_NEW
;
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"
80 public function __construct($dao, $beginStmt, $commitStmt, $rollbackStmt) {
82 $this->beginStmt
= $beginStmt;
83 $this->commitStmt
= $commitStmt;
84 $this->rollbackStmt
= $rollbackStmt;
86 $this->callbacks
= array(
87 \CRM_Core_Transaction
::PHASE_PRE_COMMIT
=> array(),
88 \CRM_Core_Transaction
::PHASE_POST_COMMIT
=> array(),
89 \CRM_Core_Transaction
::PHASE_PRE_ROLLBACK
=> array(),
90 \CRM_Core_Transaction
::PHASE_POST_ROLLBACK
=> array(),
94 public function inc() {
98 public function dec() {
105 public function isEmpty() {
106 return ($this->refCount
== 0);
112 public function isRollbackOnly() {
113 return !$this->doCommit
;
116 public function setRollbackOnly() {
117 $this->doCommit
= FALSE;
121 * Begin frame processing.
123 * @throws \CRM_Core_Exception
125 public function begin() {
126 if ($this->state
!== self
::F_NEW
) {
127 throw new \
CRM_Core_Exception('State is not F_NEW');
130 $this->state
= self
::F_ACTIVE
;
131 if ($this->beginStmt
) {
132 $this->dao
->query($this->beginStmt
);
137 * Finish frame processing.
139 * @param int $newState
141 * @throws \CRM_Core_Exception
143 public function finish($newState = self
::F_DONE
) {
144 if ($this->state
== self
::F_FORCED
) {
147 if ($this->state
!== self
::F_ACTIVE
) {
148 throw new \
CRM_Core_Exception('State is not F_ACTIVE');
151 $this->state
= $newState;
153 if ($this->doCommit
) {
154 $this->invokeCallbacks(\CRM_Core_Transaction
::PHASE_PRE_COMMIT
);
155 if ($this->commitStmt
) {
156 $this->dao
->query($this->commitStmt
);
158 $this->invokeCallbacks(\CRM_Core_Transaction
::PHASE_POST_COMMIT
);
161 $this->invokeCallbacks(\CRM_Core_Transaction
::PHASE_PRE_ROLLBACK
);
162 if ($this->rollbackStmt
) {
163 $this->dao
->query($this->rollbackStmt
);
165 $this->invokeCallbacks(\CRM_Core_Transaction
::PHASE_POST_ROLLBACK
);
169 public function forceRollback() {
170 $this->setRollbackOnly();
171 $this->finish(self
::F_FORCED
);
175 * Add a transaction callback.
177 * Pre-condition: isActive()
180 * A constant; one of: self::PHASE_{PRE,POST}_{COMMIT,ROLLBACK}.
181 * @param mixed $callback
183 * @param array|NULL $params Optional values to pass to callback.
184 * See php manual call_user_func_array for details.
187 public function addCallback($phase, $callback, $params = NULL, $id = NULL) {
189 $this->callbacks
[$phase][$id] = array(
190 'callback' => $callback,
191 'parameters' => (is_array($params) ?
$params : array($params)),
195 $this->callbacks
[$phase][] = array(
196 'callback' => $callback,
197 'parameters' => (is_array($params) ?
$params : array($params)),
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']);