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