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