377c035f213660c7874eb8bc8d2d46062d360553
[civicrm-core.git] / CRM / Core / Config / MagicMerge.php
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 */
47 class 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
57 private $runtime, $locals, $settings;
58
59 public function __construct() {
60 $this->map = self::getPropertyMap();
61 }
62
63 public function __wakeup() {
64 $this->map = self::getPropertyMap();
65 }
66
67 /**
68 * @return array
69 */
70 public static function getPropertyMap() {
71 // Each mapping: $propertyName => Array(0 => $type, 1 => $foreignName|NULL, ...).
72 // If $foreignName is omitted/null, then it's assumed to match the $propertyName.
73 // Other parameters may be specified, depending on the type.
74 return array(
75 'backtrace' => array('setting'),
76 'countryLimit' => array('setting'),
77 'dashboardCacheTimeout' => array('setting'),
78 'dateInputFormat' => array('setting'),
79 'dateformatDatetime' => array('setting'),
80 'dateformatFull' => array('setting'),
81 'dateformatPartial' => array('setting'),
82 'dateformatTime' => array('setting'),
83 'dateformatYear' => array('setting'),
84 'debug' => array('setting', 'debug_enabled'), // renamed.
85 'defaultContactCountry' => array('setting'),
86 'defaultContactStateProvince' => array('setting'),
87 'defaultCurrency' => array('setting'),
88 'defaultSearchProfileID' => array('setting'),
89 'doNotAttachPDFReceipt' => array('setting'),
90 'empoweredBy' => array('setting'),
91 'enableComponents' => array('setting', 'enable_components'), // renamed.
92 'enableSSL' => array('setting'),
93 'fatalErrorHandler' => array('setting'),
94 'fieldSeparator' => array('setting'),
95 'fiscalYearStart' => array('setting'),
96 'geoAPIKey' => array('setting'),
97 'geoProvider' => array('setting'),
98 'includeAlphabeticalPager' => array('setting'),
99 'includeEmailInName' => array('setting'),
100 'includeNickNameInName' => array('setting'),
101 'includeOrderByClause' => array('setting'),
102 'includeWildCardInName' => array('setting'),
103 'inheritLocale' => array('setting'),
104 'languageLimit' => array('setting'),
105 'lcMessages' => array('setting'),
106 'legacyEncoding' => array('setting'),
107 'logging' => array('setting'),
108 'mailThrottleTime' => array('setting'),
109 'mailerBatchLimit' => array('setting'),
110 'mailerJobSize' => array('setting'),
111 'mailerJobsMax' => array('setting'),
112 'mapAPIKey' => array('setting'),
113 'mapProvider' => array('setting'),
114 'maxFileSize' => array('setting'),
115 'maxAttachments' => array('setting', 'max_attachments'), // renamed.
116 'monetaryDecimalPoint' => array('setting'),
117 'monetaryThousandSeparator' => array('setting'),
118 'moneyformat' => array('setting'),
119 'moneyvalueformat' => array('setting'),
120 'provinceLimit' => array('setting'),
121 'recaptchaOptions' => array('setting'),
122 'recaptchaPublicKey' => array('setting'),
123 'recaptchaPrivateKey' => array('setting'),
124 'secondDegRelPermissions' => array('setting'),
125 'smartGroupCacheTimeout' => array('setting'),
126 'timeInputFormat' => array('setting'),
127 'userFrameworkLogging' => array('setting'),
128 'userFrameworkUsersTableName' => array('setting'),
129 'verpSeparator' => array('setting'),
130 'wkhtmltopdfPath' => array('setting'),
131 'wpBasePage' => array('setting'),
132 'wpLoadPhp' => array('setting'),
133
134 'doNotResetCache' => array('local'),
135 'inCiviCRM' => array('local'),
136 'userFrameworkFrontend' => array('local'),
137 'initialized' => array('local'),
138
139 'dsn' => array('runtime'),
140 'userFramework' => array('runtime'),
141 'userFrameworkBaseURL' => array('runtime'),
142 'userFrameworkClass' => array('runtime'),
143 'userFrameworkDSN' => array('runtime'),
144 'useFrameworkRelativeBase' => array('runtime', 'useFrameworkRelativeBase'),
145 'userFrameworkURLVar' => array('runtime'),
146 'userPermissionClass' => array('runtime'),
147 'userPermissionTemp' => array('runtime'),
148 'userSystem' => array('runtime'),
149 'userHookClass' => array('runtime'),
150 'cleanURL' => array('runtime'),
151 'configAndLogDir' => array('runtime'),
152 'templateCompileDir' => array('runtime'),
153 'templateDir' => array('runtime'),
154
155 'customFileUploadDir' => array('setting-path', NULL, '[civicrm.files]/custom/', array('mkdir', 'restrict')),
156 'customPHPPathDir' => array('setting-path'),
157 'customTemplateDir' => array('setting-path'),
158 'extensionsDir' => array('setting-path'),
159 'imageUploadDir' => array('setting-path', NULL, '[civicrm.files]/persist/contribute/', array('mkdir')),
160 'uploadDir' => array('setting-path', NULL, '[civicrm.files]/upload/', array('mkdir', 'restrict')),
161
162 'customCSSURL' => array('setting-url-abs'),
163 'extensionsURL' => array('setting-url-abs'),
164 'imageUploadURL' => array('setting-url-abs', NULL, '[civicrm.files]/persist/contribute/'),
165 'resourceBase' => array('setting-url-rel', 'userFrameworkResourceURL', '[civicrm]/.'),
166 'userFrameworkResourceURL' => array('setting-url-abs', NULL, '[civicrm]/.'),
167
168 'geocodeMethod' => array('callback', 'CRM_Utils_Geocode', 'getProviderClass'),
169 'defaultCurrencySymbol' => array('callback', 'CRM_Core_Config_Defaults', 'getDefaultCurrencySymbol'),
170 );
171 }
172
173 public function __get($k) {
174 if (!isset($this->map[$k])) {
175 throw new \CRM_Core_Exception("Cannot read unrecognized property CRM_Core_Config::\${$k}.");
176 }
177
178 $type = $this->map[$k][0];
179 $name = isset($this->map[$k][1]) ? $this->map[$k][1] : $k;
180
181 switch ($type) {
182 case 'setting':
183 return $this->getSettings()->get($name);
184
185 case 'setting-path':
186 // Array(0 => $type, 1 => $setting, 2 => $default, 3 => $actions).
187 $value = $this->getSettings()->get($name);
188 if (empty($value) && isset($this->map[$k][2])) {
189 $value = $this->map[$k][2];
190 }
191 $value = Civi::paths()->getPath($value);
192 if ($value) {
193 $value = CRM_Utils_File::addTrailingSlash($value);
194 if (isset($this->map[$k][3]) && in_array('mkdir', $this->map[$k][3])) {
195 CRM_Utils_File::createDir($value);
196 }
197 if (isset($this->map[$k][3]) && in_array('restrict', $this->map[$k][3])) {
198 CRM_Utils_File::restrictAccess($value);
199 }
200 }
201 return $value;
202
203 case 'setting-url-abs':
204 // Array(0 => $type, 1 => $setting, 2 => $default).
205 $value = $this->getSettings()->get($name);
206 if (empty($value) && isset($this->map[$k][2])) {
207 $value = $this->map[$k][2];
208 }
209 return Civi::paths()->getUrl($value, 'absolute');
210
211 case 'setting-url-rel':
212 // Array(0 => $type, 1 => $setting, 2 => $default).
213 $value = $this->getSettings()->get($name);
214 if (empty($value) && isset($this->map[$k][2])) {
215 $value = $this->map[$k][2];
216 }
217 return Civi::paths()->getUrl($value, 'relative');
218
219 case 'runtime':
220 return $this->getRuntime()->{$name};
221
222 case 'local':
223 $this->initLocals();
224 return $this->locals[$name];
225
226 case 'service':
227 return \Civi::service($name);
228
229 case 'callback':
230 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
231 if (!isset($this->map[$k][1], $this->map[$k][2])) {
232 throw new \CRM_Core_Exception("Cannot find getter for property CRM_Core_Config::\${$k}");
233 }
234 return \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][2]), array($k));
235
236 default:
237 throw new \CRM_Core_Exception("Cannot read property CRM_Core_Config::\${$k} ($type)");
238 }
239 }
240
241 public function __set($k, $v) {
242 if (!isset($this->map[$k])) {
243 throw new \CRM_Core_Exception("Cannot set unrecognized property CRM_Core_Config::\${$k}");
244 }
245 list ($type, $name) = $this->map[$k];
246
247 switch ($type) {
248 case 'setting':
249 $this->getSettings()->set($name, $v);
250 return;
251
252 case 'runtime':
253 $this->getRuntime()->{$name} = $v;
254 return;
255
256 case 'local':
257 $this->initLocals();
258 $this->locals[$name] = $v;
259 return;
260
261 case 'callback':
262 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
263 if (!isset($this->map[$k][1], $this->map[$k][3])) {
264 throw new \CRM_Core_Exception("Cannot find setter for property CRM_Core_Config::\${$k}");
265 }
266 \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][3]), array($k, $v));
267 return;
268
269 default:
270 throw new \CRM_Core_Exception("Cannot set property CRM_Core_Config::\${$k} ($type)");
271 }
272 }
273
274 public function __isset($k) {
275 return isset($this->map[$k]);
276 }
277
278 public function __unset($k) {
279 if (!isset($this->map[$k])) {
280 throw new \CRM_Core_Exception("Cannot unset unrecognized property CRM_Core_Config::\${$k}");
281 }
282 list ($type, $name) = $this->map[$k];
283
284 switch ($type) {
285 case 'setting':
286 case 'setting-path':
287 case 'setting-url-abs':
288 case 'setting-url-rel':
289 $this->getSettings()->revert($k);
290 return;
291
292 case 'local':
293 $this->initLocals();
294 $this->locals[$name] = NULL;
295 return;
296
297 case 'callback':
298 // Array(0 => $type, 1 => $obj, 2 => $getter, 3 => $setter, 4 => $unsetter).
299 if (!isset($this->map[$k][1], $this->map[$k][4])) {
300 throw new \CRM_Core_Exception("Cannot find unsetter for property CRM_Core_Config::\${$k}");
301 }
302 \Civi\Core\Resolver::singleton()->call(array($this->map[$k][1], $this->map[$k][4]), array($k));
303 return;
304
305 default:
306 throw new \CRM_Core_Exception("Cannot unset property CRM_Core_Config::\${$k} ($type)");
307 }
308 }
309
310 /**
311 * @return CRM_Core_Config_Runtime
312 */
313 protected function getRuntime() {
314 if ($this->runtime === NULL) {
315 $this->runtime = new CRM_Core_Config_Runtime();
316 }
317 return $this->runtime;
318 }
319
320 /**
321 * @return \Civi\Core\SettingsBag
322 */
323 protected function getSettings() {
324 if ($this->settings === NULL) {
325 $this->settings = Civi::settings();
326 }
327 return $this->settings;
328 }
329
330 private function initLocals() {
331 if ($this->locals === NULL) {
332 $this->locals = array(
333 'inCiviCRM' => FALSE,
334 'doNotResetCache' => 0,
335 'initialized' => FALSE,
336 'userFrameworkFrontend' => FALSE,
337 );
338 }
339 }
340
341 }