From 5b17d0d92529fcf2a2e731d60c2672096177c3d6 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 24 Aug 2023 16:48:53 -0700 Subject: [PATCH] hook_civicrm_config - Add parameter ($flags) to distinguish multiple calls --- CRM/Core/Config.php | 5 ++- CRM/Utils/Hook.php | 40 ++++++++++++++++++++--- CRM/Utils/System/Backdrop.php | 2 +- CRM/Utils/System/Drupal.php | 2 +- CRM/Utils/System/Drupal8.php | 2 +- CRM/Utils/System/Joomla.php | 2 +- tests/events/hook_civicrm_config.evch.php | 31 ++++++++++++++++++ 7 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 tests/events/hook_civicrm_config.evch.php diff --git a/CRM/Core/Config.php b/CRM/Core/Config.php index 66e59e4264..6a9dc2cb86 100644 --- a/CRM/Core/Config.php +++ b/CRM/Core/Config.php @@ -91,7 +91,10 @@ class CRM_Core_Config extends CRM_Core_Config_MagicMerge { unset($errorScope); - CRM_Utils_Hook::config(self::$_singleton); + CRM_Utils_Hook::config(self::$_singleton, [ + 'civicrm' => TRUE, + 'uf' => self::$_singleton->userSystem->isLoaded(), + ]); self::$_singleton->authenticate(); // Extreme backward compat: $config binds to active domain at moment of setup. diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index d3b4417f60..a082dc5c05 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -1425,18 +1425,48 @@ abstract class CRM_Utils_Hook { } /** - * This hook is called soon after the CRM_Core_Config object has ben initialized. * You can use this hook to modify the config object and hence behavior of CiviCRM dynamically. * - * @param CRM_Core_Config|array $config + * In *typical* page-loads, this hook fires one time. However, the hook may fire multiple times if... + * + * - the process is executing test-suites, or + * - the process involves some special configuration-changes, or + * - the process begins with the "extern" bootstrap process (aka `loadBootStrap()`) + * N.B. For "extern", CiviCRM initially boots without having access to the UF APIs. + * When the UF eventually boots, it may re-fire the event (for the benefit UF add-ons). + * + * The possibility of multiple invocations means that most consumers should be guarded. + * When registering resources, consult the `$flags`. + * + * function hook_civicrm_config($config, $flags = NULL) { + * if ($flags['...']) { + * Civi::dispatcher()->addListener(...); + * CRM_Core_Smarty::singleton()->addTemplateDir(...); + * } + * } + * + * @param CRM_Core_Config $config * The config object + * @param array|NULL $flags + * Mix of flags: + * - civicrm: TRUE if this invocation is intended for CiviCRM extensions + * - uf: TRUE if this invocation is intended for UF modules (Drupal/Joomla/etc) + * - instances: The number of distinct copies of `CRM_Core_Config` which have been initialized. + * + * The value of `$flags` is NULL when executing on an older CiviCRM environments (<=5.65). * * @return mixed */ - public static function config(&$config) { + public static function config(&$config, ?array $flags = NULL) { + static $count = 0; + if (!empty($flags['civicrm'])) { + $count++; + } + $defaultFlags = ['civicrm' => FALSE, 'uf' => FALSE, 'instances' => $count]; + $flags = array_merge($defaultFlags, $flags); $null = NULL; - return self::singleton()->invoke(['config'], $config, - $null, $null, $null, $null, $null, + return self::singleton()->invoke(['config', 'flags'], $config, + $flags, $null, $null, $null, $null, 'civicrm_config' ); } diff --git a/CRM/Utils/System/Backdrop.php b/CRM/Utils/System/Backdrop.php index 2fd767141f..7376977849 100644 --- a/CRM/Utils/System/Backdrop.php +++ b/CRM/Utils/System/Backdrop.php @@ -596,7 +596,7 @@ AND u.status = 1 // all the modules that are listening on it, does not apply // to J! and WP as yet // CRM-8655 - CRM_Utils_Hook::config($config); + CRM_Utils_Hook::config($config, ['uf' => TRUE]); if (!$loadUser) { return TRUE; diff --git a/CRM/Utils/System/Drupal.php b/CRM/Utils/System/Drupal.php index 832f2da52b..c2ee73e305 100644 --- a/CRM/Utils/System/Drupal.php +++ b/CRM/Utils/System/Drupal.php @@ -513,7 +513,7 @@ AND u.status = 1 // all the modules that are listening on it, does not apply // to J! and WP as yet // CRM-8655 - CRM_Utils_Hook::config($config); + CRM_Utils_Hook::config($config, ['uf' => TRUE]); if (!$loadUser) { return TRUE; diff --git a/CRM/Utils/System/Drupal8.php b/CRM/Utils/System/Drupal8.php index af6821e182..760de128c2 100644 --- a/CRM/Utils/System/Drupal8.php +++ b/CRM/Utils/System/Drupal8.php @@ -433,7 +433,7 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase { // We need to call the config hook again, since we now know // all the modules that are listening on it (CRM-8655). $config = CRM_Core_Config::singleton(); - CRM_Utils_Hook::config($config); + CRM_Utils_Hook::config($config, ['uf' => TRUE]); if ($loadUser) { if (!empty($params['uid']) && $username = \Drupal\user\Entity\User::load($params['uid'])->getAccountName()) { diff --git a/CRM/Utils/System/Joomla.php b/CRM/Utils/System/Joomla.php index 539428cbba..b7f92257fc 100644 --- a/CRM/Utils/System/Joomla.php +++ b/CRM/Utils/System/Joomla.php @@ -680,7 +680,7 @@ class CRM_Utils_System_Joomla extends CRM_Utils_System_Base { // CRM-14281 Joomla wasn't available during bootstrap, so hook_civicrm_config never executes. $config = CRM_Core_Config::singleton(); - CRM_Utils_Hook::config($config); + CRM_Utils_Hook::config($config, ['uf' => TRUE]); return TRUE; } diff --git a/tests/events/hook_civicrm_config.evch.php b/tests/events/hook_civicrm_config.evch.php new file mode 100644 index 0000000000..356e48b59d --- /dev/null +++ b/tests/events/hook_civicrm_config.evch.php @@ -0,0 +1,31 @@ +assertType('CRM_Core_Config', $config, "$msg: Bad config object"); + $this->assertType('array', $flags, "$msg: Bad flags array"); + $this->assertType('boolean', $flags['civicrm'], "$msg: civicrm should be boolean"); + $this->assertType('boolean', $flags['uf'], "$msg: uf should be boolean"); + $this->assertType('integer', $flags['instances'], "$msg: instances should be integer"); + + static $lastInstanceCount = 1; + $this->assertTrue($flags['instances'] >= $lastInstanceCount, "$msg: instance count should be monotonic-increasing, starting from 1"); + $lastInstanceCount = $flags['instances']; + + $knownKeys = ['civicrm', 'uf', 'instances']; + $unknownKeys = array_diff(array_keys($flags), $knownKeys); + $this->assertEquals([], $unknownKeys, "$msg: Flags array has unknown keys: " . implode(' ', $unknownKeys)); + } + +}; -- 2.25.1