Annotate DAO files with COMPONENT, exclude disabled components' entities from APIv4...
[civicrm-core.git] / CRM / Core / Resources.php
index 5b7765a33a6c1c2d4bab98040310da4ef547462f..77467b61203eeba218c6dc50c47bb17eaaec6e1a 100644 (file)
@@ -177,16 +177,37 @@ class CRM_Core_Resources implements CRM_Core_Resources_CollectionAdderInterface
    * Assimilate all the resources listed in a bundle.
    *
    * @param iterable|string|\CRM_Core_Resources_Bundle $bundle
-   *   Either bundle object, or the symbolic name of a bundle, or a list of budnles.
+   *   Either bundle object, or the symbolic name of a bundle, or a list of bundles.
    *   Note: For symbolic names, the bundle must be a container service ('bundle.FOO').
    * @return static
    */
   public function addBundle($bundle) {
+    // There are two ways you might write this method: (1) immediately merge
+    // resources from the bundle, or (2) store a reference to the bundle and
+    // merge resources later. Both have pros/cons. The implementation does #1.
+    //
+    // The upshot of #1 is *multi-region* support. For example, a bundle might
+    // add some JS to `html-header` and then add some HTML to `page-header`.
+    // Implementing this requires splitting the bundle (ie copying specific
+    // resources to their respective regions). The timing of `addBundle()` is
+    // favorable to splitting.
+    //
+    // The upshot of #2 would be *reduced timing sensitivity for downstream*:
+    // if party A wants to include some bundle, and party B wants to refine
+    // the same bundle, then it wouldn't matter if A or B executed first.
+    // This should make DX generally more forgiving. But we can't split until
+    // everyone has their shot at tweaking the bundle.
+    //
+    // In theory, you could have both characteristics if you figure the right
+    // time at which to perform a split. Or maybe you could have both by tracking
+    // more detailed references+events among the bundles/regions. I haven't
+    // seen a simple way to do get both.
+
     if (is_iterable($bundle)) {
       foreach ($bundle as $b) {
         $this->addBundle($b);
-        return $this;
       }
+      return $this;
     }
 
     if (is_string($bundle)) {
@@ -198,23 +219,17 @@ class CRM_Core_Resources implements CRM_Core_Resources_CollectionAdderInterface
     }
     $this->addedBundles[$bundle->name] = TRUE;
 
-    // If an item is already assigned to a region, we'll respect that.
-    // Otherwise, we'll use defaults.
-    $pickRegion = function ($snippet) {
-      if (isset($snippet['settings'])) {
-        return $this->getSettingRegion($snippet['region'] ?? NULL)->_name;
-      }
-      else {
-        return $snippet['region'] ?? self::DEFAULT_REGION;
+    // Ensure that every asset has a region.
+    $bundle->filter(function($snippet) {
+      if (empty($snippet['region'])) {
+        $snippet['region'] = isset($snippet['settings'])
+          ? $this->getSettingRegion()->_name
+          : self::DEFAULT_REGION;
       }
-    };
-
-    $byRegion = [];
-    foreach ($bundle->getAll() as $snippet) {
-      $snippet['region'] = $pickRegion($snippet);
-      $byRegion[$snippet['region']][$snippet['name']] = $snippet;
-    }
+      return $snippet;
+    });
 
+    $byRegion = CRM_Utils_Array::index(['region', 'name'], $bundle->getAll());
     foreach ($byRegion as $regionName => $snippets) {
       CRM_Core_Region::instance($regionName)->merge($snippets);
     }
@@ -224,8 +239,8 @@ class CRM_Core_Resources implements CRM_Core_Resources_CollectionAdderInterface
   /**
    * Helper fn for addSettingsFactory.
    */
-  public function getSettings() {
-    return $this->getSettingRegion()->getSettings();
+  public function getSettings($region = NULL) {
+    return $this->getSettingRegion($region)->getSettings();
   }
 
   /**