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