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