get($cacheString); if (!is_array($settingsMetadata)) { global $civicrm_root; $metaDataFolders = [$civicrm_root . '/settings']; \CRM_Utils_Hook::alterSettingsFolders($metaDataFolders); $settingsMetadata = self::loadSettingsMetaDataFolders($metaDataFolders); \CRM_Utils_Hook::alterSettingsMetaData($settingsMetadata, $domainID, NULL); $cache->set($cacheString, $settingsMetadata); } self::_filterSettingsSpecification($filters, $settingsMetadata); if ($loadOptions) { self::loadOptions($settingsMetadata); } return $settingsMetadata; } /** * Load the settings files defined in a series of folders. * @param array $metaDataFolders * List of folder paths. * @return array */ protected static function loadSettingsMetaDataFolders($metaDataFolders) { $settingsMetadata = []; $loadedFolders = []; foreach ($metaDataFolders as $metaDataFolder) { $realFolder = realpath($metaDataFolder); if (is_dir($realFolder) && !isset($loadedFolders[$realFolder])) { $loadedFolders[$realFolder] = TRUE; $settingsMetadata = $settingsMetadata + self::loadSettingsMetadata($metaDataFolder); } } return $settingsMetadata; } /** * Load up settings metadata from files. * * @param array $metaDataFolder * * @return array */ protected static function loadSettingsMetadata($metaDataFolder) { $settingMetaData = []; $settingsFiles = \CRM_Utils_File::findFiles($metaDataFolder, '*.setting.php'); foreach ($settingsFiles as $file) { $settings = include $file; $settingMetaData = array_merge($settingMetaData, $settings); } return $settingMetaData; } /** * Filter the settings metadata according to filters passed in. This is a convenience filter * and allows selective reverting / filling of settings * * @param array $filters * Filters to match against data. * @param array $settingSpec * Metadata to filter. */ protected static function _filterSettingsSpecification($filters, &$settingSpec) { if (!empty($filters['name'])) { $settingSpec = array_intersect_key($settingSpec, array_flip((array) $filters['name'])); // FIXME: This is a workaround for settingsBag::setDb() called by unit tests with settings names that don't exist $settingSpec += array_fill_keys((array) $filters['name'], []); unset($filters['name']); } if (!empty($filters)) { foreach ($settingSpec as $field => $fieldValues) { if (array_intersect_assoc($fieldValues, $filters) != $filters) { unset($settingSpec[$field]); } } } } /** * Retrieve options from settings metadata * * @param array $settingSpec */ protected static function loadOptions(&$settingSpec) { foreach ($settingSpec as &$spec) { if (empty($spec['pseudoconstant'])) { continue; } $pseudoconstant = $spec['pseudoconstant']; // It would be nice if we could leverage CRM_Core_PseudoConstant::get() somehow, // but it's tightly coupled to DAO/field. However, if you really need to support // more pseudoconstant types, then probably best to refactor it. For now, KISS. if (!empty($pseudoconstant['callback'])) { $spec['options'] = Resolver::singleton()->call($pseudoconstant['callback'], []); } elseif (!empty($pseudoconstant['optionGroupName'])) { $keyColumn = \CRM_Utils_Array::value('keyColumn', $pseudoconstant, 'value'); $spec['options'] = \CRM_Core_OptionGroup::values($pseudoconstant['optionGroupName'], FALSE, FALSE, TRUE, NULL, 'label', TRUE, FALSE, $keyColumn); } if (!empty($pseudoconstant['table'])) { $params = [ 'condition' => $pseudoconstant['condition'] ?? [], 'keyColumn' => $pseudoconstant['keyColumn'] ?? NULL, 'labelColumn' => $pseudoconstant['labelColumn'] ?? NULL, ]; $spec['options'] = \CRM_Core_PseudoConstant::renderOptionsFromTablePseudoconstant($pseudoconstant, $params, ($spec['localize_context'] ?? NULL), 'get'); } } } }