Update copyright date for 2020
[civicrm-core.git] / Civi / Core / SettingsMetadata.php
CommitLineData
c7d90a9f
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
c7d90a9f 5 +--------------------------------------------------------------------+
f299f7db 6 | Copyright CiviCRM LLC (c) 2004-2020 |
c7d90a9f
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26 */
27
28namespace Civi\Core;
29
30/**
31 * Class SettingsMetadata
32 * @package Civi\Core
33 */
34class SettingsMetadata {
35
c7d90a9f
TO
36 /**
37 * WARNING: This interface may change.
38 *
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
43 * also leverages it.
44 *
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
47 *
48 * Function is intended for configuration rather than runtime access to settings
49 *
50 * The following params will filter the result. If none are passed all settings will be returns
51 *
52 * @param array $filters
53 * @param int $domainID
4cc9fbc2 54 * @param bool $loadOptions
c7d90a9f
TO
55 *
56 * @return array
57 * the following information as appropriate for each setting
58 * - name
59 * - type
60 * - default
61 * - add (CiviCRM version added)
62 * - is_domain
63 * - is_contact
64 * - description
65 * - help_text
4cc9fbc2
CW
66 * - options
67 * - pseudoconstant
c7d90a9f 68 */
4cc9fbc2 69 public static function getMetadata($filters = [], $domainID = NULL, $loadOptions = FALSE) {
e1d39824
TO
70 if ($domainID === NULL) {
71 $domainID = \CRM_Core_Config::domainID();
72 }
73
c7d90a9f 74 $cache = \Civi::cache('settings');
e1d39824 75 $cacheString = 'settingsMetadata_' . $domainID . '_';
c7d90a9f 76 $settingsMetadata = $cache->get($cacheString);
c7d90a9f 77
1209c8a7
CW
78 if (!is_array($settingsMetadata)) {
79 global $civicrm_root;
80 $metaDataFolders = [$civicrm_root . '/settings'];
81 \CRM_Utils_Hook::alterSettingsFolders($metaDataFolders);
82 $settingsMetadata = self::loadSettingsMetaDataFolders($metaDataFolders);
83 \CRM_Utils_Hook::alterSettingsMetaData($settingsMetadata, $domainID, NULL);
c7d90a9f
TO
84 $cache->set($cacheString, $settingsMetadata);
85 }
86
87 self::_filterSettingsSpecification($filters, $settingsMetadata);
4cc9fbc2
CW
88 if ($loadOptions) {
89 self::loadOptions($settingsMetadata);
90 }
c7d90a9f
TO
91
92 return $settingsMetadata;
93 }
94
95 /**
96 * Load the settings files defined in a series of folders.
97 * @param array $metaDataFolders
98 * List of folder paths.
99 * @return array
100 */
101 protected static function loadSettingsMetaDataFolders($metaDataFolders) {
c64f69d9
CW
102 $settingsMetadata = [];
103 $loadedFolders = [];
c7d90a9f
TO
104 foreach ($metaDataFolders as $metaDataFolder) {
105 $realFolder = realpath($metaDataFolder);
106 if (is_dir($realFolder) && !isset($loadedFolders[$realFolder])) {
107 $loadedFolders[$realFolder] = TRUE;
3c250b10 108 $settingsMetadata = $settingsMetadata + self::loadSettingsMetadata($metaDataFolder);
c7d90a9f
TO
109 }
110 }
111 return $settingsMetadata;
112 }
113
114 /**
115 * Load up settings metadata from files.
54957108 116 *
117 * @param array $metaDataFolder
118 *
119 * @return array
c7d90a9f
TO
120 */
121 protected static function loadSettingsMetadata($metaDataFolder) {
c64f69d9 122 $settingMetaData = [];
c7d90a9f
TO
123 $settingsFiles = \CRM_Utils_File::findFiles($metaDataFolder, '*.setting.php');
124 foreach ($settingsFiles as $file) {
125 $settings = include $file;
126 $settingMetaData = array_merge($settingMetaData, $settings);
127 }
c7d90a9f
TO
128 return $settingMetaData;
129 }
130
131 /**
132 * Filter the settings metadata according to filters passed in. This is a convenience filter
133 * and allows selective reverting / filling of settings
134 *
135 * @param array $filters
136 * Filters to match against data.
137 * @param array $settingSpec
138 * Metadata to filter.
139 */
140 protected static function _filterSettingsSpecification($filters, &$settingSpec) {
4cc9fbc2
CW
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']);
c7d90a9f 146 }
4cc9fbc2 147 if (!empty($filters)) {
c7d90a9f
TO
148 foreach ($settingSpec as $field => $fieldValues) {
149 if (array_intersect_assoc($fieldValues, $filters) != $filters) {
150 unset($settingSpec[$field]);
151 }
152 }
4cc9fbc2
CW
153 }
154 }
155
156 /**
157 * Retrieve options from settings metadata
158 *
159 * @param array $settingSpec
160 */
161 protected static function loadOptions(&$settingSpec) {
162 foreach ($settingSpec as &$spec) {
163 if (empty($spec['pseudoconstant'])) {
164 continue;
165 }
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'], []);
171 }
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);
175 }
c7d90a9f
TO
176 }
177 }
178
179}