Merge remote-tracking branch 'upstream/4.4' into 4.4-master-2014-06-01-20-54-24
[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 $lcMessages = NULL;
323 }
324 }
325
326 if ($lcMessages) {
327 // update config lcMessages - CRM-5027 fixed.
328 $defaults['lcMessages'] = $lcMessages;
329 }
330 else {
331 // if a single-lang site or the above didn't yield a result, use default
332 $lcMessages = CRM_Utils_Array::value( 'lcMessages', $defaults );
333 }
334
335 // set suffix for table names - use views if more than one language
336 $dbLocale = $multiLang ? "_{$lcMessages}" : '';
337
338 // FIXME: an ugly hack to fix CRM-4041
339 global $tsLocale;
340 $tsLocale = $lcMessages;
341
342 // FIXME: as bad aplace as any to fix CRM-5428
343 // (to be moved to a sane location along with the above)
344 if (function_exists('mb_internal_encoding')) {
345 mb_internal_encoding('UTF-8');
346 }
347 }
348
349 // dont add if its empty
350 if (!empty($defaults)) {
351 // retrieve directory and url preferences also
352 CRM_Core_BAO_Setting::retrieveDirectoryAndURLPreferences($defaults);
353
354 // Pickup enabled-components from settings table if found.
355 $enableComponents = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components', NULL, array());
356 if (!empty($enableComponents)) {
357 $defaults['enableComponents'] = $enableComponents;
358
359 $components = CRM_Core_Component::getComponents();
360 $enabledComponentIDs = array();
361 foreach ($defaults['enableComponents'] as $name) {
362 $enabledComponentIDs[] = $components[$name]->componentID;
363 }
364 $defaults['enableComponentIDs'] = $enabledComponentIDs;
365 }
366 }
367 }
368
369 /**
370 * @return array
371 */
372 static function getConfigSettings() {
373 $config = CRM_Core_Config::singleton();
374
375 $url = $dir = $siteName = $siteRoot = NULL;
376 if ($config->userFramework == 'Joomla') {
377 $url = preg_replace(
378 '|administrator/components/com_civicrm/civicrm/|',
379 '',
380 $config->userFrameworkResourceURL
381 );
382
383 // lets use imageUploadDir since we dont mess around with its values
384 // in the config object, lets kep it a bit generic since folks
385 // might have different values etc
386 $dir = preg_replace(
387 '|civicrm/templates_c/.*$|',
388 '',
389 $config->templateCompileDir
390 );
391 $siteRoot = preg_replace(
392 '|/media/civicrm/.*$|',
393 '',
394 $config->imageUploadDir
395 );
396 }
397 else if ($config->userFramework == 'WordPress') {
398 $url = preg_replace(
399 '|wp-content/plugins/civicrm/civicrm/|',
400 '',
401 $config->userFrameworkResourceURL
402 );
403
404 // lets use imageUploadDir since we dont mess around with its values
405 // in the config object, lets kep it a bit generic since folks
406 // might have different values etc
407 $dir = preg_replace(
408 '|civicrm/templates_c/.*$|',
409 '',
410 $config->templateCompileDir
411 );
412 $siteRoot = preg_replace(
413 '|/wp-content/plugins/files/civicrm/.*$|',
414 '',
415 $config->imageUploadDir
416 );
417 }
418 else {
419 $url = preg_replace(
420 '|sites/[\w\.\-\_]+/modules/civicrm/|',
421 '',
422 $config->userFrameworkResourceURL
423 );
424
425 // lets use imageUploadDir since we dont mess around with its values
426 // in the config object, lets kep it a bit generic since folks
427 // might have different values etc
428 $dir = preg_replace(
429 '|/files/civicrm/.*$|',
430 '/files/',
431 $config->imageUploadDir
432 );
433
434 $matches = array();
435 if (preg_match(
436 '|/sites/([\w\.\-\_]+)/|',
437 $config->imageUploadDir,
438 $matches
439 )) {
440 $siteName = $matches[1];
441 if ($siteName) {
442 $siteName = "/sites/$siteName/";
443 $siteNamePos = strpos($dir, $siteName);
444 if ($siteNamePos !== FALSE) {
445 $siteRoot = substr($dir, 0, $siteNamePos);
446 }
447 }
448 }
449 }
450
451
452 return array($url, $dir, $siteName, $siteRoot);
453 }
454
455 /**
456 * Return likely default settings
457 * @return array site settings
458 * -$url,
459 * - $dir Base Directory
460 * - $siteName
461 * - $siteRoot
462 */
463 static function getBestGuessSettings() {
464 $config = CRM_Core_Config::singleton();
465 $dir = preg_replace(
466 '|civicrm/templates_c/.*$|',
467 '',
468 $config->templateCompileDir
469 );
470
471 list($url, $siteName, $siteRoot) = $config->userSystem->getDefaultSiteSettings($dir);
472 return array($url, $dir, $siteName, $siteRoot);
473 }
474
475 /**
476 * @param array $defaultValues
477 *
478 * @return string
479 * @throws Exception
480 */
481 static function doSiteMove($defaultValues = array() ) {
482 $moveStatus = ts('Beginning site move process...') . '<br />';
483 // get the current and guessed values
484 list($oldURL, $oldDir, $oldSiteName, $oldSiteRoot) = self::getConfigSettings();
485 list($newURL, $newDir, $newSiteName, $newSiteRoot) = self::getBestGuessSettings();
486
487
488 // retrieve these values from the argument list
489 $variables = array('URL', 'Dir', 'SiteName', 'SiteRoot', 'Val_1', 'Val_2', 'Val_3');
490 $states = array('old', 'new');
491 foreach ($variables as $varSuffix) {
492 foreach ($states as $state) {
493 $var = "{$state}{$varSuffix}";
494 if (!isset($$var)) {
495 if (isset($defaultValues[$var])) {
496 $$var = $defaultValues[$var];
497 }
498 else {
499 $$var = NULL;
500 }
501 }
502 $$var = CRM_Utils_Request::retrieve($var,
503 'String',
504 CRM_Core_DAO::$_nullArray,
505 FALSE,
506 $$var,
507 'REQUEST'
508 );
509 }
510 }
511
512 $from = $to = array();
513 foreach ($variables as $varSuffix) {
514 $oldVar = "old{$varSuffix}";
515 $newVar = "new{$varSuffix}";
516 //skip it if either is empty or both are exactly the same
517 if ($$oldVar &&
518 $$newVar &&
519 $$oldVar != $$newVar
520 ) {
521 $from[] = $$oldVar;
522 $to[] = $$newVar;
523 }
524 }
525
526 $sql = "
527 SELECT config_backend
528 FROM civicrm_domain
529 WHERE id = %1
530 ";
531 $params = array(1 => array(CRM_Core_Config::domainID(), 'Integer'));
532 $configBackend = CRM_Core_DAO::singleValueQuery($sql, $params);
533 if (!$configBackend) {
534 CRM_Core_Error::fatal(ts('Returning early due to unexpected error - civicrm_domain.config_backend column value is NULL. Try visiting CiviCRM Home page.'));
535 }
536 $configBackend = unserialize($configBackend);
537
538 $configBackend = str_replace($from,
539 $to,
540 $configBackend
541 );
542
543 $configBackend = serialize($configBackend);
544 $sql = "
545 UPDATE civicrm_domain
546 SET config_backend = %2
547 WHERE id = %1
548 ";
549 $params[2] = array($configBackend, 'String');
550 CRM_Core_DAO::executeQuery($sql, $params);
551
552 // Apply the changes to civicrm_option_values
553 $optionGroups = array('url_preferences', 'directory_preferences');
554 foreach ($optionGroups as $option) {
555 foreach ($variables as $varSuffix) {
556 $oldVar = "old{$varSuffix}";
557 $newVar = "new{$varSuffix}";
558
559 $from = $$oldVar;
560 $to = $$newVar;
561
562 if ($from && $to && $from != $to) {
563 $sql = '
564 UPDATE civicrm_option_value
565 SET value = REPLACE(value, %1, %2)
566 WHERE option_group_id = (
567 SELECT id
568 FROM civicrm_option_group
569 WHERE name = %3 )
570 ';
571 $params = array(1 => array($from, 'String'),
572 2 => array($to, 'String'),
573 3 => array($option, 'String'),
574 );
575 CRM_Core_DAO::executeQuery($sql, $params);
576 }
577 }
578 }
579
580 $moveStatus .= ts('Directory and Resource URLs have been updated in the moved database to reflect current site location.') . '<br />';
581
582 $config = CRM_Core_Config::singleton();
583
584 // clear the template_c and upload directory also
585 $config->cleanup(3, TRUE);
586 $moveStatus .= ts('Template cache and upload directory have been cleared.') . '<br />';
587
588 // clear all caches
589 CRM_Core_Config::clearDBCache();
590 $moveStatus .= ts('Database cache tables cleared.') . '<br />';
591
592 $resetSessionTable = CRM_Utils_Request::retrieve('resetSessionTable',
593 'Boolean',
594 CRM_Core_DAO::$_nullArray,
595 FALSE,
596 FALSE,
597 'REQUEST'
598 );
599 if ($config->userSystem->is_drupal &&
600 $resetSessionTable
601 ) {
602 db_query("DELETE FROM {sessions} WHERE 1");
603 $moveStatus .= ts('Drupal session table cleared.') . '<br />';
604 }
605 else {
606 $session = CRM_Core_Session::singleton();
607 $session->reset(2);
608 $moveStatus .= ts('Session has been reset.') . '<br />';
609 }
610
611 return $moveStatus;
612 }
613
614 /**
615 * takes a componentName and enables it in the config
616 * Primarily used during unit testing
617 *
618 * @param string $componentName name of the component to be enabled, needs to be valid
619 *
620 * @return boolean - true if valid component name and enabling succeeds, else false
621 * @static
622 */
623 static function enableComponent($componentName) {
624 $config = CRM_Core_Config::singleton();
625 if (in_array($componentName, $config->enableComponents)) {
626 // component is already enabled
627 return TRUE;
628 }
629 $components = CRM_Core_Component::getComponents();
630
631 // return if component does not exist
632 if (!array_key_exists($componentName, $components)) {
633 return FALSE;
634 }
635
636 // get enabled-components from DB and add to the list
637 $enabledComponents =
638 CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enable_components', NULL, array());
639 $enabledComponents[] = $componentName;
640
641 $enabledComponentIDs = array();
642 foreach ($enabledComponents as $name) {
643 $enabledComponentIDs[] = $components[$name]->componentID;
644 }
645
646 // fix the config object
647 $config->enableComponents = $enabledComponents;
648 $config->enableComponentIDs = $enabledComponentIDs;
649
650 // also force reset of component array
651 CRM_Core_Component::getEnabledComponents(TRUE);
652
653 // update DB
654 CRM_Core_BAO_Setting::setItem($enabledComponents,
655 CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,'enable_components');
656
657 return TRUE;
658 }
659
660 /**
661 * @return array
662 */
663 static function skipVars() {
664 return array(
665 'dsn', 'templateCompileDir',
666 'userFrameworkDSN',
667 'userFramework',
668 'userFrameworkBaseURL', 'userFrameworkClass', 'userHookClass',
669 'userPermissionClass', 'userFrameworkURLVar', 'userFrameworkVersion',
670 'newBaseURL', 'newBaseDir', 'newSiteName', 'configAndLogDir',
671 'qfKey', 'gettextResourceDir', 'cleanURL',
672 'locale_custom_strings', 'localeCustomStrings',
673 'autocompleteContactSearch',
674 'autocompleteContactReference',
675 'checksumTimeout',
676 );
677 }
678 }
679