From 8f2a141a09e91f680ecd1f0a7d0a61777a2d2586 Mon Sep 17 00:00:00 2001
From: Tim Otten <totten@civicrm.org>
Date: Tue, 28 Apr 2020 14:14:45 -0700
Subject: [PATCH] (REF) dev/core#1724 - SettingsBag - Convert to
 computeVirtual/updateVirtual

The `SettingsBag` uses the `$combined` property to (locally) cache a full
view of the active settings (based on combining different layers of data --
default-values, explicit-values, and mandatory-values). This design is
good for read-mostly data.

This patch changes the `__ContributionSettings` to be another layer in the
construction of `$combined` -- the virtual-values layer.  It fixes issues
wherein:

1. The virtual value is recomputed during every call to `get($key)`.

2. The virtual value is only based on explicit-values -- it disregards
   default-values and mandatory-values.
---
 Civi/Core/SettingsBag.php | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/Civi/Core/SettingsBag.php b/Civi/Core/SettingsBag.php
index ca79d860366..3435fd3114f 100644
--- a/Civi/Core/SettingsBag.php
+++ b/Civi/Core/SettingsBag.php
@@ -136,7 +136,6 @@ class SettingsBag {
       while ($dao->fetch()) {
         $this->values[$dao->name] = ($dao->value !== NULL) ? \CRM_Utils_String::unserialize($dao->value) : NULL;
       }
-      $dao->values['contribution_invoice_settings'] = $this->getContributionSettings();
     }
 
     return $this;
@@ -167,8 +166,11 @@ class SettingsBag {
       $this->combined = $this->combine(
         [$this->defaults, $this->values, $this->mandatory]
       );
+      // computeVirtual() depends on completion of preceding pass.
+      $this->combined = $this->combine(
+        [$this->combined, $this->computeVirtual()]
+      );
     }
-    $this->combined['contribution_invoice_settings'] = $this->getContributionSettings();
     return $this->combined;
   }
 
@@ -255,8 +257,7 @@ class SettingsBag {
    * @return SettingsBag
    */
   public function set($key, $value) {
-    if ($key === 'contribution_invoice_settings') {
-      $this->setContributionSettings($value);
+    if ($this->updateVirtual($key, $value)) {
       return $this;
     }
     $this->setDb($key, $value);
@@ -266,6 +267,8 @@ class SettingsBag {
   }
 
   /**
+   * Update a virtualized/deprecated setting.
+   *
    * Temporary handling for phasing out contribution_invoice_settings.
    *
    * Until we have transitioned we need to handle setting & retrieving
@@ -275,29 +278,33 @@ class SettingsBag {
    *
    * https://lab.civicrm.org/dev/core/issues/1558
    *
+   * @param string $key
    * @param array $value
+   * @return bool
+   *   TRUE if $key is a virtualized setting. FALSE if it is a normal setting.
    */
-  public function setContributionSettings($value) {
-    foreach (SettingsBag::getContributionInvoiceSettingKeys() as $possibleKeyName => $settingName) {
-      $keyValue = $value[$possibleKeyName] ?? '';
-      $this->set($settingName, $keyValue);
+  public function updateVirtual($key, $value) {
+    if ($key === 'contribution_invoice_settings') {
+      foreach (SettingsBag::getContributionInvoiceSettingKeys() as $possibleKeyName => $settingName) {
+        $keyValue = $value[$possibleKeyName] ?? '';
+        $this->set($settingName, $keyValue);
+      }
+      return TRUE;
     }
-    $this->values['contribution_invoice_settings'] = $this->getContributionSettings();
+    return FALSE;
   }
 
   /**
-   * Temporary function to handle returning the contribution_settings key despite it being deprecated.
-   *
-   * See more in comment block on previous function.
+   * Determine the values of any virtual/computed settings.
    *
    * @return array
    */
-  public function getContributionSettings() {
+  public function computeVirtual() {
     $contributionSettings = [];
     foreach (SettingsBag::getContributionInvoiceSettingKeys() as $keyName => $settingName) {
-      $contributionSettings[$keyName] = $this->values[$settingName] ?? '';
+      $contributionSettings[$keyName] = $this->get($settingName);
     }
-    return $contributionSettings;
+    return ['contribution_invoice_settings' => $contributionSettings];
   }
 
   /**
-- 
GitLab