INFRA-132 - CRM/Core - Convert single-line @param to multi-line
[civicrm-core.git] / CRM / Core / BAO / ConfigSetting.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 *
31 * @package CRM
32 * @copyright CiviCRM LLC (c) 2004-2014
33 * $Id$
34 *
35 */
36
37 /**
38 * file contains functions used in civicrm configuration
39 *
40 */
41 class CRM_Core_BAO_ConfigSetting {
42
43 /**
44 * Create civicrm settings. This is the same as add but it clears the cache and
45 * reloads the config object
46 *
47 * @param array $params
48 * Associated array of civicrm variables.
49 *
50 * @return null
51 * @static
52 */
53 public static function create($params) {
54 self::add($params);
55 $cache = CRM_Utils_Cache::singleton();
56 $cache->delete('CRM_Core_Config');
57 $cache->delete('CRM_Core_Config' . CRM_Core_Config::domainID());
58 $config = CRM_Core_Config::singleton(TRUE, TRUE);
59 }
60
61 /**
62 * Add civicrm settings
63 *
64 * @param array $params
65 * Associated array of civicrm variables.
66 *
67 * @return null
68 * @static
69 */
70 public static function add(&$params) {
71 self::fixParams($params);
72
73 // also set a template url so js files can use this
74 // CRM-6194
75 $params['civiRelativeURL'] = CRM_Utils_System::url('CIVI_BASE_TEMPLATE');
76 $params['civiRelativeURL'] =
77 str_replace(
78 'CIVI_BASE_TEMPLATE',
79 '',
80 $params['civiRelativeURL']
81 );
82
83 // also add the version number for use by template / js etc
84 $params['civiVersion'] = CRM_Utils_System::version();
85
86 $domain = new CRM_Core_DAO_Domain();
87 $domain->id = CRM_Core_Config::domainID();
88 $domain->find(TRUE);
89 if ($domain->config_backend) {
90 $values = unserialize($domain->config_backend);
91 self::formatParams($params, $values);
92 }
93
94 // CRM-6151
95 if (isset($params['localeCustomStrings']) &&
96 is_array($params['localeCustomStrings'])
97 ) {
98 $domain->locale_custom_strings = serialize($params['localeCustomStrings']);
99 }
100
101 // unset any of the variables we read from file that should not be stored in the database
102 // the username and certpath are stored flat with _test and _live
103 // check CRM-1470
104 $skipVars = self::skipVars();
105 foreach ($skipVars as $var) {
106 unset($params[$var]);
107 }
108
109 CRM_Core_BAO_Setting::fixAndStoreDirAndURL($params);
110
111 // also skip all Dir Params, we dont need to store those in the DB!
112 foreach ($params as $name => $val) {
113 if (substr($name, -3) == 'Dir') {
114 unset($params[$name]);
115 }
116 }
117
118 //keep user preferred language upto date, CRM-7746
119 $session = CRM_Core_Session::singleton();
120 $lcMessages = CRM_Utils_Array::value('lcMessages', $params);
121 if ($lcMessages && $session->get('userID')) {
122 $languageLimit = CRM_Utils_Array::value('languageLimit', $params);
123 if (is_array($languageLimit) &&
124 !in_array($lcMessages, array_keys($languageLimit))
125 ) {
126 $lcMessages = $session->get('lcMessages');
127 }
128
129 $ufm = new CRM_Core_DAO_UFMatch();
130 $ufm->contact_id = $session->get('userID');
131 if ($lcMessages && $ufm->find(TRUE)) {
132 $ufm->language = $lcMessages;
133 $ufm->save();
134 $session->set('lcMessages', $lcMessages);
135 $params['lcMessages'] = $lcMessages;
136 }
137 }
138
139 $domain->config_backend = serialize($params);
140 $domain->save();
141 }
142
143 /**
144 * Fix civicrm setting variables
145 *
146 * @param array $params
147 * Associated array of civicrm variables.
148 *
149 * @return null
150 * @static
151 */
152 public static function fixParams(&$params) {
153 // in our old civicrm.settings.php we were using ISO code for country and
154 // province limit, now we have changed it to use ids
155
156 $countryIsoCodes = CRM_Core_PseudoConstant::countryIsoCode();
157
158 $specialArray = array('countryLimit', 'provinceLimit');
159
160 foreach ($params as $key => $value) {
161 if (in_array($key, $specialArray) && is_array($value)) {
162 foreach ($value as $k => $val) {
163 if (!is_numeric($val)) {
164 $params[$key][$k] = array_search($val, $countryIsoCodes);
165 }
166 }
167 }
168 elseif ($key == 'defaultContactCountry') {
169 if (!is_numeric($value)) {
170 $params[$key] = array_search($value, $countryIsoCodes);
171 }
172 }
173 }
174 }
175
176 /**
177 * Format the array containing before inserting in db
178 *
179 * @param array $params
180 * Associated array of civicrm variables(submitted).
181 * @param array $values
182 * Associated array of civicrm variables stored in db.
183 *
184 * @return null
185 * @static
186 */
187 public static function formatParams(&$params, &$values) {
188 if (empty($params) ||
189 !is_array($params)
190 ) {
191 $params = $values;
192 }
193 else {
194 foreach ($params as $key => $val) {
195 if (array_key_exists($key, $values)) {
196 unset($values[$key]);
197 }
198 }
199 $params = array_merge($params, $values);
200 }
201 }
202
203 /**
204 * Retrieve the settings values from db
205 *
206 * @param $defaults
207 *
208 * @return array $defaults
209 * @static
210 */
211 public static function retrieve(&$defaults) {
212 $domain = new CRM_Core_DAO_Domain();
213
214 //we are initializing config, really can't use, CRM-7863
215 $urlVar = 'q';
216 if (defined('CIVICRM_UF') && CIVICRM_UF == 'Joomla') {
217 $urlVar = 'task';
218 }
219
220 if (CRM_Core_Config::isUpgradeMode()) {
221 $domain->selectAdd('config_backend');
222 }
223 elseif (CRM_Utils_Array::value($urlVar, $_GET) == 'admin/modules/list/confirm') {
224 $domain->selectAdd('config_backend', 'locales');
225 }
226 else {
227 $domain->selectAdd('config_backend, locales, locale_custom_strings');
228 }
229
230 $domain->id = CRM_Core_Config::domainID();
231 $domain->find(TRUE);
232 if ($domain->config_backend) {
233 $defaults = unserialize($domain->config_backend);
234 if ($defaults === FALSE || !is_array($defaults)) {
235 $defaults = array();
236 return;
237 }
238
239 $skipVars = self::skipVars();
240 foreach ($skipVars as $skip) {
241 if (array_key_exists($skip, $defaults)) {
242 unset($defaults[$skip]);
243 }
244 }
245
246 // check if there are any locale strings
247 if ($domain->locale_custom_strings) {
248 $defaults['localeCustomStrings'] = unserialize($domain->locale_custom_strings);
249 }
250 else {
251 $defaults['localeCustomStrings'] = NULL;
252 }
253
254 // are we in a multi-language setup?
255 $multiLang = $domain->locales ? TRUE : FALSE;
256
257 // set the current language
258 $lcMessages = NULL;
259
260 $session = CRM_Core_Session::singleton();
261
262 // on multi-lang sites based on request and civicrm_uf_match
263 if ($multiLang) {
264 $lcMessagesRequest = CRM_Utils_Request::retrieve('lcMessages', 'String', $this);
265 $languageLimit = array();
266 if (array_key_exists('languageLimit', $defaults) && is_array($defaults['languageLimit'])) {
267 $languageLimit = $defaults['languageLimit'];
268 }
269
270 if (in_array($lcMessagesRequest, array_keys($languageLimit))) {
271 $lcMessages = $lcMessagesRequest;
272
273 //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache.
274 CRM_Core_BAO_Cache::deleteGroup('navigation');
275 }
276 else {
277 $lcMessagesRequest = NULL;
278 }
279
280 if (!$lcMessagesRequest) {
281 $lcMessagesSession = $session->get('lcMessages');
282 if (in_array($lcMessagesSession, array_keys($languageLimit))) {
283 $lcMessages = $lcMessagesSession;
284 }
285 else {
286 $lcMessagesSession = NULL;
287 }
288 }
289
290 if ($lcMessagesRequest) {
291 $ufm = new CRM_Core_DAO_UFMatch();
292 $ufm->contact_id = $session->get('userID');
293 if ($ufm->find(TRUE)) {
294 $ufm->language = $lcMessages;
295 $ufm->save();
296 }
297 $session->set('lcMessages', $lcMessages);
298 }
299
300 if (!$lcMessages and $session->get('userID')) {
301 $ufm = new CRM_Core_DAO_UFMatch();
302 $ufm->contact_id = $session->get('userID');
303 if ($ufm->find(TRUE) &&
304 in_array($ufm->language, array_keys($languageLimit))
305 ) {
306 $lcMessages = $ufm->language;
307 }
308 $session->set('lcMessages', $lcMessages);
309 }
310 }
311 global $dbLocale;
312
313 // try to inherit the language from the hosting CMS
314 if (!empty($defaults['inheritLocale'])) {
315 // FIXME: On multilanguage installs, CRM_Utils_System::getUFLocale() in many cases returns nothing if $dbLocale is not set
316 $dbLocale = $multiLang ? "_{$defaults['lcMessages']}" : '';
317 $lcMessages = CRM_Utils_System::getUFLocale();
318 if ($domain->locales and !in_array($lcMessages, explode(CRM_Core_DAO::VALUE_SEPARATOR,
319 $domain->locales
320 ))
321 ) {
322 $lcMessages = NULL;
323 }
324 }
325
326 if (empty($lcMessages)) {
327 //CRM-11993 - if a single-lang site, use default
328 $lcMessages = CRM_Utils_Array::value('lcMessages', $defaults);
329 }
330
331 // set suffix for table names - use views if more than one language
332 $dbLocale = $multiLang ? "_{$lcMessages}" : '';
333
334 // FIXME: an ugly hack to fix CRM-4041
335 global $tsLocale;
336 $tsLocale = $lcMessages;
337
338 // FIXME: as bad aplace as any to fix CRM-5428
339 // (to be moved to a sane location along with the above)
340 if (function_exists('mb_internal_encoding')) {
341 mb_internal_encoding('UTF-8');
342 }
343 }
344
345 // dont add if its empty
346 if (!empty($defaults)) {
347 // retrieve directory and url preferences also
348 CRM_Core_BAO_Setting::retrieveDirectoryAndURLPreferences($defaults);
349
350 // Pickup enabled-components from settings table if found.
351 $enableComponents = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components', NULL, array());
352 if (!empty($enableComponents)) {
353 $defaults['enableComponents'] = $enableComponents;
354
355 $components = CRM_Core_Component::getComponents();
356 $enabledComponentIDs = array();
357 foreach ($defaults['enableComponents'] as $name) {
358 $enabledComponentIDs[] = $components[$name]->componentID;
359 }
360 $defaults['enableComponentIDs'] = $enabledComponentIDs;
361 }
362 }
363 }
364
365 /**
366 * @return array
367 */
368 public static function getConfigSettings() {
369 $config = CRM_Core_Config::singleton();
370
371 $url = $dir = $siteName = $siteRoot = NULL;
372 if ($config->userFramework == 'Joomla') {
373 $url = preg_replace(
374 '|administrator/components/com_civicrm/civicrm/|',
375 '',
376 $config->userFrameworkResourceURL
377 );
378
379 // lets use imageUploadDir since we dont mess around with its values
380 // in the config object, lets kep it a bit generic since folks
381 // might have different values etc
382
383 //CRM-15365 - Fix preg_replace to handle backslash for Windows File Paths
384 if (DIRECTORY_SEPARATOR == '\\') {
385 $dir = preg_replace(
386 '|civicrm[/\\\\]templates_c[/\\\\].*$|',
387 '',
388 $config->templateCompileDir
389 );
390 }
391 else {
392 $dir = preg_replace(
393 '|civicrm/templates_c/.*$|',
394 '',
395 $config->templateCompileDir
396 );
397 }
398
399 $siteRoot = preg_replace(
400 '|/media/civicrm/.*$|',
401 '',
402 $config->imageUploadDir
403 );
404 }
405 else if ($config->userFramework == 'WordPress') {
406 $url = preg_replace(
407 '|wp-content/plugins/civicrm/civicrm/|',
408 '',
409 $config->userFrameworkResourceURL
410 );
411
412 // lets use imageUploadDir since we dont mess around with its values
413 // in the config object, lets kep it a bit generic since folks
414 // might have different values etc
415
416 //CRM-15365 - Fix preg_replace to handle backslash for Windows File Paths
417 if (DIRECTORY_SEPARATOR == '\\') {
418 $dir = preg_replace(
419 '|civicrm[/\\\\]templates_c[/\\\\].*$|',
420 '',
421 $config->templateCompileDir
422 );
423 }
424 else {
425 $dir = preg_replace(
426 '|civicrm/templates_c/.*$|',
427 '',
428 $config->templateCompileDir
429 );
430 }
431
432 $siteRoot = preg_replace(
433 '|/wp-content/plugins/files/civicrm/.*$|',
434 '',
435 $config->imageUploadDir
436 );
437 }
438 else {
439 $url = preg_replace(
440 '|sites/[\w\.\-\_]+/modules/civicrm/|',
441 '',
442 $config->userFrameworkResourceURL
443 );
444
445 // lets use imageUploadDir since we dont mess around with its values
446 // in the config object, lets kep it a bit generic since folks
447 // might have different values etc
448
449 //CRM-15365 - Fix preg_replace to handle backslash for Windows File Paths
450 if (DIRECTORY_SEPARATOR == '\\') {
451 $dir = preg_replace(
452 '|[/\\\\]files[/\\\\]civicrm[/\\\\].*$|',
453 '\\\\files\\\\',
454 $config->imageUploadDir
455 );
456 }
457 else {
458 $dir = preg_replace(
459 '|/files/civicrm/.*$|',
460 '/files/',
461 $config->imageUploadDir
462 );
463 }
464
465 $matches = array();
466 if (preg_match(
467 '|/sites/([\w\.\-\_]+)/|',
468 $config->imageUploadDir,
469 $matches
470 )) {
471 $siteName = $matches[1];
472 if ($siteName) {
473 $siteName = "/sites/$siteName/";
474 $siteNamePos = strpos($dir, $siteName);
475 if ($siteNamePos !== FALSE) {
476 $siteRoot = substr($dir, 0, $siteNamePos);
477 }
478 }
479 }
480 }
481
482 return array($url, $dir, $siteName, $siteRoot);
483 }
484
485 /**
486 * Return likely default settings
487 * @return array site settings
488 * -$url,
489 * - $dir Base Directory
490 * - $siteName
491 * - $siteRoot
492 */
493 public static function getBestGuessSettings() {
494 $config = CRM_Core_Config::singleton();
495
496 //CRM-15365 - Fix preg_replace to handle backslash for Windows File Paths
497 if (DIRECTORY_SEPARATOR == '\\') {
498 $needle = 'civicrm[/\\\\]templates_c[/\\\\].*$';
499 }
500 else {
501 $needle = 'civicrm/templates_c/.*$';
502 }
503
504 $dir = preg_replace(
505 "|$needle|",
506 '',
507 $config->templateCompileDir
508 );
509
510 list($url, $siteName, $siteRoot) = $config->userSystem->getDefaultSiteSettings($dir);
511 return array($url, $dir, $siteName, $siteRoot);
512 }
513
514 /**
515 * @param array $defaultValues
516 *
517 * @return string
518 * @throws Exception
519 */
520 public static function doSiteMove($defaultValues = array()) {
521 $moveStatus = ts('Beginning site move process...') . '<br />';
522 // get the current and guessed values
523 list($oldURL, $oldDir, $oldSiteName, $oldSiteRoot) = self::getConfigSettings();
524 list($newURL, $newDir, $newSiteName, $newSiteRoot) = self::getBestGuessSettings();
525
526
527 // retrieve these values from the argument list
528 $variables = array('URL', 'Dir', 'SiteName', 'SiteRoot', 'Val_1', 'Val_2', 'Val_3');
529 $states = array('old', 'new');
530 foreach ($variables as $varSuffix) {
531 foreach ($states as $state) {
532 $var = "{$state}{$varSuffix}";
533 if (!isset($$var)) {
534 if (isset($defaultValues[$var])) {
535 $$var = $defaultValues[$var];
536 }
537 else {
538 $$var = NULL;
539 }
540 }
541 $$var = CRM_Utils_Request::retrieve($var,
542 'String',
543 CRM_Core_DAO::$_nullArray,
544 FALSE,
545 $$var,
546 'REQUEST'
547 );
548 }
549 }
550
551 $from = $to = array();
552 foreach ($variables as $varSuffix) {
553 $oldVar = "old{$varSuffix}";
554 $newVar = "new{$varSuffix}";
555 //skip it if either is empty or both are exactly the same
556 if ($$oldVar &&
557 $$newVar &&
558 $$oldVar != $$newVar
559 ) {
560 $from[] = $$oldVar;
561 $to[] = $$newVar;
562 }
563 }
564
565 $sql = "
566 SELECT config_backend
567 FROM civicrm_domain
568 WHERE id = %1
569 ";
570 $params = array(1 => array(CRM_Core_Config::domainID(), 'Integer'));
571 $configBackend = CRM_Core_DAO::singleValueQuery($sql, $params);
572 if (!$configBackend) {
573 CRM_Core_Error::fatal(ts('Returning early due to unexpected error - civicrm_domain.config_backend column value is NULL. Try visiting CiviCRM Home page.'));
574 }
575 $configBackend = unserialize($configBackend);
576
577 $configBackend = str_replace($from,
578 $to,
579 $configBackend
580 );
581
582 $configBackend = serialize($configBackend);
583 $sql = "
584 UPDATE civicrm_domain
585 SET config_backend = %2
586 WHERE id = %1
587 ";
588 $params[2] = array($configBackend, 'String');
589 CRM_Core_DAO::executeQuery($sql, $params);
590
591 // Apply the changes to civicrm_option_values
592 $optionGroups = array('url_preferences', 'directory_preferences');
593 foreach ($optionGroups as $option) {
594 foreach ($variables as $varSuffix) {
595 $oldVar = "old{$varSuffix}";
596 $newVar = "new{$varSuffix}";
597
598 $from = $$oldVar;
599 $to = $$newVar;
600
601 if ($from && $to && $from != $to) {
602 $sql = '
603 UPDATE civicrm_option_value
604 SET value = REPLACE(value, %1, %2)
605 WHERE option_group_id = (
606 SELECT id
607 FROM civicrm_option_group
608 WHERE name = %3 )
609 ';
610 $params = array(
611 1 => array($from, 'String'),
612 2 => array($to, 'String'),
613 3 => array($option, 'String'),
614 );
615 CRM_Core_DAO::executeQuery($sql, $params);
616 }
617 }
618 }
619
620 $moveStatus .=
621 ts('Directory and Resource URLs have been updated in the moved database to reflect current site location.') .
622 '<br />';
623
624 $config = CRM_Core_Config::singleton();
625
626 // clear the template_c and upload directory also
627 $config->cleanup(3, TRUE);
628 $moveStatus .= ts('Template cache and upload directory have been cleared.') . '<br />';
629
630 // clear all caches
631 CRM_Core_Config::clearDBCache();
632 $moveStatus .= ts('Database cache tables cleared.') . '<br />';
633
634 $resetSessionTable = CRM_Utils_Request::retrieve('resetSessionTable',
635 'Boolean',
636 CRM_Core_DAO::$_nullArray,
637 FALSE,
638 FALSE,
639 'REQUEST'
640 );
641 if ($config->userSystem->is_drupal &&
642 $resetSessionTable
643 ) {
644 db_query("DELETE FROM {sessions} WHERE 1");
645 $moveStatus .= ts('Drupal session table cleared.') . '<br />';
646 }
647 else {
648 $session = CRM_Core_Session::singleton();
649 $session->reset(2);
650 $moveStatus .= ts('Session has been reset.') . '<br />';
651 }
652
653 return $moveStatus;
654 }
655
656 /**
657 * Takes a componentName and enables it in the config
658 * Primarily used during unit testing
659 *
660 * @param string $componentName
661 * Name of the component to be enabled, needs to be valid.
662 *
663 * @return boolean - true if valid component name and enabling succeeds, else false
664 * @static
665 */
666 public static function enableComponent($componentName) {
667 $config = CRM_Core_Config::singleton();
668 if (in_array($componentName, $config->enableComponents)) {
669 // component is already enabled
670 return TRUE;
671 }
672
673 // return if component does not exist
674 if (!array_key_exists($componentName, CRM_Core_Component::getComponents())) {
675 return FALSE;
676 }
677
678 // get enabled-components from DB and add to the list
679 $enabledComponents =
680 CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components', NULL, array());
681 $enabledComponents[] = $componentName;
682
683 self::setEnabledComponents($enabledComponents);
684
685 return TRUE;
686 }
687
688 public static function disableComponent($componentName) {
689 $config = CRM_Core_Config::singleton();
690 if (!in_array($componentName, $config->enableComponents) ||
691 !array_key_exists($componentName, CRM_Core_Component::getComponents())
692 ) {
693 // post-condition satisified
694 return TRUE;
695 }
696
697 // get enabled-components from DB and add to the list
698 $enabledComponents =
699 CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components', NULL, array());
700 $enabledComponents = array_diff($enabledComponents, array($componentName));
701
702 self::setEnabledComponents($enabledComponents);
703
704 return TRUE;
705 }
706
707 public static function setEnabledComponents($enabledComponents) {
708 $config = CRM_Core_Config::singleton();
709 $components = CRM_Core_Component::getComponents();
710
711 $enabledComponentIDs = array();
712 foreach ($enabledComponents as $name) {
713 $enabledComponentIDs[] = $components[$name]->componentID;
714 }
715
716 // fix the config object
717 $config->enableComponents = $enabledComponents;
718 $config->enableComponentIDs = $enabledComponentIDs;
719
720 // also force reset of component array
721 CRM_Core_Component::getEnabledComponents(TRUE);
722
723 // update DB
724 CRM_Core_BAO_Setting::setItem($enabledComponents,
725 CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components');
726 }
727
728 /**
729 * @return array
730 */
731 public static function skipVars() {
732 return array(
733 'dsn',
734 'templateCompileDir',
735 'userFrameworkDSN',
736 'userFramework',
737 'userFrameworkBaseURL',
738 'userFrameworkClass',
739 'userHookClass',
740 'userPermissionClass',
741 'userFrameworkURLVar',
742 'userFrameworkVersion',
743 'newBaseURL',
744 'newBaseDir',
745 'newSiteName',
746 'configAndLogDir',
747 'qfKey',
748 'gettextResourceDir',
749 'cleanURL',
750 'locale_custom_strings',
751 'localeCustomStrings',
752 'autocompleteContactSearch',
753 'autocompleteContactReference',
754 'checksumTimeout',
755 );
756 }
757 }