CRM-16373 - Migrate config_backend to civicrm_setting
[civicrm-core.git] / CRM / Core / Config / MagicMerge.php
CommitLineData
c0a1f187
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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
28/**
29 * Class CRM_Core_Config_MagicMerge
30 *
31 * Originally, the $config object was based on a single, serialized
32 * data object stored in the database. As the needs for settings
33 * grew (with robust metadata, system overrides, and extension support),
34 * the $config started to store a mix of:
35 * (a) canonical config options,
36 * (b) dynamically generated runtime data,
37 * (c) cached data derived from other sources (esp civicrm_setting)
38 * (d) instances of service objects
39 *
40 * The config object is now deprecated. Settings and service objects
41 * should generally be accessed via Civi::settings() and Civi::service().
42 *
43 * MagicMerge provides backward compatibility. You may still access
44 * old properties via $config, but they will be loaded from their
45 * new services.
46 */
47class CRM_Core_Config_MagicMerge {
48
49 /**
50 * Map old config properties to their contemporary counterparts.
51 *
52 * @var array
53 * Array(string $configAlias => Array(string $realType, string $realName)).
54 */
55 private $map;
56
23bb9c85 57 private $runtime, $locals, $settings;
c0a1f187 58
7dba62da
TO
59 private $cache = array();
60
c0a1f187
TO
61 public function __construct() {
62 $this->map = self::getPropertyMap();
63 }
64
65 public function __wakeup() {
66 $this->map = self::getPropertyMap();
67 }
68
69 /**
f806379b
TO
70 * Get a list of $config properties and the entities to which they map.
71 *
72 * This is used for two purposes:
73 *
74 * 1. Runtime: Provide backward-compatible interface for reading these
75 * properties.
76 * 2. Upgrade: Migrate old properties of config_backend into settings.
77 *
c0a1f187
TO
78 * @return array
79 */
80 public static function getPropertyMap() {
e3d28c74
TO
81 // Each mapping: $propertyName => Array(0 => $type, 1 => $foreignName|NULL, ...).
82 // If $foreignName is omitted/null, then it's assumed to match the $propertyName.
83 // Other parameters may be specified, depending on the type.
c0a1f187 84 return array(
e3d28c74
TO
85 'backtrace' => array('setting'),
86 'countryLimit' => array('setting'),
87 'dashboardCacheTimeout' => array('setting'),
88 'dateInputFormat' => array('setting'),
89 'dateformatDatetime' => array('setting'),
90 'dateformatFull' => array('setting'),
91 'dateformatPartial' => array('setting'),
92 'dateformatTime' => array('setting'),
93 'dateformatYear' => array('setting'),
c0a1f187 94 'debug' => array('setting', 'debug_enabled'), // renamed.
e3d28c74
TO
95 'defaultContactCountry' => array('setting'),
96 'defaultContactStateProvince' => array('setting'),
97 'defaultCurrency' => array('setting'),
98 'defaultSearchProfileID' => array('setting'),
99 'doNotAttachPDFReceipt' => array('setting'),
100 'empoweredBy' => array('setting'),
c0a1f187 101 'enableComponents' => array('setting', 'enable_components'), // renamed.
e3d28c74
TO
102 'enableSSL' => array('setting'),
103 'fatalErrorHandler' => array('setting'),
104 'fieldSeparator' => array('setting'),
105 'fiscalYearStart' => array('setting'),
106 'geoAPIKey' => array('setting'),
107 'geoProvider' => array('setting'),
108 'includeAlphabeticalPager' => array('setting'),
109 'includeEmailInName' => array('setting'),
110 'includeNickNameInName' => array('setting'),
111 'includeOrderByClause' => array('setting'),
112 'includeWildCardInName' => array('setting'),
113 'inheritLocale' => array('setting'),
114 'languageLimit' => array('setting'),
115 'lcMessages' => array('setting'),
116 'legacyEncoding' => array('setting'),
117 'logging' => array('setting'),
118 'mailThrottleTime' => array('setting'),
119 'mailerBatchLimit' => array('setting'),
120 'mailerJobSize' => array('setting'),
121 'mailerJobsMax' => array('setting'),
122 'mapAPIKey' => array('setting'),
123 'mapProvider' => array('setting'),
124 'maxFileSize' => array('setting'),
c0a1f187 125 'maxAttachments' => array('setting', 'max_attachments'), // renamed.
e3d28c74
TO
126 'monetaryDecimalPoint' => array('setting'),
127 'monetaryThousandSeparator' => array('setting'),
128 'moneyformat' => array('setting'),
129 'moneyvalueformat' => array('setting'),
130 'provinceLimit' => array('setting'),
131 'recaptchaOptions' => array('setting'),
132 'recaptchaPublicKey' => array('setting'),
133 'recaptchaPrivateKey' => array('setting'),
606999ec 134 'replyTo' => array('setting'),
e3d28c74
TO
135 'secondDegRelPermissions' => array('setting'),
136 'smartGroupCacheTimeout' => array('setting'),
137 'timeInputFormat' => array('setting'),
138 'userFrameworkLogging' => array('setting'),
139 'userFrameworkUsersTableName' => array('setting'),
140 'verpSeparator' => array('setting'),
606999ec 141 'versionCheck' => array('setting'),
e3d28c74
TO
142 'wkhtmltopdfPath' => array('setting'),
143 'wpBasePage' => array('setting'),
144 'wpLoadPhp' => array('setting'),
145
146 'doNotResetCache' => array('local'),
147 'inCiviCRM' => array('local'),
148 'userFrameworkFrontend' => array('local'),
e3d28c74
TO
149
150 'dsn' => array('runtime'),
606999ec 151 'initialized' => array('runtime'),
e3d28c74
TO
152 'userFramework' => array('runtime'),
153 'userFrameworkBaseURL' => array('runtime'),
154 'userFrameworkClass' => array('runtime'),
155 'userFrameworkDSN' => array('runtime'),
c0a1f187 156 'useFrameworkRelativeBase' => array('runtime', 'useFrameworkRelativeBase'),
e3d28c74 157 'userFrameworkURLVar' => array('runtime'),
606999ec 158 'userFrameworkVersion' => array('runtime'),
e3d28c74
TO
159 'userPermissionClass' => array('runtime'),
160 'userPermissionTemp' => array('runtime'),
161 'userSystem' => array('runtime'),
162 'userHookClass' => array('runtime'),
163 'cleanURL' => array('runtime'),
164 'configAndLogDir' => array('runtime'),
165 'templateCompileDir' => array('runtime'),
166 'templateDir' => array('runtime'),
167
168 'customFileUploadDir' => array('setting-path', NULL, '[civicrm.files]/custom/', array('mkdir', 'restrict')),
169 'customPHPPathDir' => array('setting-path'),
170 'customTemplateDir' => array('setting-path'),
171 'extensionsDir' => array('setting-path'),
172 'imageUploadDir' => array('setting-path', NULL, '[civicrm.files]/persist/contribute/', array('mkdir')),
173 'uploadDir' => array('setting-path', NULL, '[civicrm.files]/upload/', array('mkdir', 'restrict')),
174
175 'customCSSURL' => array('setting-url-abs'),
176 'extensionsURL' => array('setting-url-abs'),
177 'imageUploadURL' => array('setting-url-abs', NULL, '[civicrm.files]/persist/contribute/'),
178 'resourceBase' => array('setting-url-rel', 'userFrameworkResourceURL', '[civicrm]/.'),
179 'userFrameworkResourceURL' => array('setting-url-abs', NULL, '[civicrm]/.'),
c0a1f187
TO
180
181 'geocodeMethod' => array('callback', 'CRM_Utils_Geocode', 'getProviderClass'),
d7c217ae 182 'defaultCurrencySymbol' => array('callback', 'CRM_Core_BAO_Country', 'getDefaultCurrencySymbol'),
c0a1f187
TO
183 );
184 }
185
186 public function __get($k) {
187 if (!isset($this->map[$k])) {
188 throw new \CRM_Core_Exception("Cannot read unrecognized property CRM_Core_Config::\${$k}.");
189 }
7dba62da
TO
190 if (isset($this->cache[$k])) {
191 return $this->cache[$k];
192 }
e3d28c74
TO
193
194 $type = $this->map[$k][0];
195 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
c0a1f187
TO
196
197 switch ($type) {
198 case 'setting':
23bb9c85 199 return $this->getSettings()->get($name);
c0a1f187
TO
200
201 case 'setting-path':
e3d28c74
TO
202 // Array(0 => $type, 1 => $setting, 2 => $default, 3 => $actions).
203 $value = $this->getSettings()->get($name);
204 if (empty($value) && isset($this->map[$k][2])) {
205 $value = $this->map[$k][2];
206 }
207 $value = Civi::paths()->getPath($value);
208 if ($value) {
209 $value = CRM_Utils_File::addTrailingSlash($value);
210 if (isset($this->map[$k][3]) && in_array('mkdir', $this->map[$k][3])) {
211 CRM_Utils_File::createDir($value);
212 }
213 if (isset($this->map[$k][3]) && in_array('restrict', $this->map[$k][3])) {
214 CRM_Utils_File::restrictAccess($value);
215 }
216 }
7dba62da 217 $this->cache[$k] = $value;
e3d28c74
TO
218 return $value;
219
220 case 'setting-url-abs':
221 // Array(0 => $type, 1 => $setting, 2 => $default).
222 $value = $this->getSettings()->get($name);
223 if (empty($value) && isset($this->map[$k][2])) {
224 $value = $this->map[$k][2];
225 }
7dba62da
TO
226 $this->cache[$k] = Civi::paths()->getUrl($value, 'absolute');
227 return $this->cache[$k];
c0a1f187 228
e3d28c74
TO
229 case 'setting-url-rel':
230 // Array(0 => $type, 1 => $setting, 2 => $default).
231 $value = $this->getSettings()->get($name);
232 if (empty($value) && isset($this->map[$k][2])) {
233 $value = $this->map[$k][2];
234 }
7dba62da
TO
235 $this->cache[$k] = Civi::paths()->getUrl($value, 'relative');
236 return $this->cache[$k];
c0a1f187
TO
237
238 case 'runtime':
239 return $this->getRuntime()->{$name};
240
241 case 'local':
242 $this->initLocals();
243 return $this->locals[$name];
244
245 case 'service':
246 return \Civi::service($name);
247
248 case 'callback':
249 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
250 if (!isset($this->map[$k][1], $this->map[$k][2])) {
251 throw new \CRM_Core_Exception("Cannot find getter for property CRM_Core_Config::\${$k}");
252 }
253 return \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][2]), array($k));
254
255 default:
256 throw new \CRM_Core_Exception("Cannot read property CRM_Core_Config::\${$k} ($type)");
257 }
258 }
259
260 public function __set($k, $v) {
261 if (!isset($this->map[$k])) {
262 throw new \CRM_Core_Exception("Cannot set unrecognized property CRM_Core_Config::\${$k}");
263 }
7dba62da 264 unset($this->cache[$k]);
dc640254
TO
265 $type = $this->map[$k][0];
266 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
c0a1f187
TO
267
268 switch ($type) {
269 case 'setting':
dc640254
TO
270 case 'setting-path':
271 case 'setting-url-abs':
272 case 'setting-url-rel':
c0a1f187 273 case 'runtime':
dc640254
TO
274 case 'callback':
275 // In the past, changes to $config were not persisted automatically.
276 $this->cache[$name] = $v;
c0a1f187
TO
277 return;
278
279 case 'local':
280 $this->initLocals();
281 $this->locals[$name] = $v;
282 return;
283
c0a1f187
TO
284 default:
285 throw new \CRM_Core_Exception("Cannot set property CRM_Core_Config::\${$k} ($type)");
286 }
287 }
288
289 public function __isset($k) {
290 return isset($this->map[$k]);
291 }
292
293 public function __unset($k) {
294 if (!isset($this->map[$k])) {
295 throw new \CRM_Core_Exception("Cannot unset unrecognized property CRM_Core_Config::\${$k}");
296 }
7dba62da 297 unset($this->cache[$k]);
dc640254
TO
298 $type = $this->map[$k][0];
299 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
c0a1f187
TO
300
301 switch ($type) {
302 case 'setting':
303 case 'setting-path':
e3d28c74
TO
304 case 'setting-url-abs':
305 case 'setting-url-rel':
23bb9c85 306 $this->getSettings()->revert($k);
c0a1f187
TO
307 return;
308
309 case 'local':
310 $this->initLocals();
311 $this->locals[$name] = NULL;
312 return;
313
314 case 'callback':
315 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
316 if (!isset($this->map[$k][1], $this->map[$k][4])) {
317 throw new \CRM_Core_Exception("Cannot find unsetter for property CRM_Core_Config::\${$k}");
318 }
319 \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][4]), array($k));
320 return;
321
322 default:
323 throw new \CRM_Core_Exception("Cannot unset property CRM_Core_Config::\${$k} ($type)");
324 }
325 }
326
327 /**
328 * @return CRM_Core_Config_Runtime
329 */
330 protected function getRuntime() {
331 if ($this->runtime === NULL) {
332 $this->runtime = new CRM_Core_Config_Runtime();
333 }
334 return $this->runtime;
335 }
336
23bb9c85
TO
337 /**
338 * @return \Civi\Core\SettingsBag
339 */
340 protected function getSettings() {
341 if ($this->settings === NULL) {
342 $this->settings = Civi::settings();
343 }
344 return $this->settings;
345 }
346
c0a1f187
TO
347 private function initLocals() {
348 if ($this->locals === NULL) {
349 $this->locals = array(
350 'inCiviCRM' => FALSE,
351 'doNotResetCache' => 0,
352 'initialized' => FALSE,
353 'userFrameworkFrontend' => FALSE,
354 );
355 }
356 }
357
358}