3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * Class SettingsMetadata
34 class SettingsMetadata
{
37 * WARNING: This interface may change.
39 * This provides information about the setting - similar to the fields concept for DAO information.
40 * As the setting is serialized code creating validation setting input needs to know the data type
41 * This also helps move information out of the form layer into the data layer where people can interact with
42 * it via the API or other mechanisms. In order to keep this consistent it is important the form layer
45 * Note that this function should never be called when using the runtime getvalue function. Caching works
46 * around the expectation it will be called during setting administration
48 * Function is intended for configuration rather than runtime access to settings
50 * The following params will filter the result. If none are passed all settings will be returns
52 * @param array $filters
53 * @param int $domainID
54 * @param bool $loadOptions
57 * the following information as appropriate for each setting
61 * - add (CiviCRM version added)
69 public static function getMetadata($filters = [], $domainID = NULL, $loadOptions = FALSE) {
70 if ($domainID === NULL) {
71 $domainID = \CRM_Core_Config
::domainID();
74 $cache = \Civi
::cache('settings');
75 $cacheString = 'settingsMetadata_' . $domainID . '_';
76 $settingsMetadata = $cache->get($cacheString);
78 if (!is_array($settingsMetadata)) {
80 $metaDataFolders = [$civicrm_root . '/settings'];
81 \CRM_Utils_Hook
::alterSettingsFolders($metaDataFolders);
82 $settingsMetadata = self
::loadSettingsMetaDataFolders($metaDataFolders);
83 \CRM_Utils_Hook
::alterSettingsMetaData($settingsMetadata, $domainID, NULL);
84 $cache->set($cacheString, $settingsMetadata);
87 self
::_filterSettingsSpecification($filters, $settingsMetadata);
89 self
::loadOptions($settingsMetadata);
92 return $settingsMetadata;
96 * Load the settings files defined in a series of folders.
97 * @param array $metaDataFolders
98 * List of folder paths.
101 protected static function loadSettingsMetaDataFolders($metaDataFolders) {
102 $settingsMetadata = [];
104 foreach ($metaDataFolders as $metaDataFolder) {
105 $realFolder = realpath($metaDataFolder);
106 if (is_dir($realFolder) && !isset($loadedFolders[$realFolder])) {
107 $loadedFolders[$realFolder] = TRUE;
108 $settingsMetadata = $settingsMetadata + self
::loadSettingsMetadata($metaDataFolder);
111 return $settingsMetadata;
115 * Load up settings metadata from files.
117 * @param array $metaDataFolder
121 protected static function loadSettingsMetadata($metaDataFolder) {
122 $settingMetaData = [];
123 $settingsFiles = \CRM_Utils_File
::findFiles($metaDataFolder, '*.setting.php');
124 foreach ($settingsFiles as $file) {
125 $settings = include $file;
126 $settingMetaData = array_merge($settingMetaData, $settings);
128 return $settingMetaData;
132 * Filter the settings metadata according to filters passed in. This is a convenience filter
133 * and allows selective reverting / filling of settings
135 * @param array $filters
136 * Filters to match against data.
137 * @param array $settingSpec
138 * Metadata to filter.
140 protected static function _filterSettingsSpecification($filters, &$settingSpec) {
141 if (!empty($filters['name'])) {
142 $settingSpec = array_intersect_key($settingSpec, array_flip((array) $filters['name']));
143 // FIXME: This is a workaround for settingsBag::setDb() called by unit tests with settings names that don't exist
144 $settingSpec +
= array_fill_keys((array) $filters['name'], []);
145 unset($filters['name']);
147 if (!empty($filters)) {
148 foreach ($settingSpec as $field => $fieldValues) {
149 if (array_intersect_assoc($fieldValues, $filters) != $filters) {
150 unset($settingSpec[$field]);
157 * Retrieve options from settings metadata
159 * @param array $settingSpec
161 protected static function loadOptions(&$settingSpec) {
162 foreach ($settingSpec as &$spec) {
163 if (empty($spec['pseudoconstant'])) {
166 // It would be nice if we could leverage CRM_Core_PseudoConstant::get() somehow,
167 // but it's tightly coupled to DAO/field. However, if you really need to support
168 // more pseudoconstant types, then probably best to refactor it. For now, KISS.
169 if (!empty($spec['pseudoconstant']['callback'])) {
170 $spec['options'] = Resolver
::singleton()->call($spec['pseudoconstant']['callback'], []);
172 elseif (!empty($spec['pseudoconstant']['optionGroupName'])) {
173 $keyColumn = \CRM_Utils_Array
::value('keyColumn', $spec['pseudoconstant'], 'value');
174 $spec['options'] = \CRM_Core_OptionGroup
::values($spec['pseudoconstant']['optionGroupName'], FALSE, FALSE, TRUE, NULL, 'label', TRUE, FALSE, $keyColumn);