diff --git a/Civi/Angular/AngularLoader.php b/Civi/Angular/AngularLoader.php index 1dca6bcd9e1d..be80912a623b 100644 --- a/Civi/Angular/AngularLoader.php +++ b/Civi/Angular/AngularLoader.php @@ -115,8 +115,13 @@ public function load() { } $res->addSettingsFactory(function () use (&$moduleNames, $angular, $res, $assetParams) { + // Merge static settings with the results of settingsFactory functions + $settingsByModule = $angular->getResources($moduleNames, 'settings', 'settings'); + foreach ($angular->getResources($moduleNames, 'settingsFactory', 'settingsFactory') as $moduleName => $factory) { + $settingsByModule[$moduleName] = array_merge($settingsByModule[$moduleName] ?? [], $factory()); + } // TODO optimization; client-side caching - $result = array_merge($angular->getResources($moduleNames, 'settings', 'settings'), [ + return array_merge($settingsByModule, [ 'resourceUrls' => \CRM_Extension_System::singleton()->getMapper()->getActiveModuleUrls(), 'angular' => [ 'modules' => $moduleNames, @@ -125,7 +130,6 @@ public function load() { 'bundleUrl' => \Civi::service('asset_builder')->getUrl('angular-modules.json', $assetParams), ], ]); - return $result; }); $res->addScriptFile('civicrm', 'bower_components/angular/angular.min.js', 100, $this->getRegion(), FALSE); diff --git a/Civi/Angular/Manager.php b/Civi/Angular/Manager.php index a763cf9e716d..51c3ad2205ac 100644 --- a/Civi/Angular/Manager.php +++ b/Civi/Angular/Manager.php @@ -397,6 +397,7 @@ public function getResources($moduleNames, $resType, $refType) { break; case 'settings': + case 'settingsFactory': case 'requires': if (!empty($module[$resType])) { $result[$moduleName] = $module[$resType]; diff --git a/tests/phpunit/Civi/Angular/LoaderTest.php b/tests/phpunit/Civi/Angular/LoaderTest.php new file mode 100644 index 000000000000..af8c28c2a2f3 --- /dev/null +++ b/tests/phpunit/Civi/Angular/LoaderTest.php @@ -0,0 +1,91 @@ +hookClass->setHook('civicrm_angularModules', [$this, 'hook_angularModules']); + self::$dummy_setting_count = 0; + self::$dummy_callback_count = 0; + $this->createLoggedInUser(); + } + + public function factoryScenarios() { + return [ + ['dummy1', 2, 1], + ['dummy2', 2, 0], + ['dummy3', 2, 2], + ]; + } + + /** + * Tests that AngularLoader only conditionally loads settings via factory functions for in-use modules. + * Our dummy settings callback functions keep a count of the number of times they have been called. + * + * @dataProvider factoryScenarios + * @param $module + * @param $expectedSettingCount + * @param $expectedCallbackCount + */ + public function testSettingFactory($module, $expectedSettingCount, $expectedCallbackCount) { + (new \Civi\Angular\AngularLoader()) + ->setModules([$module]) + ->useApp() + ->load(); + + // Run factory callbacks + $factorySettings = \Civi::resources()->getSettings(); + + // Dummy1 module's factory setting should be set if it is loaded directly or required by dummy3 + $this->assertTrue(($expectedCallbackCount > 0) === isset($factorySettings['dummy1']['dummy_setting_factory'])); + // Dummy3 module's factory setting should be set if it is loaded directly + $this->assertTrue(($expectedCallbackCount > 1) === isset($factorySettings['dummy3']['dummy_setting_factory'])); + + // Assert the callback functions ran the expected number of times + $this->assertEquals($expectedSettingCount, self::$dummy_setting_count); + $this->assertEquals($expectedCallbackCount, self::$dummy_callback_count); + } + + public function hook_angularModules(&$modules) { + $modules['dummy1'] = [ + 'ext' => 'civicrm', + 'settings' => $this->getDummySetting(), + 'settingsFactory' => [self::class, 'getDummySettingFactory'], + ]; + $modules['dummy2'] = [ + 'ext' => 'civicrm', + 'settings' => $this->getDummySetting(), + ]; + $modules['dummy3'] = [ + 'ext' => 'civicrm', + 'settingsFactory' => [self::class, 'getDummySettingFactory'], + 'requires' => ['dummy1'], + ]; + } + + public function getDummySetting() { + return ['dummy_setting' => self::$dummy_setting_count++]; + } + + public static function getDummySettingFactory() { + return ['dummy_setting_factory' => self::$dummy_callback_count++]; + } + +}