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