(dev/core#1387) Remove some lingering references to config_backend
[civicrm-core.git] / CRM / Core / Config.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 * Config handles all the run time configuration changes that the system needs to deal with.
8eedd10a 14 *
6a488035
TO
15 * Typically we'll have different values for a user's sandbox, a qa sandbox and a production area.
16 * The default values in general, should reflect production values (minimizes chances of screwing up)
17 *
18 * @package CRM
ca5cec67 19 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
20 */
21
df8de0eb 22require_once 'Log.php';
6a488035
TO
23require_once 'Mail.php';
24
25require_once 'api/api.php';
72536736 26
28518c90
EM
27/**
28 * Class CRM_Core_Config
e367c7b0
CW
29 *
30 * @property CRM_Utils_System_Base $userSystem
6d054a8e 31 * @property CRM_Core_Permission_Base $userPermissionClass
6b070fc0
CW
32 * @property array $enableComponents
33 * @property array $languageLimit
34 * @property bool $debug
35 * @property bool $doNotResetCache
36 * @property string $maxFileSize
37 * @property string $defaultCurrency
38 * @property string $defaultCurrencySymbol
39 * @property string $lcMessages
40 * @property string $fieldSeparator
41 * @property string $userFramework
42 * @property string $verpSeparator
43 * @property string $dateFormatFull
44 * @property string $resourceBase
45 * @property string $dsn
46 * @property string $customTemplateDir
47 * @property string $defaultContactCountry
48 * @property string $defaultContactStateProvince
49 * @property string $monetaryDecimalPoint
50 * @property string $monetaryThousandSeparator
81716ddb 51 * @property array fiscalYearStart
28518c90 52 */
c0a1f187 53class CRM_Core_Config extends CRM_Core_Config_MagicMerge {
4d66768d 54
6a488035
TO
55 /**
56 * The handle to the log that we are using
57 * @var object
58 */
59 private static $_log = NULL;
60
6a488035
TO
61 /**
62 * We only need one instance of this object. So we use the singleton
63 * pattern and cache the instance in this variable
72536736
AH
64 *
65 * @var CRM_Core_Config
6a488035
TO
66 */
67 private static $_singleton = NULL;
68
6a488035
TO
69 /**
70 * The constructor. Sets domain id if defined, otherwise assumes
71 * single instance installation.
6a488035 72 */
0acb7f15 73 public function __construct() {
c0a1f187 74 parent::__construct();
6a488035
TO
75 }
76
77 /**
78 * Singleton function used to manage this object.
79 *
5a4f6742
CW
80 * @param bool $loadFromDB
81 * whether to load from the database.
82 * @param bool $force
83 * whether to force a reconstruction.
6a488035 84 *
5af8c999 85 * @return CRM_Core_Config
6a488035 86 */
00be9182 87 public static function &singleton($loadFromDB = TRUE, $force = FALSE) {
6a488035 88 if (self::$_singleton === NULL || $force) {
be2fb01f
CW
89 $GLOBALS['civicrm_default_error_scope'] = CRM_Core_TemporaryErrorScope::create(['CRM_Core_Error', 'handle']);
90 $errorScope = CRM_Core_TemporaryErrorScope::create(['CRM_Core_Error', 'simpleHandler']);
6a488035 91
6a488035
TO
92 if (defined('E_DEPRECATED')) {
93 error_reporting(error_reporting() & ~E_DEPRECATED);
94 }
95
fc50f470 96 self::$_singleton = new CRM_Core_Config();
7f835399
TO
97 \Civi\Core\Container::boot($loadFromDB);
98 if ($loadFromDB && self::$_singleton->dsn) {
c0a1f187
TO
99 $domain = \CRM_Core_BAO_Domain::getDomain();
100 \CRM_Core_BAO_ConfigSetting::applyLocale(\Civi::settings($domain->id), $domain->locales);
6a488035 101
fc50f470 102 unset($errorScope);
6a488035 103
fc50f470
TO
104 CRM_Utils_Hook::config(self::$_singleton);
105 self::$_singleton->authenticate();
23bb9c85 106
fc50f470
TO
107 // Extreme backward compat: $config binds to active domain at moment of setup.
108 self::$_singleton->getSettings();
23bb9c85 109
fc50f470 110 Civi::service('settings_manager')->useDefaults();
0085db83
C
111
112 self::$_singleton->handleFirstRun();
fc50f470 113 }
6a488035
TO
114 }
115 return self::$_singleton;
116 }
117
6a488035 118 /**
d09edf64 119 * Returns the singleton logger for the application.
6a488035 120 *
c0a1f187 121 * @deprecated
6a488035 122 * @return object
c0a1f187 123 * @see Civi::log()
6a488035 124 */
518fa0ee 125 public static function &getLog() {
6a488035
TO
126 if (!isset(self::$_log)) {
127 self::$_log = Log::singleton('display');
128 }
129
130 return self::$_log;
131 }
132
6a488035 133 /**
d09edf64 134 * Retrieve a mailer to send any mail from the application.
6a488035 135 *
247eb841
TO
136 * @return Mail
137 * @deprecated
c0a1f187 138 * @see Civi::service()
6a488035 139 */
247eb841 140 public static function getMailer() {
048222df 141 return Civi::service('pear_mail');
72ad6c1b
TO
142 }
143
6a488035 144 /**
d09edf64 145 * Deletes the web server writable directories.
6a488035 146 *
72536736
AH
147 * @param int $value
148 * 1: clean templates_c, 2: clean upload, 3: clean both
149 * @param bool $rmdir
6a488035
TO
150 */
151 public function cleanup($value, $rmdir = TRUE) {
152 $value = (int ) $value;
153
154 if ($value & 1) {
155 // clean templates_c
156 CRM_Utils_File::cleanDir($this->templateCompileDir, $rmdir);
157 CRM_Utils_File::createDir($this->templateCompileDir);
158 }
159 if ($value & 2) {
160 // clean upload dir
161 CRM_Utils_File::cleanDir($this->uploadDir);
162 CRM_Utils_File::createDir($this->uploadDir);
fea6131e
TO
163 }
164
165 // Whether we delete/create or simply preserve directories, we should
166 // certainly make sure the restrictions are enforced.
be2fb01f 167 foreach ([
518fa0ee
SL
168 $this->templateCompileDir,
169 $this->uploadDir,
170 $this->configAndLogDir,
171 $this->customFileUploadDir,
172 ] as $dir) {
fea6131e
TO
173 if ($dir && is_dir($dir)) {
174 CRM_Utils_File::restrictAccess($dir);
175 }
6a488035
TO
176 }
177 }
178
179 /**
0880a9d0 180 * Verify that the needed parameters are not null in the config.
6a488035 181 *
8d7a9d07
CB
182 * @param CRM_Core_Config $config (reference) the system config object
183 * @param array $required (reference) the parameters that need a value
6a488035 184 *
8d7a9d07 185 * @return bool
6a488035 186 */
00be9182 187 public static function check(&$config, &$required) {
6a488035
TO
188 foreach ($required as $name) {
189 if (CRM_Utils_System::isNull($config->$name)) {
190 return FALSE;
191 }
192 }
193 return TRUE;
194 }
195
196 /**
0880a9d0 197 * Reset the serialized array and recompute.
6a488035 198 * use with care
502b6747
TO
199 *
200 * @deprecated
6a488035 201 */
00be9182 202 public function reset() {
502b6747
TO
203 // This is what it used to do. However, it hasn't meant anything since 4.6.
204 // $query = "UPDATE civicrm_domain SET config_backend = null";
205 // CRM_Core_DAO::executeQuery($query);
6a488035
TO
206 }
207
546b78fa 208 /**
0880a9d0 209 * This method should initialize auth sources.
546b78fa 210 */
635f0b86
TO
211 public function authenticate() {
212 // make sure session is always initialised
e8f14831 213 $session = CRM_Core_Session::singleton();
635f0b86
TO
214
215 // for logging purposes, pass the userID to the db
216 $userID = $session->get('userID');
217 if ($userID) {
218 CRM_Core_DAO::executeQuery('SET @civicrm_user_id = %1',
be2fb01f 219 [1 => [$userID, 'Integer']]
635f0b86
TO
220 );
221 }
222
e8f14831
DS
223 if ($session->get('userID') && !$session->get('authSrc')) {
224 $session->set('authSrc', CRM_Core_Permission::AUTH_SRC_LOGIN);
225 }
226
227 // checksum source
228 CRM_Contact_BAO_Contact_Permission::initChecksumAuthSrc();
229 }
230
6a488035 231 /**
0880a9d0 232 * One function to get domain ID.
ad37ac8e 233 *
234 * @param int $domainID
235 * @param bool $reset
236 *
237 * @return int|null
6a488035 238 */
00be9182 239 public static function domainID($domainID = NULL, $reset = FALSE) {
6a488035
TO
240 static $domain;
241 if ($domainID) {
242 $domain = $domainID;
243 }
244 if ($reset || empty($domain)) {
245 $domain = defined('CIVICRM_DOMAIN_ID') ? CIVICRM_DOMAIN_ID : 1;
246 }
247
322b59f0 248 return (int) $domain;
6a488035
TO
249 }
250
f008885c
E
251 /**
252 * Function to get environment.
253 *
254 * @param string $env
255 * @param bool $reset
256 *
257 * @return string
258 */
259 public static function environment($env = NULL, $reset = FALSE) {
f008885c
E
260 if ($env) {
261 $environment = $env;
262 }
263 if ($reset || empty($environment)) {
8a078f99 264 $environment = Civi::settings()->get('environment');
f008885c
E
265 }
266 if (!$environment) {
267 $environment = 'Production';
268 }
269 return $environment;
270 }
271
6a488035 272 /**
100fef9d 273 * Do general cleanup of caches, temp directories and temp tables
6a488035 274 * CRM-8739
ea3ddccf 275 *
276 * @param bool $sessionReset
6a488035 277 */
00be9182 278 public function cleanupCaches($sessionReset = TRUE) {
6a488035
TO
279 // cleanup templates_c directory
280 $this->cleanup(1, FALSE);
281
1b50807d 282 // clear all caches
6a488035 283 self::clearDBCache();
0a12cd4a 284 Civi::cache('session')->clear();
1b50807d 285 CRM_Utils_System::flushCache();
6a488035
TO
286
287 if ($sessionReset) {
288 $session = CRM_Core_Session::singleton();
289 $session->reset(2);
290 }
291 }
292
293 /**
294 * Do general cleanup of module permissions.
295 */
00be9182 296 public function cleanupPermissions() {
6a488035 297 $module_files = CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles();
7fccad46
TO
298 if ($this->userPermissionClass->isModulePermissionSupported()) {
299 // Can store permissions -- so do it!
0d8fc497
TO
300 $this->userPermissionClass->upgradePermissions(
301 CRM_Core_Permission::basicPermissions()
302 );
0db6c3e1
TO
303 }
304 else {
7fccad46 305 // Cannot store permissions -- warn if any modules require them
be2fb01f 306 $modules_with_perms = [];
7fccad46
TO
307 foreach ($module_files as $module_file) {
308 $perms = $this->userPermissionClass->getModulePermissions($module_file['prefix']);
309 if (!empty($perms)) {
310 $modules_with_perms[] = $module_file['prefix'];
311 }
312 }
313 if (!empty($modules_with_perms)) {
314 CRM_Core_Session::setStatus(
be2fb01f 315 ts('Some modules define permissions, but the CMS cannot store them: %1', [1 => implode(', ', $modules_with_perms)]),
7fccad46
TO
316 ts('Permission Error'),
317 'error'
318 );
319 }
6a488035
TO
320 }
321 }
322
323 /**
0880a9d0 324 * Flush information about loaded modules.
6a488035 325 */
00be9182 326 public function clearModuleList() {
6a488035
TO
327 CRM_Extension_System::singleton()->getCache()->flush();
328 CRM_Utils_Hook::singleton(TRUE);
329 CRM_Core_PseudoConstant::getModuleExtensions(TRUE);
330 CRM_Core_Module::getAll(TRUE);
331 }
332
333 /**
0880a9d0 334 * Clear db cache.
6a488035
TO
335 */
336 public static function clearDBCache() {
be2fb01f 337 $queries = [
6a488035
TO
338 'TRUNCATE TABLE civicrm_acl_cache',
339 'TRUNCATE TABLE civicrm_acl_contact_cache',
340 'TRUNCATE TABLE civicrm_cache',
341 'TRUNCATE TABLE civicrm_prevnext_cache',
342 'UPDATE civicrm_group SET cache_date = NULL',
343 'TRUNCATE TABLE civicrm_group_contact_cache',
344 'TRUNCATE TABLE civicrm_menu',
345 'UPDATE civicrm_setting SET value = NULL WHERE name="navigation" AND contact_id IS NOT NULL',
be2fb01f 346 ];
6a488035
TO
347
348 foreach ($queries as $query) {
349 CRM_Core_DAO::executeQuery($query);
350 }
351
5a302bbc
TO
352 if ($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) {
353 return $adapter::clearDBCache();
354 }
355
6a488035
TO
356 // also delete all the import and export temp tables
357 self::clearTempTables();
358 }
359
360 /**
0880a9d0 361 * Clear leftover temporary tables.
0383ef73
EM
362 *
363 * This is called on upgrade, during tests and site move, from the cron and via clear caches in the UI.
364 *
365 * Currently the UI clear caches does not pass a time interval - which may need review as it does risk
366 * ripping the tables out from underneath a current action. This was considered but
367 * out-of-scope for CRM-16167
368 *
369 * @param string|bool $timeInterval
370 * Optional time interval for mysql date function.g '2 day'. This can be used to prevent
371 * tables created recently from being deleted.
6a488035 372 */
0383ef73
EM
373 public static function clearTempTables($timeInterval = FALSE) {
374
375 $dao = new CRM_Core_DAO();
6a488035 376 $query = "
0383ef73
EM
377 SELECT TABLE_NAME as tableName
378 FROM INFORMATION_SCHEMA.TABLES
379 WHERE TABLE_SCHEMA = %1
380 AND (
381 TABLE_NAME LIKE 'civicrm_import_job_%'
0383ef73 382 OR TABLE_NAME LIKE 'civicrm_report_temp%'
40c8b829 383 OR TABLE_NAME LIKE 'civicrm_tmp_d%'
0383ef73
EM
384 )
385 ";
f7e48bad
TO
386 // NOTE: Cannot find use-cases where "civicrm_report_temp" would be durable. Could probably remove.
387
0383ef73
EM
388 if ($timeInterval) {
389 $query .= " AND CREATE_TIME < DATE_SUB(NOW(), INTERVAL {$timeInterval})";
390 }
391
be2fb01f
CW
392 $tableDAO = CRM_Core_DAO::executeQuery($query, [1 => [$dao->database(), 'String']]);
393 $tables = [];
6a488035
TO
394 while ($tableDAO->fetch()) {
395 $tables[] = $tableDAO->tableName;
396 }
397 if (!empty($tables)) {
398 $table = implode(',', $tables);
399 // drop leftover temporary tables
400 CRM_Core_DAO::executeQuery("DROP TABLE $table");
401 }
402 }
403
404 /**
0880a9d0 405 * Check if running in upgrade mode.
54957108 406 *
407 * @param string $path
408 *
409 * @return bool
6a488035 410 */
00be9182 411 public static function isUpgradeMode($path = NULL) {
6a488035
TO
412 if (defined('CIVICRM_UPGRADE_ACTIVE')) {
413 return TRUE;
414 }
415
416 if (!$path) {
417 // note: do not re-initialize config here, since this function is part of
418 // config initialization itself
419 $urlVar = 'q';
420 if (defined('CIVICRM_UF') && CIVICRM_UF == 'Joomla') {
421 $urlVar = 'task';
422 }
423
424 $path = CRM_Utils_Array::value($urlVar, $_GET);
425 }
426
427 if ($path && preg_match('/^civicrm\/upgrade(\/.*)?$/', $path)) {
428 return TRUE;
429 }
430
867a532b
TO
431 if ($path && preg_match('/^civicrm\/ajax\/l10n-js/', $path)
432 && !empty($_SERVER['HTTP_REFERER'])
433 ) {
434 $ref = parse_url($_SERVER['HTTP_REFERER']);
8b15d2e9
CW
435 if (
436 (!empty($ref['path']) && preg_match('/civicrm\/upgrade/', $ref['path'])) ||
437 (!empty($ref['query']) && preg_match('/civicrm\/upgrade/', urldecode($ref['query'])))
438 ) {
867a532b
TO
439 return TRUE;
440 }
441 }
442
6a488035
TO
443 return FALSE;
444 }
445
9be1374d
EM
446 /**
447 * Is back office credit card processing enabled for this site - ie are there any installed processors that support
fbcb6fba 448 * it?
52767de0
EM
449 * This function is used for determining whether to show the submit credit card link, not for determining which processors to show, hence
450 * it is a config var
9be1374d
EM
451 * @return bool
452 */
00be9182 453 public static function isEnabledBackOfficeCreditCardPayments() {
be2fb01f 454 return CRM_Financial_BAO_PaymentProcessor::hasPaymentProcessorSupporting(['BackOffice']);
9be1374d 455 }
96025800 456
0acb7f15
TO
457 /**
458 * @deprecated
459 */
460 public function addressSequence() {
9b118398 461 CRM_Core_Error::deprecatedFunctionWarning('CRM_Utils_Address::sequence(Civi::settings()->get(\'address_format\')');
0acb7f15
TO
462 return CRM_Utils_Address::sequence(Civi::settings()->get('address_format'));
463 }
464
465 /**
466 * @deprecated
467 */
468 public function defaultContactCountry() {
d14f0a66 469 CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultContactCountry');
0acb7f15
TO
470 return CRM_Core_BAO_Country::defaultContactCountry();
471 }
472
473 /**
474 * @deprecated
475 */
476 public function defaultContactCountryName() {
d14f0a66 477 CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultContactCountryName');
0acb7f15
TO
478 return CRM_Core_BAO_Country::defaultContactCountryName();
479 }
480
481 /**
482 * @deprecated
ea3ddccf 483 *
484 * @param string $defaultCurrency
485 *
486 * @return string
0acb7f15
TO
487 */
488 public function defaultCurrencySymbol($defaultCurrency = NULL) {
a5dfa653 489 CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultCurrencySymbol');
0acb7f15
TO
490 return CRM_Core_BAO_Country::defaultCurrencySymbol($defaultCurrency);
491 }
492
97b8e6b2 493 /**
494 * Resets the singleton, so that the next call to CRM_Core_Config::singleton()
495 * reloads completely.
496 *
497 * While normally we could call the singleton function with $force = TRUE,
498 * this function addresses a very specific use-case in the CiviCRM installer,
499 * where we cannot yet force a reload, but we want to make sure that the next
500 * call to this object gets a fresh start (ex: to initialize the DAO).
501 */
502 public function free() {
503 self::$_singleton = NULL;
504 }
c8ab0a65 505
0085db83
C
506 /**
507 * Conditionally fire an event during the first page run.
508 *
509 * The install system is currently implemented several times, so it's hard to add
e047612e 510 * new installation logic. We use a makeshift method to detect the first run.
0085db83
C
511 *
512 * Situations to test:
513 * - New installation
514 * - Upgrade from an old version (predating first-run tracker)
515 * - Upgrade from an old version (with first-run tracking)
516 */
517 public function handleFirstRun() {
518 // Ordinarily, we prefetch settings en masse and find that the system is already installed.
519 // No extra SQL queries required.
520 if (Civi::settings()->get('installed')) {
521 return;
522 }
523
524 // Q: How should this behave during testing?
525 if (defined('CIVICRM_TEST')) {
526 return;
527 }
528
529 // If schema hasn't been loaded yet, then do nothing. Don't want to interfere
530 // with the existing installers. NOTE: If we change the installer pageflow,
531 // then we may want to modify this behavior.
532 if (!CRM_Core_DAO::checkTableExists('civicrm_domain')) {
533 return;
534 }
535
536 // If we're handling an upgrade, then the system has already been used, so this
537 // is not the first run.
538 if (CRM_Core_Config::isUpgradeMode()) {
539 return;
540 }
541 $dao = CRM_Core_DAO::executeQuery('SELECT version FROM civicrm_domain');
542 while ($dao->fetch()) {
543 if ($dao->version && version_compare($dao->version, CRM_Utils_System::version(), '<')) {
544 return;
545 }
546 }
547
548 // The installation flag is stored in civicrm_setting, which is domain-aware. The
549 // flag could have been stored under a different domain.
550 $dao = CRM_Core_DAO::executeQuery('
551 SELECT domain_id, value FROM civicrm_setting
552 WHERE is_domain = 1 AND name = "installed"
553 ');
554 while ($dao->fetch()) {
f24846d5 555 $value = CRM_Utils_String::unserialize($dao->value);
0085db83
C
556 if (!empty($value)) {
557 Civi::settings()->set('installed', 1);
558 return;
559 }
560 }
561
562 // OK, this looks new.
563 Civi::service('dispatcher')->dispatch(\Civi\Core\Event\SystemInstallEvent::EVENT_NAME, new \Civi\Core\Event\SystemInstallEvent());
564 Civi::settings()->set('installed', 1);
565 }
566
0626851e 567 /**
568 * Is the system permitted to flush caches at the moment.
569 */
518fa0ee 570 public static function isPermitCacheFlushMode() {
0626851e 571 return !CRM_Core_Config::singleton()->doNotResetCache;
572 }
573
574 /**
575 * Set cache clearing to enabled or disabled.
576 *
577 * This might be enabled at the start of a long running process
578 * such as an import in order to delay clearing caches until the end.
579 *
580 * @param bool $enabled
581 * If true then caches can be cleared at this time.
582 */
518fa0ee 583 public static function setPermitCacheFlushMode($enabled) {
0626851e 584 CRM_Core_Config::singleton()->doNotResetCache = $enabled ? 0 : 1;
585 }
586
6a488035 587}