Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
fee14197 | 4 | | CiviCRM version 5 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
8c9251b3 | 6 | | Copyright CiviCRM LLC (c) 2004-2018 | |
6a488035 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 | */ |
6a488035 TO |
27 | |
28 | /** | |
29 | * | |
30 | * @package CRM | |
8c9251b3 | 31 | * @copyright CiviCRM LLC (c) 2004-2018 |
6a488035 TO |
32 | * $Id$ |
33 | * | |
34 | */ | |
35 | class CRM_Upgrade_Form extends CRM_Core_Form { | |
7da04cde | 36 | const QUEUE_NAME = 'CRM_Upgrade'; |
6a488035 TO |
37 | |
38 | /** | |
39 | * Minimum size of MySQL's thread_stack option | |
40 | * | |
41 | * @see install/index.php MINIMUM_THREAD_STACK | |
42 | */ | |
43 | const MINIMUM_THREAD_STACK = 192; | |
44 | ||
304c1a5a CW |
45 | /** |
46 | * Minimum previous CiviCRM version we can directly upgrade from | |
47 | */ | |
49cdccf4 | 48 | const MINIMUM_UPGRADABLE_VERSION = '4.1.3'; |
304c1a5a CW |
49 | |
50 | /** | |
cc1f4988 | 51 | * Minimum php version required to run (equal to or lower than the minimum install version) |
304c1a5a | 52 | */ |
e2383acd | 53 | const MINIMUM_PHP_VERSION = '5.5'; |
304c1a5a | 54 | |
6a488035 TO |
55 | protected $_config; |
56 | ||
6a488035 | 57 | /** |
fe482240 | 58 | * Upgrade for multilingual. |
6a488035 TO |
59 | * |
60 | * @var boolean | |
6a488035 TO |
61 | */ |
62 | public $multilingual = FALSE; | |
63 | ||
64 | /** | |
fe482240 | 65 | * Locales available for multilingual upgrade. |
6a488035 TO |
66 | * |
67 | * @var array | |
6a488035 TO |
68 | */ |
69 | public $locales; | |
70 | ||
624e56fa | 71 | /** |
fe482240 | 72 | * Constructor for the basic form page. |
624e56fa EM |
73 | * |
74 | * We should not use QuickForm directly. This class provides a lot | |
75 | * of default convenient functions, rules and buttons | |
76 | * | |
c68f8bfa TO |
77 | * @param object $state |
78 | * State associated with this form. | |
e8e8f3ad | 79 | * @param const|\enum|int $action The mode the form is operating in (None/Create/View/Update/Delete) |
c68f8bfa TO |
80 | * @param string $method |
81 | * The type of http method used (GET/POST). | |
82 | * @param string $name | |
83 | * The name of the form if different from class name. | |
624e56fa | 84 | */ |
ae5ffbb7 | 85 | public function __construct( |
4e66d748 | 86 | $state = NULL, |
6a488035 TO |
87 | $action = CRM_Core_Action::NONE, |
88 | $method = 'post', | |
e418776c | 89 | $name = NULL |
6a488035 TO |
90 | ) { |
91 | $this->_config = CRM_Core_Config::singleton(); | |
92 | ||
6a488035 TO |
93 | $domain = new CRM_Core_DAO_Domain(); |
94 | $domain->find(TRUE); | |
95 | ||
96 | $this->multilingual = (bool) $domain->locales; | |
97 | $this->locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales); | |
98 | ||
99 | $smarty = CRM_Core_Smarty::singleton(); | |
635f0b86 | 100 | //$smarty->compile_dir = $this->_config->templateCompileDir; |
6a488035 TO |
101 | $smarty->assign('multilingual', $this->multilingual); |
102 | $smarty->assign('locales', $this->locales); | |
103 | ||
104 | // we didn't call CRM_Core_BAO_ConfigSetting::retrieve(), so we need to set $dbLocale by hand | |
105 | if ($this->multilingual) { | |
106 | global $dbLocale; | |
107 | $dbLocale = "_{$this->_config->lcMessages}"; | |
108 | } | |
109 | ||
110 | parent::__construct($state, $action, $method, $name); | |
111 | } | |
112 | ||
624e56fa EM |
113 | /** |
114 | * @param $version | |
115 | * | |
116 | * @return mixed | |
117 | */ | |
00be9182 | 118 | public static function &incrementalPhpObject($version) { |
6a488035 TO |
119 | static $incrementalPhpObject = array(); |
120 | ||
121 | $versionParts = explode('.', $version); | |
0ae8b1af | 122 | $versionName = CRM_Utils_EnglishNumber::toCamelCase($versionParts[0]) . CRM_Utils_EnglishNumber::toCamelCase($versionParts[1]); |
6a488035 TO |
123 | |
124 | if (!array_key_exists($versionName, $incrementalPhpObject)) { | |
0e6e8724 | 125 | $className = "CRM_Upgrade_Incremental_php_{$versionName}"; |
e8cb3963 | 126 | $incrementalPhpObject[$versionName] = new $className(); |
6a488035 TO |
127 | } |
128 | return $incrementalPhpObject[$versionName]; | |
129 | } | |
130 | ||
624e56fa EM |
131 | /** |
132 | * @param $version | |
133 | * @param $release | |
134 | * | |
135 | * @return bool | |
136 | */ | |
00be9182 | 137 | public function checkVersionRelease($version, $release) { |
6a488035 | 138 | $versionParts = explode('.', $version); |
bf6a5362 | 139 | return ($versionParts[2] == $release); |
6a488035 TO |
140 | } |
141 | ||
624e56fa EM |
142 | /** |
143 | * @param $constraints | |
144 | * | |
145 | * @return array | |
146 | */ | |
00be9182 | 147 | public function checkSQLConstraints(&$constraints) { |
6a488035 TO |
148 | $pass = $fail = 0; |
149 | foreach ($constraints as $constraint) { | |
150 | if ($this->checkSQLConstraint($constraint)) { | |
151 | $pass++; | |
152 | } | |
153 | else { | |
154 | $fail++; | |
155 | } | |
156 | return array($pass, $fail); | |
157 | } | |
158 | } | |
159 | ||
624e56fa EM |
160 | /** |
161 | * @param $constraint | |
162 | * | |
163 | * @return bool | |
164 | */ | |
00be9182 | 165 | public function checkSQLConstraint($constraint) { |
6a488035 TO |
166 | // check constraint here |
167 | return TRUE; | |
168 | } | |
169 | ||
624e56fa | 170 | /** |
100fef9d | 171 | * @param string $fileName |
624e56fa EM |
172 | * @param bool $isQueryString |
173 | */ | |
00be9182 | 174 | public function source($fileName, $isQueryString = FALSE) { |
c0e4c31d JK |
175 | if ($isQueryString) { |
176 | CRM_Utils_File::runSqlQuery($this->_config->dsn, | |
177 | $fileName, NULL | |
178 | ); | |
179 | } | |
180 | else { | |
181 | CRM_Utils_File::sourceSQLFile($this->_config->dsn, | |
182 | $fileName, NULL | |
183 | ); | |
184 | } | |
6a488035 TO |
185 | } |
186 | ||
00be9182 | 187 | public function preProcess() { |
6a488035 TO |
188 | CRM_Utils_System::setTitle($this->getTitle()); |
189 | if (!$this->verifyPreDBState($errorMessage)) { | |
190 | if (!isset($errorMessage)) { | |
191 | $errorMessage = 'pre-condition failed for current upgrade step'; | |
192 | } | |
193 | CRM_Core_Error::fatal($errorMessage); | |
194 | } | |
195 | $this->assign('recentlyViewed', FALSE); | |
196 | } | |
197 | ||
00be9182 | 198 | public function buildQuickForm() { |
6a488035 TO |
199 | $this->addDefaultButtons($this->getButtonTitle(), |
200 | 'next', | |
201 | NULL, | |
202 | TRUE | |
203 | ); | |
204 | } | |
205 | ||
624e56fa | 206 | /** |
100fef9d | 207 | * Getter function for title. Should be over-ridden by derived class |
624e56fa EM |
208 | * |
209 | * @return string | |
624e56fa EM |
210 | */ |
211 | /** | |
212 | * @return string | |
213 | */ | |
00be9182 | 214 | public function getTitle() { |
6a488035 TO |
215 | return ts('Title not Set'); |
216 | } | |
217 | ||
624e56fa EM |
218 | /** |
219 | * @return string | |
220 | */ | |
00be9182 | 221 | public function getFieldsetTitle() { |
ba8f6a69 | 222 | return ''; |
6a488035 TO |
223 | } |
224 | ||
624e56fa EM |
225 | /** |
226 | * @return string | |
227 | */ | |
00be9182 | 228 | public function getButtonTitle() { |
6a488035 TO |
229 | return ts('Continue'); |
230 | } | |
231 | ||
624e56fa | 232 | /** |
fe482240 | 233 | * Use the form name to create the tpl file name. |
624e56fa EM |
234 | * |
235 | * @return string | |
624e56fa EM |
236 | */ |
237 | /** | |
238 | * @return string | |
239 | */ | |
00be9182 | 240 | public function getTemplateFileName() { |
6a488035 TO |
241 | $this->assign('title', |
242 | $this->getFieldsetTitle() | |
243 | ); | |
244 | $this->assign('message', | |
245 | $this->getTemplateMessage() | |
246 | ); | |
247 | return 'CRM/Upgrade/Base.tpl'; | |
248 | } | |
249 | ||
00be9182 | 250 | public function postProcess() { |
6a488035 TO |
251 | $this->upgrade(); |
252 | ||
253 | if (!$this->verifyPostDBState($errorMessage)) { | |
254 | if (!isset($errorMessage)) { | |
255 | $errorMessage = 'post-condition failed for current upgrade step'; | |
256 | } | |
257 | CRM_Core_Error::fatal($errorMessage); | |
258 | } | |
259 | } | |
260 | ||
624e56fa EM |
261 | /** |
262 | * @param $query | |
263 | * | |
264 | * @return Object | |
265 | */ | |
00be9182 | 266 | public function runQuery($query) { |
6a488035 TO |
267 | return CRM_Core_DAO::executeQuery($query, |
268 | CRM_Core_DAO::$_nullArray | |
269 | ); | |
270 | } | |
271 | ||
624e56fa EM |
272 | /** |
273 | * @param $version | |
274 | * | |
275 | * @return Object | |
276 | */ | |
00be9182 | 277 | public function setVersion($version) { |
6a488035 TO |
278 | $this->logVersion($version); |
279 | ||
280 | $query = " | |
281 | UPDATE civicrm_domain | |
282 | SET version = '$version' | |
283 | "; | |
284 | return $this->runQuery($query); | |
285 | } | |
286 | ||
624e56fa EM |
287 | /** |
288 | * @param $newVersion | |
289 | * | |
290 | * @return bool | |
291 | */ | |
00be9182 | 292 | public function logVersion($newVersion) { |
6a488035 TO |
293 | if ($newVersion) { |
294 | $oldVersion = CRM_Core_BAO_Domain::version(); | |
295 | ||
296 | $session = CRM_Core_Session::singleton(); | |
297 | $logParams = array( | |
298 | 'entity_table' => 'civicrm_domain', | |
299 | 'entity_id' => 1, | |
300 | 'data' => "upgrade:{$oldVersion}->{$newVersion}", | |
301 | // lets skip 'modified_id' for now, as it causes FK issues And | |
302 | // is not very important for now. | |
303 | 'modified_date' => date('YmdHis'), | |
304 | ); | |
305 | CRM_Core_BAO_Log::add($logParams); | |
306 | return TRUE; | |
307 | } | |
308 | ||
309 | return FALSE; | |
310 | } | |
311 | ||
624e56fa EM |
312 | /** |
313 | * @param $version | |
314 | * | |
315 | * @return bool | |
316 | */ | |
00be9182 | 317 | public function checkVersion($version) { |
6a488035 TO |
318 | $domainID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', |
319 | $version, 'id', | |
320 | 'version' | |
321 | ); | |
322 | return $domainID ? TRUE : FALSE; | |
323 | } | |
324 | ||
624e56fa EM |
325 | /** |
326 | * @return array | |
327 | * @throws Exception | |
328 | */ | |
00be9182 | 329 | public function getRevisionSequence() { |
6a488035 TO |
330 | $revList = array(); |
331 | $sqlDir = implode(DIRECTORY_SEPARATOR, | |
332 | array(dirname(__FILE__), 'Incremental', 'sql') | |
333 | ); | |
334 | $sqlFiles = scandir($sqlDir); | |
335 | ||
336 | $sqlFilePattern = '/^((\d{1,2}\.\d{1,2})\.(\d{1,2}\.)?(\d{1,2}|\w{4,7}))\.(my)?sql(\.tpl)?$/i'; | |
337 | foreach ($sqlFiles as $file) { | |
338 | if (preg_match($sqlFilePattern, $file, $matches)) { | |
6a488035 TO |
339 | if (!in_array($matches[1], $revList)) { |
340 | $revList[] = $matches[1]; | |
341 | } | |
342 | } | |
343 | } | |
344 | ||
6a488035 TO |
345 | usort($revList, 'version_compare'); |
346 | return $revList; | |
347 | } | |
348 | ||
624e56fa EM |
349 | /** |
350 | * @param $rev | |
351 | * @param int $index | |
352 | * | |
353 | * @return null | |
354 | */ | |
00be9182 | 355 | public static function getRevisionPart($rev, $index = 1) { |
6a488035 TO |
356 | $revPattern = '/^((\d{1,2})\.\d{1,2})\.(\d{1,2}|\w{4,7})?$/i'; |
357 | preg_match($revPattern, $rev, $matches); | |
358 | ||
359 | return array_key_exists($index, $matches) ? $matches[$index] : NULL; | |
360 | } | |
361 | ||
624e56fa EM |
362 | /** |
363 | * @param $tplFile | |
364 | * @param $rev | |
365 | * | |
366 | * @return bool | |
367 | */ | |
00be9182 | 368 | public function processLocales($tplFile, $rev) { |
6a488035 TO |
369 | $smarty = CRM_Core_Smarty::singleton(); |
370 | $smarty->assign('domainID', CRM_Core_Config::domainID()); | |
371 | ||
372 | $this->source($smarty->fetch($tplFile), TRUE); | |
373 | ||
374 | if ($this->multilingual) { | |
375 | CRM_Core_I18n_Schema::rebuildMultilingualSchema($this->locales, $rev); | |
376 | } | |
377 | return $this->multilingual; | |
378 | } | |
379 | ||
624e56fa EM |
380 | /** |
381 | * @param $rev | |
382 | */ | |
00be9182 | 383 | public function setSchemaStructureTables($rev) { |
6a488035 TO |
384 | if ($this->multilingual) { |
385 | CRM_Core_I18n_Schema::schemaStructureTables($rev, TRUE); | |
386 | } | |
387 | } | |
388 | ||
624e56fa EM |
389 | /** |
390 | * @param $rev | |
391 | * | |
392 | * @throws Exception | |
393 | */ | |
00be9182 | 394 | public function processSQL($rev) { |
6a488035 TO |
395 | $sqlFile = implode(DIRECTORY_SEPARATOR, |
396 | array( | |
353ffa53 TO |
397 | dirname(__FILE__), |
398 | 'Incremental', | |
399 | 'sql', | |
400 | $rev . '.mysql', | |
6a488035 TO |
401 | ) |
402 | ); | |
403 | $tplFile = "$sqlFile.tpl"; | |
404 | ||
405 | if (file_exists($tplFile)) { | |
406 | $this->processLocales($tplFile, $rev); | |
407 | } | |
408 | else { | |
409 | if (!file_exists($sqlFile)) { | |
410 | CRM_Core_Error::fatal("sqlfile - $rev.mysql not found."); | |
411 | } | |
412 | $this->source($sqlFile); | |
413 | } | |
414 | } | |
415 | ||
416 | /** | |
fe482240 | 417 | * Determine the start and end version of the upgrade process. |
6a488035 TO |
418 | * |
419 | * @return array(0=>$currentVer, 1=>$latestVer) | |
420 | */ | |
00be9182 | 421 | public function getUpgradeVersions() { |
6a488035 | 422 | $latestVer = CRM_Utils_System::version(); |
e418776c | 423 | $currentVer = CRM_Core_BAO_Domain::version(TRUE); |
6a488035 TO |
424 | if (!$currentVer) { |
425 | CRM_Core_Error::fatal(ts('Version information missing in civicrm database.')); | |
426 | } | |
427 | elseif (stripos($currentVer, 'upgrade')) { | |
428 | CRM_Core_Error::fatal(ts('Database check failed - the database looks to have been partially upgraded. You may want to reload the database with the backup and try the upgrade process again.')); | |
429 | } | |
430 | if (!$latestVer) { | |
431 | CRM_Core_Error::fatal(ts('Version information missing in civicrm codebase.')); | |
432 | } | |
433 | ||
6a488035 TO |
434 | return array($currentVer, $latestVer); |
435 | } | |
436 | ||
437 | /** | |
438 | * Determine if $currentVer can be upgraded to $latestVer | |
439 | * | |
77b97be7 EM |
440 | * @param $currentVer |
441 | * @param $latestVer | |
442 | * | |
6a488035 TO |
443 | * @return mixed, a string error message or boolean 'false' if OK |
444 | */ | |
00be9182 | 445 | public function checkUpgradeableVersion($currentVer, $latestVer) { |
6a488035 TO |
446 | $error = FALSE; |
447 | // since version is suppose to be in valid format at this point, especially after conversion ($convertVer), | |
448 | // lets do a pattern check - | |
449 | if (!CRM_Utils_System::isVersionFormatValid($currentVer)) { | |
450 | $error = ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'); | |
451 | } | |
452 | elseif (version_compare($currentVer, $latestVer) > 0) { | |
453 | // DB version number is higher than codebase being upgraded to. This is unexpected condition-fatal error. | |
454 | $error = ts('Your database is marked with an unexpected version number: %1. The automated upgrade to version %2 can not be run - and the %2 codebase may not be compatible with your database state. You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase you were using prior to beginning this upgrade until you resolve this problem.', | |
304c1a5a | 455 | array(1 => $currentVer, 2 => $latestVer) |
6a488035 TO |
456 | ); |
457 | } | |
458 | elseif (version_compare($currentVer, $latestVer) == 0) { | |
459 | $error = ts('Your database has already been upgraded to CiviCRM %1', | |
460 | array(1 => $latestVer) | |
461 | ); | |
462 | } | |
304c1a5a CW |
463 | elseif (version_compare($currentVer, self::MINIMUM_UPGRADABLE_VERSION) < 0) { |
464 | $error = ts('CiviCRM versions prior to %1 cannot be upgraded directly to %2. This upgrade will need to be done in stages. First download an intermediate version (the LTS may be a good choice) and upgrade to that before proceeding to this version.', | |
465 | array(1 => self::MINIMUM_UPGRADABLE_VERSION, 2 => $latestVer) | |
466 | ); | |
467 | } | |
6a488035 | 468 | |
304c1a5a | 469 | if (version_compare(phpversion(), self::MINIMUM_PHP_VERSION) < 0) { |
6a488035 | 470 | $error = ts('CiviCRM %3 requires PHP version %1 (or newer), but the current system uses %2 ', |
353ffa53 | 471 | array( |
304c1a5a CW |
472 | 1 => self::MINIMUM_PHP_VERSION, |
473 | 2 => phpversion(), | |
353ffa53 TO |
474 | 3 => $latestVer, |
475 | )); | |
6a488035 TO |
476 | } |
477 | ||
478 | // check for mysql trigger privileges | |
509e50b7 | 479 | if (!\Civi::settings()->get('logging_no_trigger_permission') && !CRM_Core_DAO::checkTriggerViewPermission(FALSE, TRUE)) { |
6a488035 | 480 | $error = ts('CiviCRM %1 requires MySQL trigger privileges.', |
353ffa53 | 481 | array(1 => $latestVer)); |
6a488035 | 482 | } |
032c9d10 | 483 | |
e418776c | 484 | if (CRM_Core_DAO::getGlobalSetting('thread_stack', 0) < (1024 * self::MINIMUM_THREAD_STACK)) { |
6a488035 TO |
485 | $error = ts('CiviCRM %1 requires MySQL thread stack >= %2k', array( |
486 | 1 => $latestVer, | |
21dfd5f5 | 487 | 2 => self::MINIMUM_THREAD_STACK, |
6a488035 TO |
488 | )); |
489 | } | |
490 | ||
491 | return $error; | |
492 | } | |
493 | ||
494 | /** | |
495 | * Determine if $currentver already matches $latestVer | |
496 | * | |
77b97be7 EM |
497 | * @param $currentVer |
498 | * @param $latestVer | |
499 | * | |
6a488035 TO |
500 | * @return mixed, a string error message or boolean 'false' if OK |
501 | */ | |
00be9182 | 502 | public function checkCurrentVersion($currentVer, $latestVer) { |
6a488035 TO |
503 | $error = FALSE; |
504 | ||
505 | // since version is suppose to be in valid format at this point, especially after conversion ($convertVer), | |
506 | // lets do a pattern check - | |
507 | if (!CRM_Utils_System::isVersionFormatValid($currentVer)) { | |
508 | $error = ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'); | |
509 | } | |
510 | elseif (version_compare($currentVer, $latestVer) != 0) { | |
511 | $error = ts('Your database is not configured for version %1', | |
512 | array(1 => $latestVer) | |
513 | ); | |
514 | } | |
515 | return $error; | |
516 | } | |
517 | ||
518 | /** | |
fe482240 | 519 | * Fill the queue with upgrade tasks. |
6a488035 | 520 | * |
5a4f6742 CW |
521 | * @param string $currentVer |
522 | * the original revision. | |
523 | * @param string $latestVer | |
524 | * the target (final) revision. | |
525 | * @param string $postUpgradeMessageFile | |
526 | * path of a modifiable file which lists the post-upgrade messages. | |
6a488035 | 527 | * |
bf6a5362 | 528 | * @return CRM_Queue_Service |
6a488035 | 529 | */ |
00be9182 | 530 | public static function buildQueue($currentVer, $latestVer, $postUpgradeMessageFile) { |
6a488035 TO |
531 | $upgrade = new CRM_Upgrade_Form(); |
532 | ||
6a488035 TO |
533 | // Ensure that queue can be created |
534 | if (!CRM_Queue_BAO_QueueItem::findCreateTable()) { | |
535 | CRM_Core_Error::fatal(ts('Failed to find or create queueing table')); | |
536 | } | |
537 | $queue = CRM_Queue_Service::singleton()->create(array( | |
353ffa53 TO |
538 | 'name' => self::QUEUE_NAME, |
539 | 'type' => 'Sql', | |
540 | 'reset' => TRUE, | |
541 | )); | |
6a488035 | 542 | |
9e799b1d TO |
543 | $task = new CRM_Queue_Task( |
544 | array('CRM_Upgrade_Form', 'doFileCleanup'), | |
545 | array($postUpgradeMessageFile), | |
546 | "Cleanup old files" | |
547 | ); | |
548 | $queue->createItem($task); | |
549 | ||
6a488035 TO |
550 | $revisions = $upgrade->getRevisionSequence(); |
551 | foreach ($revisions as $rev) { | |
552 | // proceed only if $currentVer < $rev | |
553 | if (version_compare($currentVer, $rev) < 0) { | |
554 | $beginTask = new CRM_Queue_Task( | |
353ffa53 | 555 | // callback |
6a488035 TO |
556 | array('CRM_Upgrade_Form', 'doIncrementalUpgradeStart'), |
557 | // arguments | |
558 | array($rev), | |
559 | "Begin Upgrade to $rev" | |
560 | ); | |
561 | $queue->createItem($beginTask); | |
562 | ||
563 | $task = new CRM_Queue_Task( | |
353ffa53 | 564 | // callback |
6a488035 TO |
565 | array('CRM_Upgrade_Form', 'doIncrementalUpgradeStep'), |
566 | // arguments | |
567 | array($rev, $currentVer, $latestVer, $postUpgradeMessageFile), | |
568 | "Upgrade DB to $rev" | |
569 | ); | |
570 | $queue->createItem($task); | |
571 | ||
572 | $task = new CRM_Queue_Task( | |
353ffa53 | 573 | // callback |
6a488035 TO |
574 | array('CRM_Upgrade_Form', 'doIncrementalUpgradeFinish'), |
575 | // arguments | |
3373fe5e | 576 | array($rev, $currentVer, $latestVer, $postUpgradeMessageFile), |
6a488035 TO |
577 | "Finish Upgrade DB to $rev" |
578 | ); | |
579 | $queue->createItem($task); | |
580 | } | |
581 | } | |
582 | ||
583 | return $queue; | |
584 | } | |
585 | ||
9e799b1d TO |
586 | /** |
587 | * Find any old, orphaned files that should have been deleted. | |
588 | * | |
589 | * These files can get left behind, eg, if you use the Joomla | |
590 | * upgrade procedure. | |
591 | * | |
592 | * The earlier we can do this, the better - don't want upgrade logic | |
593 | * to inadvertently rely on old/relocated files. | |
594 | * | |
595 | * @param \CRM_Queue_TaskContext $ctx | |
596 | * @param string $postUpgradeMessageFile | |
597 | * @return bool | |
598 | */ | |
599 | public static function doFileCleanup(CRM_Queue_TaskContext $ctx, $postUpgradeMessageFile) { | |
600 | $source = new CRM_Utils_Check_Component_Source(); | |
601 | $files = $source->findOrphanedFiles(); | |
602 | $errors = array(); | |
603 | foreach ($files as $file) { | |
604 | if (is_dir($file['path'])) { | |
605 | @rmdir($file['path']); | |
606 | } | |
607 | else { | |
608 | @unlink($file['path']); | |
609 | } | |
610 | ||
611 | if (file_exists($file['path'])) { | |
612 | $errors[] = sprintf("<li>%s</li>", htmlentities($file['path'])); | |
613 | } | |
614 | } | |
615 | ||
616 | if (!empty($errors)) { | |
617 | file_put_contents($postUpgradeMessageFile, | |
618 | '<br/><br/>' . ts('Some old files could not be removed. Please remove them.') | |
619 | . '<ul>' . implode("\n", $errors) . '</ul>', | |
620 | FILE_APPEND | |
621 | ); | |
622 | } | |
623 | ||
624 | return TRUE; | |
625 | } | |
626 | ||
6a488035 | 627 | /** |
fe482240 | 628 | * Perform an incremental version update. |
6a488035 | 629 | * |
77b97be7 | 630 | * @param CRM_Queue_TaskContext $ctx |
5a4f6742 CW |
631 | * @param string $rev |
632 | * the target (intermediate) revision e.g '3.2.alpha1'. | |
77b97be7 EM |
633 | * |
634 | * @return bool | |
6a488035 | 635 | */ |
00be9182 | 636 | public static function doIncrementalUpgradeStart(CRM_Queue_TaskContext $ctx, $rev) { |
6a488035 TO |
637 | $upgrade = new CRM_Upgrade_Form(); |
638 | ||
639 | // as soon as we start doing anything we append ".upgrade" to version. | |
640 | // this also helps detect any partial upgrade issues | |
641 | $upgrade->setVersion($rev . '.upgrade'); | |
642 | ||
643 | return TRUE; | |
644 | } | |
645 | ||
646 | /** | |
fe482240 | 647 | * Perform an incremental version update. |
6a488035 | 648 | * |
77b97be7 | 649 | * @param CRM_Queue_TaskContext $ctx |
5a4f6742 CW |
650 | * @param string $rev |
651 | * the target (intermediate) revision e.g '3.2.alpha1'. | |
652 | * @param string $originalVer | |
653 | * the original revision. | |
654 | * @param string $latestVer | |
655 | * the target (final) revision. | |
656 | * @param string $postUpgradeMessageFile | |
657 | * path of a modifiable file which lists the post-upgrade messages. | |
77b97be7 EM |
658 | * |
659 | * @return bool | |
6a488035 | 660 | */ |
e418776c | 661 | public static function doIncrementalUpgradeStep(CRM_Queue_TaskContext $ctx, $rev, $originalVer, $latestVer, $postUpgradeMessageFile) { |
6a488035 TO |
662 | $upgrade = new CRM_Upgrade_Form(); |
663 | ||
664 | $phpFunctionName = 'upgrade_' . str_replace('.', '_', $rev); | |
665 | ||
bd00780f CW |
666 | $versionObject = $upgrade->incrementalPhpObject($rev); |
667 | ||
668 | // pre-db check for major release. | |
669 | if ($upgrade->checkVersionRelease($rev, 'alpha1')) { | |
d9c7af19 | 670 | if (!(is_callable(array($versionObject, 'verifyPreDBstate')))) { |
bd00780f | 671 | CRM_Core_Error::fatal("verifyPreDBstate method was not found for $rev"); |
6a488035 | 672 | } |
6a488035 | 673 | |
bd00780f CW |
674 | $error = NULL; |
675 | if (!($versionObject->verifyPreDBstate($error))) { | |
676 | if (!isset($error)) { | |
677 | $error = "post-condition failed for current upgrade for $rev"; | |
6a488035 | 678 | } |
bd00780f | 679 | CRM_Core_Error::fatal($error); |
6a488035 TO |
680 | } |
681 | ||
bd00780f | 682 | } |
6a488035 | 683 | |
bd00780f | 684 | $upgrade->setSchemaStructureTables($rev); |
6a488035 | 685 | |
d9c7af19 | 686 | if (is_callable(array($versionObject, $phpFunctionName))) { |
bd00780f CW |
687 | $versionObject->$phpFunctionName($rev, $originalVer, $latestVer); |
688 | } | |
689 | else { | |
690 | $upgrade->processSQL($rev); | |
691 | } | |
692 | ||
693 | // set post-upgrade-message if any | |
d9c7af19 | 694 | if (is_callable(array($versionObject, 'setPostUpgradeMessage'))) { |
bd00780f CW |
695 | $postUpgradeMessage = file_get_contents($postUpgradeMessageFile); |
696 | $versionObject->setPostUpgradeMessage($postUpgradeMessage, $rev); | |
bd00780f | 697 | file_put_contents($postUpgradeMessageFile, $postUpgradeMessage); |
6a488035 TO |
698 | } |
699 | ||
700 | return TRUE; | |
701 | } | |
702 | ||
703 | /** | |
fe482240 | 704 | * Perform an incremental version update. |
6a488035 | 705 | * |
77b97be7 | 706 | * @param CRM_Queue_TaskContext $ctx |
5a4f6742 CW |
707 | * @param string $rev |
708 | * the target (intermediate) revision e.g '3.2.alpha1'. | |
709 | * @param string $currentVer | |
710 | * the original revision. | |
711 | * @param string $latestVer | |
712 | * the target (final) revision. | |
713 | * @param string $postUpgradeMessageFile | |
714 | * path of a modifiable file which lists the post-upgrade messages. | |
77b97be7 EM |
715 | * |
716 | * @return bool | |
6a488035 | 717 | */ |
00be9182 | 718 | public static function doIncrementalUpgradeFinish(CRM_Queue_TaskContext $ctx, $rev, $currentVer, $latestVer, $postUpgradeMessageFile) { |
6a488035 TO |
719 | $upgrade = new CRM_Upgrade_Form(); |
720 | $upgrade->setVersion($rev); | |
721 | CRM_Utils_System::flushCache(); | |
ac05cde3 | 722 | |
d8a4acc0 C |
723 | $config = CRM_Core_Config::singleton(); |
724 | $config->userSystem->flush(); | |
6a488035 TO |
725 | return TRUE; |
726 | } | |
727 | ||
00be9182 | 728 | public static function doFinish() { |
6a488035 TO |
729 | $upgrade = new CRM_Upgrade_Form(); |
730 | list($ignore, $latestVer) = $upgrade->getUpgradeVersions(); | |
731 | // Seems extraneous in context, but we'll preserve old behavior | |
732 | $upgrade->setVersion($latestVer); | |
733 | ||
f806379b TO |
734 | // Clear cached metadata. |
735 | Civi::service('settings_manager')->flush(); | |
b6386d8c | 736 | |
6a488035 TO |
737 | // cleanup caches CRM-8739 |
738 | $config = CRM_Core_Config::singleton(); | |
1fcf16cc | 739 | $config->cleanupCaches(1); |
6a488035 | 740 | |
6b4bec74 CW |
741 | $versionCheck = new CRM_Utils_VersionCheck(); |
742 | $versionCheck->flushCache(); | |
743 | ||
6a488035 TO |
744 | // Rebuild all triggers and re-enable logging if needed |
745 | $logging = new CRM_Logging_Schema(); | |
746 | $logging->fixSchemaDifferences(); | |
747 | } | |
748 | ||
749 | /** | |
750 | * Compute any messages which should be displayed before upgrade | |
751 | * by calling the 'setPreUpgradeMessage' on each incremental upgrade | |
752 | * object. | |
753 | * | |
5a4f6742 CW |
754 | * @param string $preUpgradeMessage |
755 | * alterable. | |
77b97be7 EM |
756 | * @param $currentVer |
757 | * @param $latestVer | |
6a488035 | 758 | */ |
00be9182 | 759 | public function setPreUpgradeMessage(&$preUpgradeMessage, $currentVer, $latestVer) { |
49368097 CW |
760 | // check for changed message templates |
761 | CRM_Upgrade_Incremental_General::checkMessageTemplate($preUpgradeMessage, $latestVer, $currentVer); | |
762 | // set global messages | |
763 | CRM_Upgrade_Incremental_General::setPreUpgradeMessage($preUpgradeMessage, $currentVer, $latestVer); | |
6a488035 TO |
764 | |
765 | // Scan through all php files and see if any file is interested in setting pre-upgrade-message | |
766 | // based on $currentVer, $latestVer. | |
767 | // Please note, at this point upgrade hasn't started executing queries. | |
768 | $revisions = $this->getRevisionSequence(); | |
769 | foreach ($revisions as $rev) { | |
49368097 | 770 | if (version_compare($currentVer, $rev) < 0) { |
6a488035 | 771 | $versionObject = $this->incrementalPhpObject($rev); |
fe83c251 | 772 | CRM_Upgrade_Incremental_General::updateMessageTemplate($preUpgradeMessage, $rev); |
49368097 | 773 | if (is_callable(array($versionObject, 'setPreUpgradeMessage'))) { |
e418776c TO |
774 | $versionObject->setPreUpgradeMessage($preUpgradeMessage, $rev, $currentVer); |
775 | } | |
6a488035 TO |
776 | } |
777 | } | |
778 | } | |
96025800 | 779 | |
6a488035 | 780 | } |