* 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)) {
}
$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);
}
/**
* Helper fn for addSettingsFactory.
*/
- public function getSettings() {
- return $this->getSettingRegion()->getSettings();
+ public function getSettings($region = NULL) {
+ return $this->getSettingRegion($region)->getSettings();
}
/**