3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
13 * Config handles all the run time configuration changes that the system needs to deal with.
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)
19 * @copyright CiviCRM LLC https://civicrm.org/licensing
22 require_once 'Log.php';
23 require_once 'Mail.php';
25 require_once 'api/api.php';
28 * Class CRM_Core_Config
30 * @property CRM_Utils_System_Base $userSystem
31 * @property CRM_Core_Permission_Base $userPermissionClass
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
51 * @property array fiscalYearStart
53 class CRM_Core_Config
extends CRM_Core_Config_MagicMerge
{
56 * The handle to the log that we are using
59 private static $_log = NULL;
62 * We only need one instance of this object. So we use the singleton
63 * pattern and cache the instance in this variable
65 * @var CRM_Core_Config
67 private static $_singleton = NULL;
70 * The constructor. Sets domain id if defined, otherwise assumes
71 * single instance installation.
73 public function __construct() {
74 parent
::__construct();
78 * Singleton function used to manage this object.
80 * @param bool $loadFromDB
81 * whether to load from the database.
83 * whether to force a reconstruction.
85 * @return CRM_Core_Config
87 public static function &singleton($loadFromDB = TRUE, $force = FALSE) {
88 if (self
::$_singleton === NULL ||
$force) {
89 $GLOBALS['civicrm_default_error_scope'] = CRM_Core_TemporaryErrorScope
::create(['CRM_Core_Error', 'exceptionHandler'], 1);
90 $errorScope = CRM_Core_TemporaryErrorScope
::create(['CRM_Core_Error', 'simpleHandler']);
92 self
::$_singleton = new CRM_Core_Config();
93 \Civi\Core\Container
::boot($loadFromDB);
94 if ($loadFromDB && self
::$_singleton->dsn
) {
95 $domain = \CRM_Core_BAO_Domain
::getDomain();
96 \CRM_Core_BAO_ConfigSetting
::applyLocale(\Civi
::settings($domain->id
), $domain->locales
);
100 CRM_Utils_Hook
::config(self
::$_singleton);
101 self
::$_singleton->authenticate();
103 // Extreme backward compat: $config binds to active domain at moment of setup.
104 self
::$_singleton->getSettings();
106 Civi
::service('settings_manager')->useDefaults();
108 self
::$_singleton->handleFirstRun();
111 return self
::$_singleton;
115 * Returns the singleton logger for the application.
121 public static function &getLog() {
122 if (!isset(self
::$_log)) {
123 self
::$_log = Log
::singleton('display');
130 * Retrieve a mailer to send any mail from the application.
134 * @see Civi::service()
136 public static function getMailer() {
137 return Civi
::service('pear_mail');
141 * Deletes the web server writable directories.
144 * 1: clean templates_c, 2: clean upload, 3: clean both
147 public function cleanup($value, $rmdir = TRUE) {
148 $value = (int ) $value;
152 CRM_Utils_File
::cleanDir($this->templateCompileDir
, $rmdir);
153 CRM_Utils_File
::createDir($this->templateCompileDir
);
157 CRM_Utils_File
::cleanDir($this->uploadDir
);
158 CRM_Utils_File
::createDir($this->uploadDir
);
161 // Whether we delete/create or simply preserve directories, we should
162 // certainly make sure the restrictions are enforced.
164 $this->templateCompileDir
,
166 $this->configAndLogDir
,
167 $this->customFileUploadDir
,
169 if ($dir && is_dir($dir)) {
170 CRM_Utils_File
::restrictAccess($dir);
176 * Verify that the needed parameters are not null in the config.
178 * @param CRM_Core_Config $config (reference) the system config object
179 * @param array $required (reference) the parameters that need a value
183 public static function check(&$config, &$required) {
184 foreach ($required as $name) {
185 if (CRM_Utils_System
::isNull($config->$name)) {
193 * Reset the serialized array and recompute.
198 public function reset() {
199 // This is what it used to do. However, it hasn't meant anything since 4.6.
200 // $query = "UPDATE civicrm_domain SET config_backend = null";
201 // CRM_Core_DAO::executeQuery($query);
205 * This method should initialize auth sources.
207 public function authenticate() {
208 // make sure session is always initialised
209 $session = CRM_Core_Session
::singleton();
211 // for logging purposes, pass the userID to the db
212 $userID = $session->get('userID');
214 CRM_Core_DAO
::executeQuery('SET @civicrm_user_id = %1',
215 [1 => [$userID, 'Integer']]
219 if ($session->get('userID') && !$session->get('authSrc')) {
220 $session->set('authSrc', CRM_Core_Permission
::AUTH_SRC_LOGIN
);
224 CRM_Contact_BAO_Contact_Permission
::initChecksumAuthSrc();
228 * One function to get domain ID.
230 * @param int $domainID
235 public static function domainID($domainID = NULL, $reset = FALSE) {
240 if ($reset ||
empty($domain)) {
241 $domain = defined('CIVICRM_DOMAIN_ID') ? CIVICRM_DOMAIN_ID
: 1;
244 return (int) $domain;
248 * Function to get environment.
255 public static function environment($env = NULL, $reset = FALSE) {
259 if ($reset ||
empty($environment)) {
260 $environment = Civi
::settings()->get('environment');
263 $environment = 'Production';
269 * Do general cleanup of caches, temp directories and temp tables
270 * @see https://issues.civicrm.org/jira/browse/CRM-8739
272 * @param bool $sessionReset
274 public function cleanupCaches($sessionReset = TRUE) {
275 // cleanup templates_c directory
276 $this->cleanup(1, FALSE);
279 self
::clearDBCache();
280 Civi
::cache('session')->clear();
281 CRM_Utils_System
::flushCache();
284 $session = CRM_Core_Session
::singleton();
290 * Do general cleanup of module permissions.
292 public function cleanupPermissions() {
293 $module_files = CRM_Extension_System
::singleton()->getMapper()->getActiveModuleFiles();
294 if ($this->userPermissionClass
->isModulePermissionSupported()) {
295 // Can store permissions -- so do it!
296 $this->userPermissionClass
->upgradePermissions(
297 CRM_Core_Permission
::basicPermissions()
301 // Cannot store permissions -- warn if any modules require them
302 $modules_with_perms = [];
303 foreach ($module_files as $module_file) {
304 $perms = $this->userPermissionClass
->getModulePermissions($module_file['prefix']);
305 if (!empty($perms)) {
306 $modules_with_perms[] = $module_file['prefix'];
309 if (!empty($modules_with_perms)) {
310 CRM_Core_Session
::setStatus(
311 ts('Some modules define permissions, but the CMS cannot store them: %1', [1 => implode(', ', $modules_with_perms)]),
312 ts('Permission Error'),
320 * Flush information about loaded modules.
322 public function clearModuleList() {
323 CRM_Extension_System
::singleton()->getCache()->flush();
324 CRM_Utils_Hook
::singleton(TRUE);
325 CRM_Core_PseudoConstant
::getModuleExtensions(TRUE);
326 CRM_Core_Module
::getAll(TRUE);
332 public static function clearDBCache() {
334 'TRUNCATE TABLE civicrm_acl_cache',
335 'TRUNCATE TABLE civicrm_acl_contact_cache',
336 'TRUNCATE TABLE civicrm_cache',
337 'TRUNCATE TABLE civicrm_prevnext_cache',
338 'UPDATE civicrm_group SET cache_date = NULL',
339 'TRUNCATE TABLE civicrm_group_contact_cache',
340 'TRUNCATE TABLE civicrm_menu',
341 'UPDATE civicrm_setting SET value = NULL WHERE name="navigation" AND contact_id IS NOT NULL',
344 foreach ($queries as $query) {
345 CRM_Core_DAO
::executeQuery($query);
348 // also delete all the import and export temp tables
349 self
::clearTempTables();
353 * Clear leftover temporary tables.
355 * This is called on upgrade, during tests and site move, from the cron and via clear caches in the UI.
357 * Currently the UI clear caches does not pass a time interval - which may need review as it does risk
358 * ripping the tables out from underneath a current action. This was considered but
359 * out-of-scope for CRM-16167
361 * @param string|bool $timeInterval
362 * Optional time interval for mysql date function.g '2 day'. This can be used to prevent
363 * tables created recently from being deleted.
365 public static function clearTempTables($timeInterval = FALSE) {
367 $dao = new CRM_Core_DAO();
369 SELECT TABLE_NAME as tableName
370 FROM INFORMATION_SCHEMA.TABLES
371 WHERE TABLE_SCHEMA = %1
373 TABLE_NAME LIKE 'civicrm_import_job_%'
374 OR TABLE_NAME LIKE 'civicrm_report_temp%'
375 OR TABLE_NAME LIKE 'civicrm_tmp_d%'
378 // NOTE: Cannot find use-cases where "civicrm_report_temp" would be durable. Could probably remove.
381 $query .= " AND CREATE_TIME < DATE_SUB(NOW(), INTERVAL {$timeInterval})";
384 $tableDAO = CRM_Core_DAO
::executeQuery($query, [1 => [$dao->database(), 'String']]);
386 while ($tableDAO->fetch()) {
387 $tables[] = $tableDAO->tableName
;
389 if (!empty($tables)) {
390 $table = implode(',', $tables);
391 // drop leftover temporary tables
392 CRM_Core_DAO
::executeQuery("DROP TABLE $table");
397 * Check if running in upgrade mode.
399 * @param string $path
403 public static function isUpgradeMode($path = NULL) {
404 if (defined('CIVICRM_UPGRADE_ACTIVE')) {
408 $upgradeInProcess = CRM_Core_Session
::singleton()->get('isUpgradePending');
409 if ($upgradeInProcess) {
414 // note: do not re-initialize config here, since this function is part of
415 // config initialization itself
417 if (defined('CIVICRM_UF') && CIVICRM_UF
== 'Joomla') {
421 $path = $_GET[$urlVar] ??
NULL;
424 if ($path && preg_match('/^civicrm\/upgrade(\/.*)?$/', $path)) {
432 * Is back office credit card processing enabled for this site - ie are there any installed processors that support
434 * This function is used for determining whether to show the submit credit card link, not for determining which processors to show, hence
438 public static function isEnabledBackOfficeCreditCardPayments() {
439 return CRM_Financial_BAO_PaymentProcessor
::hasPaymentProcessorSupporting(['BackOffice']);
445 public function addressSequence() {
446 CRM_Core_Error
::deprecatedFunctionWarning('CRM_Utils_Address::sequence(Civi::settings()->get(\'address_format\')');
447 return CRM_Utils_Address
::sequence(Civi
::settings()->get('address_format'));
453 public function defaultContactCountry() {
454 CRM_Core_Error
::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultContactCountry');
455 return CRM_Core_BAO_Country
::defaultContactCountry();
461 public function defaultContactCountryName() {
462 CRM_Core_Error
::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultContactCountryName');
463 return CRM_Core_BAO_Country
::defaultContactCountryName();
469 * @param string $defaultCurrency
473 public function defaultCurrencySymbol($defaultCurrency = NULL) {
474 CRM_Core_Error
::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultCurrencySymbol');
475 return CRM_Core_BAO_Country
::defaultCurrencySymbol($defaultCurrency);
479 * Resets the singleton, so that the next call to CRM_Core_Config::singleton()
480 * reloads completely.
482 * While normally we could call the singleton function with $force = TRUE,
483 * this function addresses a very specific use-case in the CiviCRM installer,
484 * where we cannot yet force a reload, but we want to make sure that the next
485 * call to this object gets a fresh start (ex: to initialize the DAO).
487 public function free() {
488 self
::$_singleton = NULL;
492 * Conditionally fire an event during the first page run.
494 * The install system is currently implemented several times, so it's hard to add
495 * new installation logic. We use a makeshift method to detect the first run.
497 * Situations to test:
499 * - Upgrade from an old version (predating first-run tracker)
500 * - Upgrade from an old version (with first-run tracking)
502 public function handleFirstRun() {
503 // Ordinarily, we prefetch settings en masse and find that the system is already installed.
504 // No extra SQL queries required.
505 if (Civi
::settings()->get('installed')) {
509 // Q: How should this behave during testing?
510 if (defined('CIVICRM_TEST')) {
514 // If schema hasn't been loaded yet, then do nothing. Don't want to interfere
515 // with the existing installers. NOTE: If we change the installer pageflow,
516 // then we may want to modify this behavior.
517 if (!CRM_Core_DAO
::checkTableExists('civicrm_domain')) {
521 // If we're handling an upgrade, then the system has already been used, so this
522 // is not the first run.
523 if (CRM_Core_Config
::isUpgradeMode()) {
526 $dao = CRM_Core_DAO
::executeQuery('SELECT version FROM civicrm_domain');
527 while ($dao->fetch()) {
528 if ($dao->version
&& version_compare($dao->version
, CRM_Utils_System
::version(), '<')) {
533 // The installation flag is stored in civicrm_setting, which is domain-aware. The
534 // flag could have been stored under a different domain.
535 $dao = CRM_Core_DAO
::executeQuery('
536 SELECT domain_id, value FROM civicrm_setting
537 WHERE is_domain = 1 AND name = "installed"
539 while ($dao->fetch()) {
540 $value = CRM_Utils_String
::unserialize($dao->value
);
541 if (!empty($value)) {
542 Civi
::settings()->set('installed', 1);
547 // OK, this looks new.
548 Civi
::dispatcher()->dispatch('civi.core.install', new \Civi\Core\Event\
SystemInstallEvent());
549 Civi
::settings()->set('installed', 1);
553 * Is the system permitted to flush caches at the moment.
555 public static function isPermitCacheFlushMode() {
556 return !CRM_Core_Config
::singleton()->doNotResetCache
;
560 * Set cache clearing to enabled or disabled.
562 * This might be enabled at the start of a long running process
563 * such as an import in order to delay clearing caches until the end.
565 * @param bool $enabled
566 * If true then caches can be cleared at this time.
568 public static function setPermitCacheFlushMode($enabled) {
569 CRM_Core_Config
::singleton()->doNotResetCache
= $enabled ?
0 : 1;