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