Merge pull request #21965 from civicrm/5.43
[civicrm-core.git] / CRM / Core / BAO / ConfigSetting.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 *
15 * @package CRM
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 */
18
19 /**
20 * File contains functions used in civicrm configuration.
21 */
22 class CRM_Core_BAO_ConfigSetting {
23
24 /**
25 * Create civicrm settings. This is the same as add but it clears the cache and
26 * reloads the config object
27 *
28 * @param array $params
29 * Associated array of civicrm variables.
30 */
31 public static function create($params) {
32 self::add($params);
33 $cache = CRM_Utils_Cache::singleton();
34 $cache->delete('CRM_Core_Config');
35 $cache->delete('CRM_Core_Config' . CRM_Core_Config::domainID());
36 $config = CRM_Core_Config::singleton(TRUE, TRUE);
37 }
38
39 /**
40 * Add civicrm settings.
41 *
42 * @param array $params
43 * Associated array of civicrm variables.
44 * @deprecated
45 * This method was historically used to access civicrm_domain.config_backend.
46 * However, that has been fully replaced by the settings system since v4.7.
47 */
48 public static function add(&$params) {
49 $domain = new CRM_Core_DAO_Domain();
50 $domain->id = CRM_Core_Config::domainID();
51 $domain->find(TRUE);
52 if ($domain->config_backend) {
53 $params = array_merge(unserialize($domain->config_backend), $params);
54 }
55
56 $params = CRM_Core_BAO_ConfigSetting::filterSkipVars($params);
57
58 // also skip all Dir Params, we dont need to store those in the DB!
59 foreach ($params as $name => $val) {
60 if (substr($name, -3) == 'Dir') {
61 unset($params[$name]);
62 }
63 }
64
65 $domain->config_backend = serialize($params);
66 $domain->save();
67 }
68
69 /**
70 * Retrieve the settings values from db.
71 *
72 * @param $defaults
73 *
74 * @return array
75 * @deprecated
76 * This method was historically used to access civicrm_domain.config_backend.
77 * However, that has been fully replaced by the settings system since v4.7.
78 */
79 public static function retrieve(&$defaults) {
80 $domain = new CRM_Core_DAO_Domain();
81 $isUpgrade = CRM_Core_Config::isUpgradeMode();
82
83 //we are initializing config, really can't use, CRM-7863
84 $urlVar = 'q';
85 if (defined('CIVICRM_UF') && CIVICRM_UF == 'Joomla') {
86 $urlVar = 'task';
87 }
88
89 $hasBackend = CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_domain', 'config_backend');
90 if ($isUpgrade && $hasBackend) {
91 $domain->selectAdd('config_backend');
92 }
93 else {
94 $domain->selectAdd('locales');
95 }
96
97 $domain->id = CRM_Core_Config::domainID();
98 $domain->find(TRUE);
99 if ($hasBackend && $domain->config_backend) {
100 // This whole branch can probably be removed; the transitional loading
101 // is in SettingBag::loadValues(). Moreover, since 4.7.alpha1 dropped
102 // the column, anyone calling ::retrieve() has likely not gotten any data.
103 $defaults = unserialize($domain->config_backend);
104 if ($defaults === FALSE || !is_array($defaults)) {
105 $defaults = [];
106 return FALSE;
107 }
108
109 $skipVars = self::skipVars();
110 foreach ($skipVars as $skip) {
111 if (array_key_exists($skip, $defaults)) {
112 unset($defaults[$skip]);
113 }
114 }
115 }
116 if (!$isUpgrade) {
117 CRM_Core_BAO_ConfigSetting::applyLocale(Civi::settings($domain->id), $domain->locales);
118 }
119 }
120
121 /**
122 * Activate a chosen locale.
123 *
124 * The locale is set by updating the session and global variables.
125 *
126 * When there is a choice of permitted languages (set on the "Administer" ->
127 * "Localisation" -> "Languages, Currency, Locations" screen) the locale to
128 * be applied can come from a variety of sources. The list below is the order
129 * of priority for deciding which of the sources "wins":
130 *
131 * - The request - when the "lcMessages" query variable is present in the URL.
132 * - The session - when the "lcMessages" session variable has been set.
133 * - Inherited from the CMS - when the "inheritLocale" setting is set.
134 * - CiviCRM settings - the fallback when none of the above set the locale.
135 *
136 * Single-language installs skip this and always set the default locale.
137 *
138 * @param \Civi\Core\SettingsBag $settings
139 * @param string $activatedLocales
140 * Imploded list of locales which are supported in the DB.
141 */
142 public static function applyLocale($settings, $activatedLocales) {
143
144 // Declare access to locale globals.
145 global $dbLocale, $tsLocale;
146
147 // Grab session reference.
148 $session = CRM_Core_Session::singleton();
149
150 // Set flag for multi-language setup.
151 $multiLang = (bool) $activatedLocales;
152
153 // Initialise the default and chosen locales.
154 $defaultLocale = $settings->get('lcMessages');
155 $chosenLocale = NULL;
156
157 // When there is a choice of permitted languages.
158 $permittedLanguages = CRM_Core_I18n::uiLanguages(TRUE);
159 if (count($permittedLanguages) >= 2) {
160
161 // Is the "lcMessages" query variable present in the URL?
162 $requestLocale = CRM_Utils_Request::retrieve('lcMessages', 'String');
163 if (in_array($requestLocale, $permittedLanguages)) {
164 $chosenLocale = $requestLocale;
165 }
166
167 // Check the session if the chosen locale hasn't been set yet.
168 if (empty($chosenLocale)) {
169 $sessionLocale = $session->get('lcMessages');
170 if (in_array($sessionLocale, $permittedLanguages)) {
171 $chosenLocale = $sessionLocale;
172 }
173 }
174
175 /*
176 * Maybe inherit the language from the CMS.
177 *
178 * If the language is specified via "lcMessages" we skip this, since the
179 * intention of the URL query var is to override all other sources.
180 */
181 if ($settings->get('inheritLocale')) {
182
183 /*
184 * FIXME: On multi-language installs, CRM_Utils_System::getUFLocale() in
185 * many cases returns nothing if $dbLocale is not set, so set it to the
186 * default - even if it's overridden later.
187 */
188 $dbLocale = $multiLang && $defaultLocale ? "_{$defaultLocale}" : '';
189
190 // Retrieve locale as reported by CMS.
191 $cmsLocale = CRM_Utils_System::getUFLocale();
192 if (in_array($cmsLocale, $permittedLanguages)) {
193 $chosenLocale = $cmsLocale;
194 }
195
196 // Clear chosen locale if not activated in multi-language CiviCRM.
197 if ($activatedLocales && !in_array($chosenLocale, explode(CRM_Core_DAO::VALUE_SEPARATOR, $activatedLocales))) {
198 $chosenLocale = NULL;
199 }
200
201 }
202
203 // Assign the system default if the chosen locale hasn't been set.
204 if (empty($chosenLocale)) {
205 $chosenLocale = $defaultLocale;
206 }
207
208 }
209 else {
210
211 // CRM-11993 - Use default when it's a single-language install.
212 $chosenLocale = $defaultLocale;
213
214 }
215
216 if (!$session->isEmpty()) {
217 // Always assign the chosen locale to the session.
218 $session->set('lcMessages', $chosenLocale);
219 }
220
221 /*
222 * Set suffix for table names in multi-language installs.
223 * Use views if more than one language.
224 */
225 $dbLocale = $multiLang && $chosenLocale ? "_{$chosenLocale}" : '';
226
227 // FIXME: an ugly hack to fix CRM-4041.
228 $tsLocale = $chosenLocale;
229
230 /*
231 * FIXME: as bad a place as any to fix CRM-5428.
232 * (to be moved to a sane location along with the above)
233 */
234 if (function_exists('mb_internal_encoding')) {
235 mb_internal_encoding('UTF-8');
236 }
237
238 }
239
240 /**
241 * @param array $defaultValues
242 *
243 * @return string
244 * @throws Exception
245 */
246 public static function doSiteMove($defaultValues = []) {
247 $moveStatus = ts('Beginning site move process...') . '<br />';
248 $settings = Civi::settings();
249
250 foreach (array_merge(self::getPathSettings(), self::getUrlSettings()) as $key) {
251 $value = $settings->get($key);
252 if ($value && $value != $settings->getDefault($key)) {
253 if ($settings->getMandatory($key) === NULL) {
254 $settings->revert($key);
255 $moveStatus .= ts("WARNING: The setting (%1) has been reverted.", [
256 1 => $key,
257 ]);
258 $moveStatus .= '<br />';
259 }
260 else {
261 $moveStatus .= ts("WARNING: The setting (%1) is overridden and could not be reverted.", [
262 1 => $key,
263 ]);
264 $moveStatus .= '<br />';
265 }
266 }
267 }
268
269 $config = CRM_Core_Config::singleton();
270
271 // clear the template_c and upload directory also
272 $config->cleanup(3, TRUE);
273 $moveStatus .= ts('Template cache and upload directory have been cleared.') . '<br />';
274
275 // clear all caches
276 CRM_Core_Config::clearDBCache();
277 Civi::cache('session')->clear();
278 $moveStatus .= ts('Database cache tables cleared.') . '<br />';
279
280 $resetSessionTable = CRM_Utils_Request::retrieve('resetSessionTable',
281 'Boolean',
282 CRM_Core_DAO::$_nullArray,
283 FALSE,
284 FALSE
285 );
286 if ($config->userSystem->is_drupal &&
287 $resetSessionTable
288 ) {
289 db_query("DELETE FROM {sessions} WHERE 1");
290 $moveStatus .= ts('Drupal session table cleared.') . '<br />';
291 }
292 else {
293 $session = CRM_Core_Session::singleton();
294 $session->reset(2);
295 $moveStatus .= ts('Session has been reset.') . '<br />';
296 }
297
298 return $moveStatus;
299 }
300
301 /**
302 * Takes a componentName and enables it in the config.
303 * Primarily used during unit testing
304 *
305 * @param string $componentName
306 * Name of the component to be enabled, needs to be valid.
307 *
308 * @return bool
309 * true if valid component name and enabling succeeds, else false
310 */
311 public static function enableComponent($componentName) {
312 $config = CRM_Core_Config::singleton();
313 if (in_array($componentName, $config->enableComponents)) {
314 // component is already enabled
315 return TRUE;
316 }
317
318 // return if component does not exist
319 if (!array_key_exists($componentName, CRM_Core_Component::getComponents())) {
320 return FALSE;
321 }
322
323 // get enabled-components from DB and add to the list
324 $enabledComponents = Civi::settings()->get('enable_components');
325 $enabledComponents[] = $componentName;
326
327 self::setEnabledComponents($enabledComponents);
328
329 return TRUE;
330 }
331
332 /**
333 * Disable specified component.
334 *
335 * @param string $componentName
336 *
337 * @return bool
338 */
339 public static function disableComponent($componentName) {
340 $config = CRM_Core_Config::singleton();
341 if (!in_array($componentName, $config->enableComponents) ||
342 !array_key_exists($componentName, CRM_Core_Component::getComponents())
343 ) {
344 // Post-condition is satisfied.
345 return TRUE;
346 }
347
348 // get enabled-components from DB and add to the list
349 $enabledComponents = Civi::settings()->get('enable_components');
350 $enabledComponents = array_diff($enabledComponents, [$componentName]);
351
352 self::setEnabledComponents($enabledComponents);
353
354 return TRUE;
355 }
356
357 /**
358 * Set enabled components.
359 *
360 * @param array $enabledComponents
361 */
362 public static function setEnabledComponents($enabledComponents) {
363 // The on_change trigger on this setting will trigger a cache flush
364 Civi::settings()->set('enable_components', $enabledComponents);
365 }
366
367 /**
368 * @return array
369 */
370 public static function skipVars() {
371 return [
372 'dsn',
373 'templateCompileDir',
374 'userFrameworkDSN',
375 'userFramework',
376 'userFrameworkBaseURL',
377 'userFrameworkClass',
378 'userHookClass',
379 'userPermissionClass',
380 'userPermissionTemp',
381 'userFrameworkURLVar',
382 'userFrameworkVersion',
383 'newBaseURL',
384 'newBaseDir',
385 'newSiteName',
386 'configAndLogDir',
387 'qfKey',
388 'gettextResourceDir',
389 'cleanURL',
390 'entryURL',
391 'locale_custom_strings',
392 'localeCustomStrings',
393 'autocompleteContactSearch',
394 'autocompleteContactReference',
395 'checksumTimeout',
396 'checksum_timeout',
397 ];
398 }
399
400 /**
401 * @param array $params
402 * @return array
403 */
404 public static function filterSkipVars($params) {
405 $skipVars = self::skipVars();
406 foreach ($skipVars as $var) {
407 unset($params[$var]);
408 }
409 foreach (array_keys($params) as $key) {
410 if (preg_match('/^_qf_/', $key)) {
411 unset($params[$key]);
412 }
413 }
414 return $params;
415 }
416
417 /**
418 * @return array
419 */
420 private static function getUrlSettings() {
421 return [
422 'userFrameworkResourceURL',
423 'imageUploadURL',
424 'customCSSURL',
425 'extensionsURL',
426 ];
427 }
428
429 /**
430 * @return array
431 */
432 private static function getPathSettings() {
433 return [
434 'uploadDir',
435 'imageUploadDir',
436 'customFileUploadDir',
437 'customTemplateDir',
438 'customPHPPathDir',
439 'extensionsDir',
440 ];
441 }
442
443 }