3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
13 * Class CRM_Core_Config_MagicMerge
15 * Originally, the $config object was based on a single, serialized
16 * data object stored in the database. As the needs for settings
17 * grew (with robust metadata, system overrides, extension support,
18 * and multi-tenancy), the $config started to store a mix of:
19 * (a) canonical config options,
20 * (b) dynamically generated runtime data,
21 * (c) cached data derived from other sources (esp civicrm_setting)
22 * (d) instances of service objects
24 * The config object is now deprecated. Settings and service objects
25 * should generally be accessed via Civi::settings() and Civi::service().
27 * MagicMerge provides backward compatibility. You may still access
28 * old properties via $config, but they will be loaded from their
31 class CRM_Core_Config_MagicMerge
{
34 * Map old config properties to their contemporary counterparts.
37 * Array(string $configAlias => Array(string $realType, string $realName)).
47 * CRM_Core_Config_MagicMerge constructor.
49 public function __construct() {
50 $this->map
= self
::getPropertyMap();
54 * Set the map to the property map.
56 public function __wakeup() {
57 $this->map
= self
::getPropertyMap();
61 * Get a list of $config properties and the entities to which they map.
63 * This is used for two purposes:
65 * 1. Runtime: Provide backward-compatible interface for reading these
67 * 2. Upgrade: Migrate old properties of config_backend into settings.
71 public static function getPropertyMap() {
72 // Each mapping: $propertyName => Array(0 => $type, 1 => $foreignName|NULL, ...).
73 // If $foreignName is omitted/null, then it's assumed to match the $propertyName.
74 // Other parameters may be specified, depending on the type.
76 // "local" properties are unique to each instance of CRM_Core_Config (each request).
77 'doNotResetCache' => ['local'],
78 'inCiviCRM' => ['local'],
79 'keyDisable' => ['local'],
80 'userFrameworkFrontend' => ['local'],
81 'userPermissionTemp' => ['local'],
83 // "runtime" properties are computed from define()s, $_ENV, etc.
84 // See also: CRM_Core_Config_Runtime.
86 'initialized' => ['runtime'],
87 'userFramework' => ['runtime'],
88 'userFrameworkClass' => ['runtime'],
89 'userFrameworkDSN' => ['runtime'],
90 'userFrameworkURLVar' => ['runtime'],
91 'userHookClass' => ['runtime'],
92 'cleanURL' => ['runtime'],
93 'templateDir' => ['runtime'],
95 // "boot-svc" properties are critical services needed during init.
96 // See also: Civi\Core\Container::getBootService().
97 'userSystem' => ['boot-svc'],
98 'userPermissionClass' => ['boot-svc'],
100 'userFrameworkBaseURL' => ['user-system', 'getAbsoluteBaseURL'],
101 'userFrameworkVersion' => ['user-system', 'getVersion'],
103 'useFrameworkRelativeBase' => ['user-system', 'getRelativeBaseURL'],
105 // "setting" properties are loaded through the setting layer, esp
106 // table "civicrm_setting" and global $civicrm_setting.
107 // See also: Civi::settings().
108 'backtrace' => ['setting'],
109 'contact_default_language' => ['setting'],
110 'countryLimit' => ['setting'],
111 'customTranslateFunction' => ['setting'],
112 'dateInputFormat' => ['setting'],
113 'dateformatDatetime' => ['setting'],
114 'dateformatFull' => ['setting'],
115 'dateformatPartial' => ['setting'],
116 'dateformatTime' => ['setting'],
117 'dateformatYear' => ['setting'],
118 'dateformatFinancialBatch' => ['setting'],
119 'dateformatshortdate' => ['setting'],
121 'debug' => ['setting', 'debug_enabled'],
122 'defaultContactCountry' => ['setting'],
123 'defaultContactStateProvince' => ['setting'],
124 'defaultCurrency' => ['setting'],
125 'defaultSearchProfileID' => ['setting'],
126 'doNotAttachPDFReceipt' => ['setting'],
127 'empoweredBy' => ['setting'],
129 'enableComponents' => ['setting', 'enable_components'],
130 'enableSSL' => ['setting'],
131 'fatalErrorHandler' => ['setting'],
132 'fieldSeparator' => ['setting'],
133 'fiscalYearStart' => ['setting'],
134 'geoAPIKey' => ['setting'],
135 'geoProvider' => ['setting'],
136 'includeAlphabeticalPager' => ['setting'],
137 'includeEmailInName' => ['setting'],
138 'includeNickNameInName' => ['setting'],
139 'includeOrderByClause' => ['setting'],
140 'includeWildCardInName' => ['setting'],
141 'inheritLocale' => ['setting'],
142 'languageLimit' => ['setting'],
143 'lcMessages' => ['setting'],
144 'legacyEncoding' => ['setting'],
145 'logging' => ['setting'],
146 'mailThrottleTime' => ['setting'],
147 'mailerBatchLimit' => ['setting'],
148 'mailerJobSize' => ['setting'],
149 'mailerJobsMax' => ['setting'],
150 'mapAPIKey' => ['setting'],
151 'mapProvider' => ['setting'],
152 'maxFileSize' => ['setting'],
154 'maxAttachments' => ['setting', 'max_attachments'],
155 'maxAttachmentsBackend' => ['setting', 'max_attachments_backend'],
156 'monetaryDecimalPoint' => ['setting'],
157 'monetaryThousandSeparator' => ['setting'],
158 'moneyformat' => ['setting'],
159 'moneyvalueformat' => ['setting'],
160 'provinceLimit' => ['setting'],
161 'recaptchaOptions' => ['setting'],
162 'recaptchaPublicKey' => ['setting'],
163 'recaptchaPrivateKey' => ['setting'],
164 'forceRecaptcha' => ['setting'],
165 'replyTo' => ['setting'],
166 'secondDegRelPermissions' => ['setting'],
167 'smartGroupCacheTimeout' => ['setting'],
168 'timeInputFormat' => ['setting'],
169 'userFrameworkLogging' => ['setting'],
170 'userFrameworkUsersTableName' => ['setting'],
171 'verpSeparator' => ['setting'],
172 'wkhtmltopdfPath' => ['setting'],
173 'wpLoadPhp' => ['setting'],
175 // "path" properties are managed via Civi::paths and $civicrm_paths
176 // Option: `mkdir` - auto-create dir
177 // Option: `restrict` - auto-restrict remote access
178 'configAndLogDir' => ['path', 'civicrm.log', ['mkdir', 'restrict']],
179 'templateCompileDir' => ['path', 'civicrm.compile', ['mkdir', 'restrict']],
181 // "setting-path" properties are settings with special filtering
182 // to return normalized file paths.
183 // Option: `mkdir` - auto-create dir
184 // Option: `restrict` - auto-restrict remote access
185 'customFileUploadDir' => ['setting-path', NULL, ['mkdir', 'restrict']],
186 'customPHPPathDir' => ['setting-path'],
187 'customTemplateDir' => ['setting-path'],
188 'extensionsDir' => ['setting-path', NULL, ['mkdir']],
189 'imageUploadDir' => ['setting-path', NULL, ['mkdir']],
190 'uploadDir' => ['setting-path', NULL, ['mkdir', 'restrict']],
192 // "setting-url" properties are settings with special filtering
193 // to return normalized URLs.
194 // Option: `noslash` - don't append trailing slash
195 // Option: `rel` - convert to relative URL (if possible)
196 'customCSSURL' => ['setting-url', NULL, ['noslash']],
197 'extensionsURL' => ['setting-url'],
198 'imageUploadURL' => ['setting-url'],
199 'resourceBase' => ['setting-url', 'userFrameworkResourceURL', ['rel']],
200 'userFrameworkResourceURL' => ['setting-url'],
202 // "callback" properties are generated on-demand by calling a function.
203 // @todo remove geocodeMethod. As of Feb 2018, $config->geocodeMethod works but gives a deprecation warning.
204 'geocodeMethod' => ['callback', 'CRM_Utils_Geocode', 'getProviderClass'],
205 'defaultCurrencySymbol' => ['callback', 'CRM_Core_BAO_Country', 'getDefaultCurrencySymbol'],
206 'wpBasePage' => ['callback', 'CRM_Utils_System_WordPress', 'getBasePage'],
216 * @throws \CRM_Core_Exception
218 public function __get($k) {
219 if (!isset($this->map
[$k])) {
220 throw new \
CRM_Core_Exception("Cannot read unrecognized property CRM_Core_Config::\${$k}.");
222 if (isset($this->cache
[$k])) {
223 return $this->cache
[$k];
226 $type = $this->map
[$k][0];
227 $name = $this->map
[$k][1] ??
$k;
231 return $this->getSettings()->get($name);
233 // The interpretation of 'path' and 'setting-path' is similar, except
234 // that the latter originates in a stored setting.
237 // Array(0 => $type, 1 => $setting, 2 => $actions).
238 $value = ($type === 'path')
239 ? Civi
::paths()->getVariable($name, 'path')
240 : Civi
::paths()->getPath($this->getSettings()->get($name));
242 $value = CRM_Utils_File
::addTrailingSlash($value);
243 if (isset($this->map
[$k][2]) && in_array('mkdir', $this->map
[$k][2])) {
244 if (!is_dir($value) && !CRM_Utils_File
::createDir($value, FALSE)) {
245 CRM_Core_Session
::setStatus(ts('Failed to make directory (%1) at "%2". Please update the settings or file permissions.', [
251 if (isset($this->map
[$k][2]) && in_array('restrict', $this->map
[$k][2])) {
252 CRM_Utils_File
::restrictAccess($value);
255 $this->cache
[$k] = $value;
259 $options = !empty($this->map
[$k][2]) ?
$this->map
[$k][2] : [];
260 $value = $this->getSettings()->get($name);
261 if ($value && !(in_array('noslash', $options))) {
262 $value = CRM_Utils_File
::addTrailingSlash($value, '/');
264 $this->cache
[$k] = Civi
::paths()->getUrl($value,
265 in_array('rel', $options) ?
'relative' : 'absolute');
266 return $this->cache
[$k];
269 return \Civi\Core\Container
::getBootService('runtime')->{$name};
272 $this->cache
[$k] = \Civi\Core\Container
::getBootService($name);
273 return $this->cache
[$k];
277 return $this->locals
[$name];
280 $userSystem = \Civi\Core\Container
::getBootService('userSystem');
281 $this->cache
[$k] = call_user_func([$userSystem, $name]);
282 return $this->cache
[$k];
285 return \Civi
::service($name);
288 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
289 if (!isset($this->map
[$k][1], $this->map
[$k][2])) {
290 throw new \
CRM_Core_Exception("Cannot find getter for property CRM_Core_Config::\${$k}");
292 return \Civi\Core\Resolver
::singleton()->call([$this->map
[$k][1], $this->map
[$k][2]], [$k]);
295 throw new \
CRM_Core_Exception("Cannot read property CRM_Core_Config::\${$k} ($type)");
305 * @throws \CRM_Core_Exception
307 public function __set($k, $v) {
308 if (!isset($this->map
[$k])) {
309 throw new \
CRM_Core_Exception("Cannot set unrecognized property CRM_Core_Config::\${$k}");
311 unset($this->cache
[$k]);
312 $type = $this->map
[$k][0];
323 // In the past, changes to $config were not persisted automatically.
324 $this->cache
[$k] = $v;
329 $this->locals
[$k] = $v;
333 throw new \
CRM_Core_Exception("Cannot set property CRM_Core_Config::\${$k} ($type)");
344 public function __isset($k) {
345 return isset($this->map
[$k]);
353 * @throws \CRM_Core_Exception
355 public function __unset($k) {
356 if (!isset($this->map
[$k])) {
357 throw new \
CRM_Core_Exception("Cannot unset unrecognized property CRM_Core_Config::\${$k}");
359 unset($this->cache
[$k]);
360 $type = $this->map
[$k][0];
361 $name = $this->map
[$k][1] ??
$k;
367 $this->getSettings()->revert($k);
372 $this->locals
[$name] = NULL;
376 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
377 if (!isset($this->map
[$k][1], $this->map
[$k][4])) {
378 throw new \
CRM_Core_Exception("Cannot find unsetter for property CRM_Core_Config::\${$k}");
380 \Civi\Core\Resolver
::singleton()->call([$this->map
[$k][1], $this->map
[$k][4]], [$k]);
384 throw new \
CRM_Core_Exception("Cannot unset property CRM_Core_Config::\${$k} ($type)");
389 * @return \Civi\Core\SettingsBag
391 protected function getSettings() {
392 if ($this->settings
=== NULL) {
393 $this->settings
= Civi
::settings();
395 return $this->settings
;
399 * Initialise local settings.
401 private function initLocals() {
402 if ($this->locals
=== NULL) {
404 'inCiviCRM' => FALSE,
405 'doNotResetCache' => 0,
406 'keyDisable' => FALSE,
407 'initialized' => FALSE,
408 'userFrameworkFrontend' => FALSE,
409 'userPermissionTemp' => NULL,