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::fillOptions($settingsMetadata, $loadOptions); } 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 string $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 * @param bool|array $optionsFormat * TRUE for a flat array; otherwise an array of keys to return */ protected static function fillOptions(&$settingSpec, $optionsFormat) { foreach ($settingSpec as &$spec) { if (empty($spec['pseudoconstant'])) { continue; } $pseudoconstant = $spec['pseudoconstant']; $spec['options'] = []; // 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['optionGroupName'])) { $keyColumn = \CRM_Utils_Array::value('keyColumn', $pseudoconstant, 'value'); if (is_array($optionsFormat)) { $optionValues = \CRM_Core_OptionValue::getValues(['name' => $pseudoconstant['optionGroupName']]); foreach ($optionValues as $option) { $option['id'] = $option['value']; $spec['options'][] = $option; } } else { $spec['options'] = \CRM_Core_OptionGroup::values($pseudoconstant['optionGroupName'], FALSE, FALSE, TRUE, NULL, 'label', TRUE, FALSE, $keyColumn); } continue; } if (!empty($pseudoconstant['callback'])) { $options = Resolver::singleton()->call($pseudoconstant['callback'], []); } if (!empty($pseudoconstant['table'])) { $params = [ 'condition' => $pseudoconstant['condition'] ?? [], 'keyColumn' => $pseudoconstant['keyColumn'] ?? NULL, 'labelColumn' => $pseudoconstant['labelColumn'] ?? NULL, ]; $options = \CRM_Core_PseudoConstant::renderOptionsFromTablePseudoconstant($pseudoconstant, $params, ($spec['localize_context'] ?? NULL), 'get'); } if (is_array($optionsFormat)) { foreach ($options as $key => $value) { $spec['options'][] = [ 'id' => $key, 'name' => $value, 'label' => $value, ]; } } else { $spec['options'] = $options; } } } }