Commit | Line | Data |
---|---|---|
60488185 M |
1 | <?php |
2 | ||
3 | // AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file | |
4 | ||
5 | /** | |
6 | * Base class which provides helpers to execute upgrade logic | |
7 | */ | |
8 | class CRM_Wci_Upgrader_Base { | |
9 | ||
10 | /** | |
11 | * @var varies, subclass of htis | |
12 | */ | |
13 | static $instance; | |
14 | ||
15 | /** | |
16 | * @var CRM_Queue_TaskContext | |
17 | */ | |
18 | protected $ctx; | |
19 | ||
20 | /** | |
21 | * @var string, eg 'com.example.myextension' | |
22 | */ | |
23 | protected $extensionName; | |
24 | ||
25 | /** | |
26 | * @var string, full path to the extension's source tree | |
27 | */ | |
28 | protected $extensionDir; | |
29 | ||
30 | /** | |
31 | * @var array(revisionNumber) sorted numerically | |
32 | */ | |
33 | private $revisions; | |
34 | ||
35 | /** | |
36 | * Obtain a refernece to the active upgrade handler | |
37 | */ | |
38 | static public function instance() { | |
39 | if (! self::$instance) { | |
40 | // FIXME auto-generate | |
41 | self::$instance = new CRM_Wci_Upgrader( | |
ae48345c | 42 | 'org.civicrm.wci', |
60488185 M |
43 | realpath(__DIR__ .'/../../../') |
44 | ); | |
45 | } | |
46 | return self::$instance; | |
47 | } | |
48 | ||
49 | /** | |
50 | * Adapter that lets you add normal (non-static) member functions to the queue. | |
51 | * | |
52 | * Note: Each upgrader instance should only be associated with one | |
53 | * task-context; otherwise, this will be non-reentrant. | |
54 | * | |
55 | * @code | |
56 | * CRM_Wci_Upgrader_Base::_queueAdapter($ctx, 'methodName', 'arg1', 'arg2'); | |
57 | * @endcode | |
58 | */ | |
59 | static public function _queueAdapter() { | |
60 | $instance = self::instance(); | |
61 | $args = func_get_args(); | |
62 | $instance->ctx = array_shift($args); | |
63 | $instance->queue = $instance->ctx->queue; | |
64 | $method = array_shift($args); | |
65 | return call_user_func_array(array($instance, $method), $args); | |
66 | } | |
67 | ||
68 | public function __construct($extensionName, $extensionDir) { | |
69 | $this->extensionName = $extensionName; | |
70 | $this->extensionDir = $extensionDir; | |
71 | } | |
72 | ||
73 | // ******** Task helpers ******** | |
74 | ||
75 | /** | |
76 | * Run a CustomData file | |
77 | * | |
78 | * @param string $relativePath the CustomData XML file path (relative to this extension's dir) | |
79 | * @return bool | |
80 | */ | |
81 | public function executeCustomDataFile($relativePath) { | |
82 | $xml_file = $this->extensionDir . '/' . $relativePath; | |
83 | return $this->executeCustomDataFileByAbsPath($xml_file); | |
84 | } | |
85 | ||
86 | /** | |
87 | * Run a CustomData file | |
88 | * | |
89 | * @param string $xml_file the CustomData XML file path (absolute path) | |
90 | * @return bool | |
91 | */ | |
92 | protected static function executeCustomDataFileByAbsPath($xml_file) { | |
93 | require_once 'CRM/Utils/Migrate/Import.php'; | |
94 | $import = new CRM_Utils_Migrate_Import(); | |
95 | $import->run($xml_file); | |
96 | return TRUE; | |
97 | } | |
98 | ||
99 | /** | |
100 | * Run a SQL file | |
101 | * | |
102 | * @param string $relativePath the SQL file path (relative to this extension's dir) | |
103 | * @return bool | |
104 | */ | |
105 | public function executeSqlFile($relativePath) { | |
106 | CRM_Utils_File::sourceSQLFile( | |
107 | CIVICRM_DSN, | |
108 | $this->extensionDir . '/' . $relativePath | |
109 | ); | |
110 | return TRUE; | |
111 | } | |
112 | ||
113 | /** | |
114 | * Run one SQL query | |
115 | * | |
116 | * This is just a wrapper for CRM_Core_DAO::executeSql, but it | |
117 | * provides syntatic sugar for queueing several tasks that | |
118 | * run different queries | |
119 | */ | |
120 | public function executeSql($query, $params = array()) { | |
121 | // FIXME verify that we raise an exception on error | |
122 | CRM_Core_DAO::executeSql($query, $params); | |
123 | return TRUE; | |
124 | } | |
125 | ||
126 | /** | |
127 | * Syntatic sugar for enqueuing a task which calls a function | |
128 | * in this class. The task is weighted so that it is processed | |
129 | * as part of the currently-pending revision. | |
130 | * | |
131 | * After passing the $funcName, you can also pass parameters that will go to | |
132 | * the function. Note that all params must be serializable. | |
133 | */ | |
134 | public function addTask($title) { | |
135 | $args = func_get_args(); | |
136 | $title = array_shift($args); | |
137 | $task = new CRM_Queue_Task( | |
138 | array(get_class($this), '_queueAdapter'), | |
139 | $args, | |
140 | $title | |
141 | ); | |
142 | return $this->queue->createItem($task, array('weight' => -1)); | |
143 | } | |
144 | ||
145 | // ******** Revision-tracking helpers ******** | |
146 | ||
147 | /** | |
148 | * Determine if there are any pending revisions | |
149 | * | |
150 | * @return bool | |
151 | */ | |
152 | public function hasPendingRevisions() { | |
153 | $revisions = $this->getRevisions(); | |
154 | $currentRevision = $this->getCurrentRevision(); | |
155 | ||
156 | if (empty($revisions)) { | |
157 | return FALSE; | |
158 | } | |
159 | if (empty($currentRevision)) { | |
160 | return TRUE; | |
161 | } | |
162 | ||
163 | return ($currentRevision < max($revisions)); | |
164 | } | |
165 | ||
166 | /** | |
167 | * Add any pending revisions to the queue | |
168 | */ | |
169 | public function enqueuePendingRevisions(CRM_Queue_Queue $queue) { | |
170 | $this->queue = $queue; | |
171 | ||
172 | $currentRevision = $this->getCurrentRevision(); | |
173 | foreach ($this->getRevisions() as $revision) { | |
174 | if ($revision > $currentRevision) { | |
175 | $title = ts('Upgrade %1 to revision %2', array( | |
176 | 1 => $this->extensionName, | |
177 | 2 => $revision, | |
178 | )); | |
179 | ||
180 | // note: don't use addTask() because it sets weight=-1 | |
181 | ||
182 | $task = new CRM_Queue_Task( | |
183 | array(get_class($this), '_queueAdapter'), | |
184 | array('upgrade_' . $revision), | |
185 | $title | |
186 | ); | |
187 | $this->queue->createItem($task); | |
188 | ||
189 | $task = new CRM_Queue_Task( | |
190 | array(get_class($this), '_queueAdapter'), | |
191 | array('setCurrentRevision', $revision), | |
192 | $title | |
193 | ); | |
194 | $this->queue->createItem($task); | |
195 | } | |
196 | } | |
197 | } | |
198 | ||
199 | /** | |
200 | * Get a list of revisions | |
201 | * | |
202 | * @return array(revisionNumbers) sorted numerically | |
203 | */ | |
204 | public function getRevisions() { | |
205 | if (! is_array($this->revisions)) { | |
206 | $this->revisions = array(); | |
207 | ||
208 | $clazz = new ReflectionClass(get_class($this)); | |
209 | $methods = $clazz->getMethods(); | |
210 | foreach ($methods as $method) { | |
211 | if (preg_match('/^upgrade_(.*)/', $method->name, $matches)) { | |
212 | $this->revisions[] = $matches[1]; | |
213 | } | |
214 | } | |
215 | sort($this->revisions, SORT_NUMERIC); | |
216 | } | |
217 | ||
218 | return $this->revisions; | |
219 | } | |
220 | ||
221 | public function getCurrentRevision() { | |
222 | // return CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName); | |
223 | $key = $this->extensionName . ':version'; | |
224 | return CRM_Core_BAO_Setting::getItem('Extension', $key); | |
225 | } | |
226 | ||
227 | public function setCurrentRevision($revision) { | |
228 | // We call this during hook_civicrm_install, but the underlying SQL | |
229 | // UPDATE fails because the extension record hasn't been INSERTed yet. | |
230 | // Instead, track revisions in our own namespace. | |
231 | // CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision); | |
232 | ||
233 | $key = $this->extensionName . ':version'; | |
234 | CRM_Core_BAO_Setting::setItem($revision, 'Extension', $key); | |
235 | return TRUE; | |
236 | } | |
237 | ||
238 | // ******** Hook delegates ******** | |
239 | ||
240 | public function onInstall() { | |
241 | $files = glob($this->extensionDir . '/sql/*_install.sql'); | |
242 | if (is_array($files)) { | |
243 | foreach ($files as $file) { | |
244 | CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file); | |
245 | } | |
246 | } | |
247 | $files = glob($this->extensionDir . '/xml/*_install.xml'); | |
248 | if (is_array($files)) { | |
249 | foreach ($files as $file) { | |
250 | $this->executeCustomDataFileByAbsPath($file); | |
251 | } | |
252 | } | |
253 | if (is_callable(array($this, 'install'))) { | |
254 | $this->install(); | |
255 | } | |
256 | $revisions = $this->getRevisions(); | |
257 | if (!empty($revisions)) { | |
258 | $this->setCurrentRevision(max($revisions)); | |
259 | } | |
260 | } | |
261 | ||
262 | public function onUninstall() { | |
263 | if (is_callable(array($this, 'uninstall'))) { | |
264 | $this->uninstall(); | |
265 | } | |
266 | $files = glob($this->extensionDir . '/sql/*_uninstall.sql'); | |
267 | if (is_array($files)) { | |
268 | foreach ($files as $file) { | |
269 | CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file); | |
270 | } | |
271 | } | |
272 | $this->setCurrentRevision(NULL); | |
273 | } | |
274 | ||
275 | public function onEnable() { | |
276 | // stub for possible future use | |
277 | if (is_callable(array($this, 'enable'))) { | |
278 | $this->enable(); | |
279 | } | |
280 | } | |
281 | ||
282 | public function onDisable() { | |
283 | // stub for possible future use | |
284 | if (is_callable(array($this, 'disable'))) { | |
285 | $this->disable(); | |
286 | } | |
287 | } | |
288 | ||
289 | public function onUpgrade($op, CRM_Queue_Queue $queue = NULL) { | |
290 | switch($op) { | |
291 | case 'check': | |
292 | return array($this->hasPendingRevisions()); | |
293 | case 'enqueue': | |
294 | return $this->enqueuePendingRevisions($queue); | |
295 | default: | |
296 | } | |
297 | } | |
298 | } |