commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / civicrm / Civi / Core / Transaction / Manager.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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 +--------------------------------------------------------------------+
26 */
27
28 namespace Civi\Core\Transaction;
29
30 /**
31 *
32 * @package Civi
33 * @copyright CiviCRM LLC (c) 2004-2015
34 */
35 class Manager {
36
37 private static $singleton = NULL;
38
39 /**
40 * @var \CRM_Core_DAO
41 */
42 private $dao;
43
44 /**
45 * @var array<Frame> stack of SQL transactions/savepoints
46 */
47 private $frames = array();
48
49 /**
50 * @var int
51 */
52 private $savePointCount = 0;
53
54 /**
55 * @param bool $fresh
56 * @return Manager
57 */
58 public static function singleton($fresh = FALSE) {
59 if (NULL === self::$singleton || $fresh) {
60 self::$singleton = new Manager(new \CRM_Core_DAO());
61 }
62 return self::$singleton;
63 }
64
65 /**
66 * @param CRM_Core_DAO $dao
67 * Handle for the DB connection that will execute transaction statements.
68 * (all we really care about is the query() function)
69 */
70 public function __construct($dao) {
71 $this->dao = $dao;
72 }
73
74 /**
75 * Increment the transaction count / add a new transaction level
76 *
77 * @param bool $nest
78 * Determines what to do if there's currently an active transaction:.
79 * - If true, then make a new nested transaction ("SAVEPOINT")
80 * - If false, then attach to the existing transaction
81 */
82 public function inc($nest = FALSE) {
83 if (!isset($this->frames[0])) {
84 $frame = $this->createBaseFrame();
85 array_unshift($this->frames, $frame);
86 $frame->inc();
87 $frame->begin();
88 }
89 elseif ($nest) {
90 $frame = $this->createSavePoint();
91 array_unshift($this->frames, $frame);
92 $frame->inc();
93 $frame->begin();
94 }
95 else {
96 $this->frames[0]->inc();
97 }
98 }
99
100 /**
101 * Decrement the transaction count / close out a transaction level
102 *
103 * @throws \CRM_Core_Exception
104 */
105 public function dec() {
106 if (!isset($this->frames[0]) || $this->frames[0]->isEmpty()) {
107 throw new \CRM_Core_Exception('Transaction integrity error: Expected to find active frame');
108 }
109
110 $this->frames[0]->dec();
111
112 if ($this->frames[0]->isEmpty()) {
113 // Callbacks may cause additional work (such as new transactions),
114 // and it would be confusing if the old frame was still active.
115 // De-register it before calling finish().
116 $oldFrame = array_shift($this->frames);
117 $oldFrame->finish();
118 }
119 }
120
121 /**
122 * Force an immediate rollback, regardless of how many
123 * transaction or frame objects exist.
124 *
125 * This is only appropriate when it is _certain_ that the
126 * callstack will not wind-down normally -- e.g. before
127 * a call to exit().
128 */
129 public function forceRollback() {
130 // we take the long-way-round (rolling back each frame) so that the
131 // internal state of each frame is consistent with its outcome
132
133 $oldFrames = $this->frames;
134 $this->frames = array();
135 foreach ($oldFrames as $oldFrame) {
136 $oldFrame->forceRollback();
137 }
138 }
139
140 /**
141 * Get the (innermost) SQL transaction.
142 *
143 * @return \Civi\Core\Transaction\Frame
144 */
145 public function getFrame() {
146 return isset($this->frames[0]) ? $this->frames[0] : NULL;
147 }
148
149 /**
150 * Get the (outermost) SQL transaction (i.e. the one
151 * demarcated by BEGIN/COMMIT/ROLLBACK)
152 *
153 * @return \Civi\Core\Transaction\Frame
154 */
155 public function getBaseFrame() {
156 if (empty($this->frames)) {
157 return NULL;
158 }
159 return $this->frames[count($this->frames) - 1];
160 }
161
162 /**
163 * @return \Civi\Core\Transaction\Frame
164 */
165 protected function createBaseFrame() {
166 return new Frame($this->dao, 'BEGIN', 'COMMIT', 'ROLLBACK');
167 }
168
169 /**
170 * @return \Civi\Core\Transaction\Frame
171 */
172 protected function createSavePoint() {
173 $spId = $this->savePointCount++;
174 return new Frame($this->dao, "SAVEPOINT civi_{$spId}", NULL, "ROLLBACK TO SAVEPOINT civi_{$spId}");
175 }
176
177 }