From 8eb5d071d545707311522cde2a87aff576749c43 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Mon, 14 Sep 2015 17:58:45 -0700 Subject: [PATCH] CRM-16373 - SettingsManager - useMandatory() to apply post-boot changes Note: The global `$civicrm_setting` is meant to provide sysadmins with a way to override settings in `civicrm.settings.php`, but it has traditionally been possible for extensions to manipulate `$civicrm_setting` in a hook. If you do this, please call `useMandatory()` to tell SettingsManager to re-scan `$civicrm_setting`. --- Civi/Core/SettingsManager.php | 105 +++++++++++------- tests/phpunit/CRM/Core/BAO/SettingTest.php | 4 + .../phpunit/Civi/Core/SettingsManagerTest.php | 15 ++- 3 files changed, 84 insertions(+), 40 deletions(-) diff --git a/Civi/Core/SettingsManager.php b/Civi/Core/SettingsManager.php index c150d6aaa1..6b3f18bc56 100644 --- a/Civi/Core/SettingsManager.php +++ b/Civi/Core/SettingsManager.php @@ -51,6 +51,12 @@ namespace Civi\Core; * in some edge-cases, you may need to work with multiple domains/contacts * at the same time. * + * Note: The global $civicrm_setting is meant to provide sysadmins with a way + * to override settings in `civicrm.settings.php`, but it has traditionally been + * possible for extensions to manipulate $civicrm_setting in a hook. If you do + * this, please call `useMandatory()` to tell SettingsManager to re-scan + * $civicrm_setting. + * * @see SettingsManagerTest */ class SettingsManager { @@ -67,9 +73,10 @@ class SettingsManager { protected $bagsByDomain = array(), $bagsByContact = array(); /** - * @var array + * @var array|NULL * Array(string $entity => array(string $settingName => mixed $value)). * Ex: $mandatory['domain']['uploadDir']. + * NULL means "autoload from $civicrm_setting". */ protected $mandatory = NULL; @@ -83,16 +90,13 @@ class SettingsManager { /** * @param \CRM_Utils_Cache_Interface $cache * A semi-durable location to store metadata. - * @param NULL|array $mandatory - * Ex: $mandatory['domain']['uploadDir']. */ - public function __construct($cache, $mandatory = NULL) { + public function __construct($cache) { $this->cache = $cache; - $this->mandatory = $mandatory; } /** - * Ensure that all defaults and mandatory values are included with + * Ensure that all defaults values are included with * all current and future bags. * * @return $this @@ -103,12 +107,14 @@ class SettingsManager { if (!empty($this->bagsByDomain)) { foreach ($this->bagsByDomain as $bag) { + /** @var SettingsBag $bag */ $bag->loadDefaults($this->getDefaults('domain')); } } if (!empty($this->bagsByContact)) { foreach ($this->bagsByContact as $bag) { + /** @var SettingsBag $bag */ $bag->loadDefaults($this->getDefaults('contact')); } } @@ -117,6 +123,31 @@ class SettingsManager { return $this; } + /** + * Ensure that mandatory values are included with + * all current and future bags. + * + * If you call useMandatory multiple times, it will + * re-scan the global $civicrm_setting. + * + * @return $this + */ + public function useMandatory() { + $this->mandatory = NULL; + + foreach ($this->bagsByDomain as $bag) { + /** @var SettingsBag $bag */ + $bag->loadMandatory($this->getMandatory('domain')); + } + + foreach ($this->bagsByContact as $bag) { + /** @var SettingsBag $bag */ + $bag->loadMandatory($this->getMandatory('contact')); + } + + return $this; + } + /** * @param int|NULL $domainId * @return SettingsBag @@ -198,17 +229,10 @@ class SettingsManager { * Array(string $settingName => mixed $value). */ protected function getMandatory($entity) { - // Prepare and cache list of all mandatory settings. if ($this->mandatory === NULL) { - if (isset($GLOBALS['civicrm_setting'])) { - $this->mandatory = self::parseMandatorySettings($GLOBALS['civicrm_setting']); - } - else { - $this->mandatory = array(); - } + $this->mandatory = self::parseMandatorySettings(\CRM_Utils_Array::value('civicrm_setting', $GLOBALS)); } - - return \CRM_Utils_Array::value($entity, $this->mandatory, array()); + return $this->mandatory[$entity]; } /** @@ -230,36 +254,39 @@ class SettingsManager { * @return array */ public static function parseMandatorySettings($civicrm_setting) { + $result = array( + 'domain' => array(), + 'contact' => array(), + ); + $rewriteGroups = array( - \CRM_Core_BAO_Setting::ADDRESS_STANDARDIZATION_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::DEVELOPER_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::DIRECTORY_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::EVENT_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::MAP_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::MEMBER_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME => 'contact', - \CRM_Core_BAO_Setting::SEARCH_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME => 'domain', - \CRM_Core_BAO_Setting::URL_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::ADDRESS_STANDARDIZATION_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::DEVELOPER_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::DIRECTORY_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::EVENT_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::MAP_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::MEMBER_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME => 'contact', + 'Personal Preferences' => 'contact', + //\CRM_Core_BAO_Setting::SEARCH_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME => 'domain', + //\CRM_Core_BAO_Setting::URL_PREFERENCES_NAME => 'domain', + 'domain' => 'domain', + 'contact' => 'contact', ); if (is_array($civicrm_setting)) { - foreach ($rewriteGroups as $oldGroup => $newGroup) { - if (!isset($civicrm_setting[$newGroup])) { - $civicrm_setting[$newGroup] = array(); - } - if (isset($civicrm_setting[$oldGroup])) { - $civicrm_setting[$newGroup] = array_merge($civicrm_setting[$oldGroup], $civicrm_setting[$newGroup]); - unset($civicrm_setting[$oldGroup]); - } + foreach ($civicrm_setting as $oldGroup => $values) { + $newGroup = isset($rewriteGroups[$oldGroup]) ? $rewriteGroups[$oldGroup] : 'domain'; + $result[$newGroup] = array_merge($result[$newGroup], $values); } } - return $civicrm_setting; + return $result; } } diff --git a/tests/phpunit/CRM/Core/BAO/SettingTest.php b/tests/phpunit/CRM/Core/BAO/SettingTest.php index 87a1cee59e..8cf695c334 100644 --- a/tests/phpunit/CRM/Core/BAO/SettingTest.php +++ b/tests/phpunit/CRM/Core/BAO/SettingTest.php @@ -78,11 +78,13 @@ class CRM_Core_BAO_SettingTest extends CiviUnitTestCase { public function testGetItem_Override() { global $civicrm_setting; $civicrm_setting[CRM_Core_BAO_Setting::DIRECTORY_PREFERENCES_NAME]['imageUploadDir'] = '/test/override'; + Civi::service('settings_manager')->useMandatory(); $value = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::DIRECTORY_PREFERENCES_NAME, 'imageUploadDir'); $this->assertEquals('/test/override', $value); // CRM-14974 test suite $civicrm_setting['Test Preferences']['overrideSetting'] = '/test/override'; + Civi::service('settings_manager')->useMandatory(); $values = CRM_Core_BAO_Setting::getItem('Test Preferences'); $this->assertEquals('/test/override', $values['overrideSetting']); CRM_Core_BAO_Setting::setItem('/test/database', 'Test Preferences', 'databaseSetting'); @@ -90,6 +92,7 @@ class CRM_Core_BAO_SettingTest extends CiviUnitTestCase { $this->assertEquals('/test/override', $values['overrideSetting']); $this->assertEquals('/test/database', $values['databaseSetting']); $civicrm_setting['Test Preferences']['databaseSetting'] = '/test/dataride'; + Civi::service('settings_manager')->useMandatory(); $values = CRM_Core_BAO_Setting::getItem('Test Preferences'); $this->assertEquals('/test/override', $values['overrideSetting']); $this->assertEquals('/test/dataride', $values['databaseSetting']); @@ -106,6 +109,7 @@ class CRM_Core_BAO_SettingTest extends CiviUnitTestCase { public function testGetItemGroup_Override() { global $civicrm_setting; $civicrm_setting[CRM_Core_BAO_Setting::DIRECTORY_PREFERENCES_NAME]['imageUploadDir'] = '/test/override'; + Civi::service('settings_manager')->useMandatory(); $values = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::DIRECTORY_PREFERENCES_NAME); $this->assertEquals('/test/override', $values['imageUploadDir']); } diff --git a/tests/phpunit/Civi/Core/SettingsManagerTest.php b/tests/phpunit/Civi/Core/SettingsManagerTest.php index dfeec81b09..c117b8c4e8 100644 --- a/tests/phpunit/Civi/Core/SettingsManagerTest.php +++ b/tests/phpunit/Civi/Core/SettingsManagerTest.php @@ -8,8 +8,11 @@ class SettingsManagerTest extends \CiviUnitTestCase { protected $domainDefaults; protected $contactDefaults; protected $mandates; + protected $origSetting; protected function setUp() { + $this->origSetting = $GLOBALS['civicrm_setting']; + parent::setUp(); $this->useTransaction(TRUE); @@ -37,6 +40,11 @@ class SettingsManagerTest extends \CiviUnitTestCase { ); } + public function tearDown() { + $GLOBALS['civicrm_setting'] = $this->origSetting; + parent::tearDown(); + } + /** * Test mingled reads/writes of settings for two different domains. */ @@ -166,7 +174,12 @@ class SettingsManagerTest extends \CiviUnitTestCase { $cache = new \CRM_Utils_Cache_Arraycache(array()); $cache->set('defaults:domain', $this->domainDefaults); $cache->set('defaults:contact', $this->contactDefaults); - $manager = new SettingsManager($cache, SettingsManager::parseMandatorySettings($this->mandates)); + foreach ($this->mandates as $entity => $keyValues) { + foreach ($keyValues as $k => $v) { + $GLOBALS['civicrm_setting'][$entity][$k] = $v; + } + } + $manager = new SettingsManager($cache); return $manager; } -- 2.25.1