CRM-16373 - SettingsManager - useMandatory() to apply post-boot changes
authorTim Otten <totten@civicrm.org>
Tue, 15 Sep 2015 00:58:45 +0000 (17:58 -0700)
committerTim Otten <totten@civicrm.org>
Thu, 17 Sep 2015 22:49:31 +0000 (15:49 -0700)
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
tests/phpunit/CRM/Core/BAO/SettingTest.php
tests/phpunit/Civi/Core/SettingsManagerTest.php

index c150d6aaa16c4b11d7950cd9b41a0cd031f46d4e..6b3f18bc56698c989bf6dc3e81467c947705fda0 100644 (file)
@@ -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;
   }
 
 }
index 87a1cee59e222d181345661c4424710383620062..8cf695c3341c117ec60d4dacc4cc83bd4ae83751 100644 (file)
@@ -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']);
   }
index dfeec81b09db2eb72124363df018f8a2744bb4c6..c117b8c4e840289f3e8cae888cab52b561e1b7a7 100644 (file)
@@ -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;
   }