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