Addition to create extension directory
[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
9e1e6020
TO
33 * grew (with robust metadata, system overrides, extension support,
34 * and multi-tenancy), the $config started to store a mix of:
c0a1f187
TO
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
7f835399 57 private $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(
9e1e6020
TO
85 // "local" properties are unique to each instance of CRM_Core_Config (each request).
86 'doNotResetCache' => array('local'),
87 'inCiviCRM' => array('local'),
5f900b59 88 'keyDisable' => array('local'),
9e1e6020 89 'userFrameworkFrontend' => array('local'),
d4330c62 90 'userPermissionTemp' => array('local'),
9e1e6020
TO
91
92 // "runtime" properties are computed from define()s, $_ENV, etc.
93 // See also: CRM_Core_Config_Runtime.
94 'dsn' => array('runtime'),
95 'initialized' => array('runtime'),
96 'userFramework' => array('runtime'),
9e1e6020
TO
97 'userFrameworkClass' => array('runtime'),
98 'userFrameworkDSN' => array('runtime'),
9e1e6020 99 'userFrameworkURLVar' => array('runtime'),
9e1e6020
TO
100 'userHookClass' => array('runtime'),
101 'cleanURL' => array('runtime'),
102 'configAndLogDir' => array('runtime'),
103 'templateCompileDir' => array('runtime'),
104 'templateDir' => array('runtime'),
105
d4330c62 106 // "boot-svc" properties are critical services needed during init.
7f835399 107 // See also: Civi\Core\Container::getBootService().
d4330c62
TO
108 'userSystem' => array('boot-svc'),
109 'userPermissionClass' => array('boot-svc'),
110
111 'userFrameworkBaseURL' => array('user-system', 'getAbsoluteBaseURL'),
112 'userFrameworkVersion' => array('user-system', 'getVersion'),
113 'useFrameworkRelativeBase' => array('user-system', 'getRelativeBaseURL'), // ugh typo.
114
9e1e6020
TO
115 // "setting" properties are loaded through the setting layer, esp
116 // table "civicrm_setting" and global $civicrm_setting.
117 // See also: Civi::settings().
e3d28c74 118 'backtrace' => array('setting'),
9e1e6020 119 'contact_default_language' => array('setting'),
e3d28c74
TO
120 'countryLimit' => array('setting'),
121 'dashboardCacheTimeout' => array('setting'),
122 'dateInputFormat' => array('setting'),
123 'dateformatDatetime' => array('setting'),
124 'dateformatFull' => array('setting'),
125 'dateformatPartial' => array('setting'),
126 'dateformatTime' => array('setting'),
127 'dateformatYear' => array('setting'),
c0a1f187 128 'debug' => array('setting', 'debug_enabled'), // renamed.
e3d28c74
TO
129 'defaultContactCountry' => array('setting'),
130 'defaultContactStateProvince' => array('setting'),
131 'defaultCurrency' => array('setting'),
132 'defaultSearchProfileID' => array('setting'),
133 'doNotAttachPDFReceipt' => array('setting'),
134 'empoweredBy' => array('setting'),
c0a1f187 135 'enableComponents' => array('setting', 'enable_components'), // renamed.
e3d28c74
TO
136 'enableSSL' => array('setting'),
137 'fatalErrorHandler' => array('setting'),
138 'fieldSeparator' => array('setting'),
139 'fiscalYearStart' => array('setting'),
140 'geoAPIKey' => array('setting'),
141 'geoProvider' => array('setting'),
142 'includeAlphabeticalPager' => array('setting'),
143 'includeEmailInName' => array('setting'),
144 'includeNickNameInName' => array('setting'),
145 'includeOrderByClause' => array('setting'),
146 'includeWildCardInName' => array('setting'),
147 'inheritLocale' => array('setting'),
148 'languageLimit' => array('setting'),
149 'lcMessages' => array('setting'),
150 'legacyEncoding' => array('setting'),
151 'logging' => array('setting'),
152 'mailThrottleTime' => array('setting'),
153 'mailerBatchLimit' => array('setting'),
154 'mailerJobSize' => array('setting'),
155 'mailerJobsMax' => array('setting'),
156 'mapAPIKey' => array('setting'),
157 'mapProvider' => array('setting'),
158 'maxFileSize' => array('setting'),
c0a1f187 159 'maxAttachments' => array('setting', 'max_attachments'), // renamed.
e3d28c74
TO
160 'monetaryDecimalPoint' => array('setting'),
161 'monetaryThousandSeparator' => array('setting'),
162 'moneyformat' => array('setting'),
163 'moneyvalueformat' => array('setting'),
164 'provinceLimit' => array('setting'),
165 'recaptchaOptions' => array('setting'),
166 'recaptchaPublicKey' => array('setting'),
167 'recaptchaPrivateKey' => array('setting'),
606999ec 168 'replyTo' => array('setting'),
e3d28c74
TO
169 'secondDegRelPermissions' => array('setting'),
170 'smartGroupCacheTimeout' => array('setting'),
171 'timeInputFormat' => array('setting'),
172 'userFrameworkLogging' => array('setting'),
173 'userFrameworkUsersTableName' => array('setting'),
174 'verpSeparator' => array('setting'),
606999ec 175 'versionCheck' => array('setting'),
e3d28c74
TO
176 'wkhtmltopdfPath' => array('setting'),
177 'wpBasePage' => array('setting'),
178 'wpLoadPhp' => array('setting'),
179
9e1e6020
TO
180 // "setting-path" properties are settings with special filtering
181 // to return normalized file paths.
ac47f7ca 182 'customFileUploadDir' => array('setting-path', NULL, array('mkdir', 'restrict')),
e3d28c74
TO
183 'customPHPPathDir' => array('setting-path'),
184 'customTemplateDir' => array('setting-path'),
8dac2d39 185 'extensionsDir' => array('setting-path', NULL, array('mkdir')),
ac47f7ca
TO
186 'imageUploadDir' => array('setting-path', NULL, array('mkdir')),
187 'uploadDir' => array('setting-path', NULL, array('mkdir', 'restrict')),
e3d28c74 188
9e1e6020
TO
189 // "setting-url-*" properties are settings with special filtering
190 // to return normalized URLs (in either absolute or relative format).
e3d28c74
TO
191 'customCSSURL' => array('setting-url-abs'),
192 'extensionsURL' => array('setting-url-abs'),
ac47f7ca
TO
193 'imageUploadURL' => array('setting-url-abs'),
194 'resourceBase' => array('setting-url-rel', 'userFrameworkResourceURL'),
195 'userFrameworkResourceURL' => array('setting-url-abs'),
c0a1f187 196
9e1e6020 197 // "callback" properties are generated on-demand by calling a function.
c0a1f187 198 'geocodeMethod' => array('callback', 'CRM_Utils_Geocode', 'getProviderClass'),
d7c217ae 199 'defaultCurrencySymbol' => array('callback', 'CRM_Core_BAO_Country', 'getDefaultCurrencySymbol'),
c0a1f187
TO
200 );
201 }
202
203 public function __get($k) {
204 if (!isset($this->map[$k])) {
205 throw new \CRM_Core_Exception("Cannot read unrecognized property CRM_Core_Config::\${$k}.");
206 }
7dba62da
TO
207 if (isset($this->cache[$k])) {
208 return $this->cache[$k];
209 }
e3d28c74
TO
210
211 $type = $this->map[$k][0];
212 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
c0a1f187
TO
213
214 switch ($type) {
215 case 'setting':
23bb9c85 216 return $this->getSettings()->get($name);
c0a1f187
TO
217
218 case 'setting-path':
ac47f7ca 219 // Array(0 => $type, 1 => $setting, 2 => $actions).
e3d28c74 220 $value = $this->getSettings()->get($name);
e3d28c74
TO
221 $value = Civi::paths()->getPath($value);
222 if ($value) {
223 $value = CRM_Utils_File::addTrailingSlash($value);
ac47f7ca 224 if (isset($this->map[$k][2]) && in_array('mkdir', $this->map[$k][2])) {
e3d28c74
TO
225 CRM_Utils_File::createDir($value);
226 }
ac47f7ca 227 if (isset($this->map[$k][2]) && in_array('restrict', $this->map[$k][2])) {
e3d28c74
TO
228 CRM_Utils_File::restrictAccess($value);
229 }
230 }
7dba62da 231 $this->cache[$k] = $value;
e3d28c74
TO
232 return $value;
233
234 case 'setting-url-abs':
e3d28c74 235 case 'setting-url-rel':
4c2e54d8 236 $type = (strstr($type, 'abs')) ? 'absolute' : 'relative';
237 $value = CRM_Utils_File::addTrailingSlash($this->getSettings()->get($name));
238 $this->cache[$k] = Civi::paths()->getUrl($value, $type);
7dba62da 239 return $this->cache[$k];
c0a1f187
TO
240
241 case 'runtime':
7f835399 242 return \Civi\Core\Container::getBootService('runtime')->{$name};
c0a1f187 243
d4330c62
TO
244 case 'boot-svc':
245 $this->cache[$k] = \Civi\Core\Container::getBootService($name);
246 return $this->cache[$k];
247
c0a1f187
TO
248 case 'local':
249 $this->initLocals();
250 return $this->locals[$name];
251
d4330c62
TO
252 case 'user-system':
253 $userSystem = \Civi\Core\Container::getBootService('userSystem');
254 $this->cache[$k] = call_user_func(array($userSystem, $name));
255 return $this->cache[$k];
256
c0a1f187
TO
257 case 'service':
258 return \Civi::service($name);
259
260 case 'callback':
261 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
262 if (!isset($this->map[$k][1], $this->map[$k][2])) {
263 throw new \CRM_Core_Exception("Cannot find getter for property CRM_Core_Config::\${$k}");
264 }
265 return \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][2]), array($k));
266
267 default:
268 throw new \CRM_Core_Exception("Cannot read property CRM_Core_Config::\${$k} ($type)");
269 }
270 }
271
272 public function __set($k, $v) {
273 if (!isset($this->map[$k])) {
274 throw new \CRM_Core_Exception("Cannot set unrecognized property CRM_Core_Config::\${$k}");
275 }
7dba62da 276 unset($this->cache[$k]);
dc640254
TO
277 $type = $this->map[$k][0];
278 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
c0a1f187
TO
279
280 switch ($type) {
281 case 'setting':
dc640254
TO
282 case 'setting-path':
283 case 'setting-url-abs':
284 case 'setting-url-rel':
d4330c62 285 case 'user-system':
c0a1f187 286 case 'runtime':
dc640254 287 case 'callback':
6504e96d 288 case 'boot-svc':
dc640254
TO
289 // In the past, changes to $config were not persisted automatically.
290 $this->cache[$name] = $v;
c0a1f187
TO
291 return;
292
293 case 'local':
294 $this->initLocals();
295 $this->locals[$name] = $v;
296 return;
297
c0a1f187
TO
298 default:
299 throw new \CRM_Core_Exception("Cannot set property CRM_Core_Config::\${$k} ($type)");
300 }
301 }
302
303 public function __isset($k) {
304 return isset($this->map[$k]);
305 }
306
307 public function __unset($k) {
308 if (!isset($this->map[$k])) {
309 throw new \CRM_Core_Exception("Cannot unset unrecognized property CRM_Core_Config::\${$k}");
310 }
7dba62da 311 unset($this->cache[$k]);
dc640254
TO
312 $type = $this->map[$k][0];
313 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
c0a1f187
TO
314
315 switch ($type) {
316 case 'setting':
317 case 'setting-path':
e3d28c74
TO
318 case 'setting-url-abs':
319 case 'setting-url-rel':
23bb9c85 320 $this->getSettings()->revert($k);
c0a1f187
TO
321 return;
322
323 case 'local':
324 $this->initLocals();
325 $this->locals[$name] = NULL;
326 return;
327
328 case 'callback':
329 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
330 if (!isset($this->map[$k][1], $this->map[$k][4])) {
331 throw new \CRM_Core_Exception("Cannot find unsetter for property CRM_Core_Config::\${$k}");
332 }
333 \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][4]), array($k));
334 return;
335
336 default:
337 throw new \CRM_Core_Exception("Cannot unset property CRM_Core_Config::\${$k} ($type)");
338 }
339 }
340
23bb9c85
TO
341 /**
342 * @return \Civi\Core\SettingsBag
343 */
344 protected function getSettings() {
345 if ($this->settings === NULL) {
346 $this->settings = Civi::settings();
347 }
348 return $this->settings;
349 }
350
c0a1f187
TO
351 private function initLocals() {
352 if ($this->locals === NULL) {
353 $this->locals = array(
354 'inCiviCRM' => FALSE,
355 'doNotResetCache' => 0,
5f900b59 356 'keyDisable' => FALSE,
c0a1f187
TO
357 'initialized' => FALSE,
358 'userFrameworkFrontend' => FALSE,
d4330c62 359 'userPermissionTemp' => NULL,
c0a1f187
TO
360 );
361 }
362 }
363
364}