[FEATURE] Install tool: Remove obsolete keys from LocalConfiguration
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Configuration / ConfigurationManager.php
1 <?php
2 namespace TYPO3\CMS\Core\Configuration;
3 use TYPO3\CMS\Core\Utility;
4
5 /***************************************************************
6 * Copyright notice
7 *
8 * (c) 2012-2013 Helge Funk <helge.funk@e-net.info>
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Handle loading and writing of global and local (instance specific)
29 * configuration.
30 *
31 * This class handles the access to the files
32 * - EXT:core/Configuration/DefaultConfiguration.php (default TYPO3_CONF_VARS)
33 * - typo3conf/LocalConfiguration.php (overrides of TYPO3_CONF_VARS)
34 * - typo3conf/AdditionalConfiguration.php (optional additional local code blocks)
35 * - typo3conf/localconf.php (legacy configuration file)
36 *
37 * @author Helge Funk <helge.funk@e-net.info>
38 */
39 class ConfigurationManager {
40
41 /**
42 * @var string Path to default TYPO3_CONF_VARS file, relative to PATH_site
43 */
44 protected $defaultConfigurationFile = 'typo3/sysext/core/Configuration/DefaultConfiguration.php';
45
46 /**
47 * @var string Path to local overload TYPO3_CONF_VARS file, relative to PATH_site
48 */
49 protected $localConfigurationFile = 'typo3conf/LocalConfiguration.php';
50
51 /**
52 * @var string Path to additional local file, relative to PATH_site
53 */
54 protected $additionalConfigurationFile = 'typo3conf/AdditionalConfiguration.php';
55
56 /**
57 * @var string Path to factory configuration file used during installation as LocalConfiguration boilerplate
58 */
59 protected $factoryConfigurationFile = 'typo3/sysext/core/Configuration/FactoryConfiguration.php';
60
61 /**
62 * @var string Path to possible additional factory configuration file delivered by packages
63 */
64 protected $additionalFactoryConfigurationFile = 'typo3conf/AdditionalFactoryConfiguration.php';
65
66 /**
67 * @var string Absolute path to typo3conf directory
68 */
69 protected $pathTypo3Conf = PATH_typo3conf;
70
71 /**
72 * Writing to these configuration pathes is always allowed,
73 * even if the requested sub path does not exist yet.
74 *
75 * @var array
76 */
77 protected $whiteListedLocalConfigurationPaths = array(
78 'EXT/extConf',
79 'EXTCONF',
80 'INSTALL/wizardDone',
81 'DB'
82 );
83
84 /**
85 * Return default configuration array
86 *
87 * @return array
88 */
89 public function getDefaultConfiguration() {
90 return require $this->getDefaultConfigurationFileLocation();
91 }
92
93 /**
94 * Get the file location of the default configuration file,
95 * currently the path and filename.
96 *
97 * @return string
98 * @access private
99 */
100 public function getDefaultConfigurationFileLocation() {
101 return PATH_site . $this->defaultConfigurationFile;
102 }
103
104 /**
105 * Return local configuration array typo3conf/LocalConfiguration.php
106 *
107 * @return array Content array of local configuration file
108 */
109 public function getLocalConfiguration() {
110 return require $this->getLocalConfigurationFileLocation();
111 }
112
113 /**
114 * Get the file location of the local configuration file,
115 * currently the path and filename.
116 *
117 * @return string
118 * @access private
119 */
120 public function getLocalConfigurationFileLocation() {
121 return PATH_site . $this->localConfigurationFile;
122 }
123
124 /**
125 * Get the file location of the additional configuration file,
126 * currently the path and filename.
127 *
128 * @return string
129 * @access private
130 */
131 public function getAdditionalConfigurationFileLocation() {
132 return PATH_site . $this->additionalConfigurationFile;
133 }
134
135 /**
136 * Get absolute file location of factory configuration file
137 *
138 * @return string
139 */
140 protected function getFactoryConfigurationFileLocation() {
141 return PATH_site . $this->factoryConfigurationFile;
142 }
143
144 /**
145 * Get absolute file location of factory configuration file
146 *
147 * @return string
148 */
149 protected function getAdditionalFactoryConfigurationFileLocation() {
150 return PATH_site . $this->additionalFactoryConfigurationFile;
151 }
152
153 /**
154 * Override local configuration with new values.
155 *
156 * @param array $configurationToMerge Override configuration array
157 * @return void
158 */
159 public function updateLocalConfiguration(array $configurationToMerge) {
160 $newLocalConfiguration = Utility\GeneralUtility::array_merge_recursive_overrule(
161 $this->getLocalConfiguration(),
162 $configurationToMerge
163 );
164 $this->writeLocalConfiguration($newLocalConfiguration);
165 }
166
167 /**
168 * Get a value at given path from default configuration
169 *
170 * @param string $path Path to search for
171 * @return mixed Value at path
172 */
173 public function getDefaultConfigurationValueByPath($path) {
174 return Utility\ArrayUtility::getValueByPath($this->getDefaultConfiguration(), $path);
175 }
176
177 /**
178 * Get a value at given path from local configuration
179 *
180 * @param string $path Path to search for
181 * @return mixed Value at path
182 */
183 public function getLocalConfigurationValueByPath($path) {
184 return Utility\ArrayUtility::getValueByPath($this->getLocalConfiguration(), $path);
185 }
186
187 /**
188 * Get a value from configuration, this is default configuration
189 * merged with local configuration
190 *
191 * @param string $path Path to search for
192 * @return mixed
193 */
194 public function getConfigurationValueByPath($path) {
195 return Utility\ArrayUtility::getValueByPath(
196 Utility\GeneralUtility::array_merge_recursive_overrule(
197 $this->getDefaultConfiguration(), $this->getLocalConfiguration()
198 ),
199 $path
200 );
201 }
202
203 /**
204 * Update a given path in local configuration to a new value.
205 *
206 * @param string $path Path to update
207 * @param mixed $value Value to set
208 * @return boolean TRUE on success
209 */
210 public function setLocalConfigurationValueByPath($path, $value) {
211 $result = FALSE;
212 if ($this->isValidLocalConfigurationPath($path)) {
213 $localConfiguration = $this->getLocalConfiguration();
214 $localConfiguration = Utility\ArrayUtility::setValueByPath($localConfiguration, $path, $value);
215 $result = $this->writeLocalConfiguration($localConfiguration);
216 }
217 return $result;
218 }
219
220 /**
221 * Update / set a list of path and value pairs in local configuration file
222 *
223 * @param array $pairs Key is path, value is value to set
224 * @return boolean TRUE on success
225 */
226 public function setLocalConfigurationValuesByPathValuePairs(array $pairs) {
227 $localConfiguration = $this->getLocalConfiguration();
228 foreach ($pairs as $path => $value) {
229 if ($this->isValidLocalConfigurationPath($path)) {
230 $localConfiguration = Utility\ArrayUtility::setValueByPath($localConfiguration, $path, $value);
231 }
232 }
233 return $this->writeLocalConfiguration($localConfiguration);
234 }
235
236 /**
237 * Remove keys from LocalConfiguration
238 *
239 * @param array $keys Array with key paths to remove from LocalConfiguration
240 * @return boolean TRUE if something was removed
241 */
242 public function removeLocalConfigurationKeysByPath(array $keys) {
243 $result = FALSE;
244 $localConfiguration = $this->getLocalConfiguration();
245 foreach ($keys as $path) {
246 // Remove key if path is within LocalConfiguration
247 if (Utility\ArrayUtility::isValidPath($localConfiguration, $path)) {
248 $result = TRUE;
249 $localConfiguration = Utility\ArrayUtility::removeByPath($localConfiguration, $path);
250 }
251 }
252 $this->writeLocalConfiguration($localConfiguration);
253 return $result;
254 }
255
256 /**
257 * Checks if the configuration can be written.
258 *
259 * @return boolean
260 * @access private
261 */
262 public function canWriteConfiguration() {
263 $result = TRUE;
264 if (!@is_writable($this->pathTypo3Conf)) {
265 $result = FALSE;
266 }
267 if (
268 file_exists($this->getLocalConfigurationFileLocation())
269 && !@is_writable($this->getLocalConfigurationFileLocation())
270 ) {
271 $result = FALSE;
272 }
273 return $result;
274 }
275
276 /**
277 * Reads the configuration array and exports it to the global variable
278 *
279 * @access private
280 * @throws \UnexpectedValueException
281 * @return void
282 */
283 public function exportConfiguration() {
284 if (@is_file($this->getLocalConfigurationFileLocation())) {
285 $localConfiguration = $this->getLocalConfiguration();
286 if (is_array($localConfiguration)) {
287 $GLOBALS['TYPO3_CONF_VARS'] = Utility\GeneralUtility::array_merge_recursive_overrule($this->getDefaultConfiguration(), $localConfiguration);
288 } else {
289 throw new \UnexpectedValueException('LocalConfiguration invalid.', 1349272276);
290 }
291 if (@is_file($this->getAdditionalConfigurationFileLocation())) {
292 require $this->getAdditionalConfigurationFileLocation();
293 }
294 } else {
295 // No LocalConfiguration (yet), load DefaultConfiguration only
296 $GLOBALS['TYPO3_CONF_VARS'] = $this->getDefaultConfiguration();
297 }
298 }
299
300 /**
301 * Write local configuration array to typo3conf/LocalConfiguration.php
302 *
303 * @param array $configuration The local configuration to be written
304 * @throws \RuntimeException
305 * @return boolean TRUE on success
306 * @access private
307 */
308 public function writeLocalConfiguration(array $configuration) {
309 $localConfigurationFile = $this->getLocalConfigurationFileLocation();
310 if (!$this->canWriteConfiguration()) {
311 throw new \RuntimeException(
312 $localConfigurationFile . ' is not writable.', 1346323822
313 );
314 }
315 $configuration = Utility\ArrayUtility::sortByKeyRecursive($configuration);
316 $result = Utility\GeneralUtility::writeFile(
317 $localConfigurationFile,
318 '<?php' . LF .
319 'return ' .
320 Utility\ArrayUtility::arrayExport(
321 Utility\ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($configuration)
322 ) .
323 ';' . LF .
324 '?>',
325 TRUE
326 );
327 return $result === FALSE ? FALSE : TRUE;
328 }
329
330 /**
331 * Write additional configuration array to typo3conf/AdditionalConfiguration.php
332 *
333 * @param array $additionalConfigurationLines The configuration lines to be written
334 * @throws \RuntimeException
335 * @return boolean TRUE on success
336 * @access private
337 */
338 public function writeAdditionalConfiguration(array $additionalConfigurationLines) {
339 $result = Utility\GeneralUtility::writeFile(
340 PATH_site . $this->additionalConfigurationFile,
341 '<?php' . LF .
342 implode(LF, $additionalConfigurationLines) . LF .
343 '?>'
344 );
345 return $result === FALSE ? FALSE : TRUE;
346 }
347
348 /**
349 * Uses FactoryConfiguration file and a possible AdditionalFactoryConfiguration
350 * file in typo3conf to create a basic LocalConfiguration.php. This is used
351 * by the install tool in an early step.
352 *
353 * @throws \RuntimeException
354 * @return void
355 * @access private
356 */
357 public function createLocalConfigurationFromFactoryConfiguration() {
358 if (file_exists($this->getLocalConfigurationFileLocation())) {
359 throw new \RuntimeException(
360 'LocalConfiguration.php exists already',
361 1364836026
362 );
363 }
364 $localConfigurationArray = require $this->getFactoryConfigurationFileLocation();
365 $additionalFactoryConfigurationFileLocation = $this->getAdditionalFactoryConfigurationFileLocation();
366 if (file_exists($additionalFactoryConfigurationFileLocation)) {
367 $additionalFactoryConfigurationArray = require $additionalFactoryConfigurationFileLocation;
368 $localConfigurationArray = Utility\GeneralUtility::array_merge_recursive_overrule(
369 $localConfigurationArray,
370 $additionalFactoryConfigurationArray
371 );
372 }
373 $this->writeLocalConfiguration($localConfigurationArray);
374 }
375
376 /**
377 * Check if access / write to given path in local configuration is allowed.
378 *
379 * @param string $path Path to search for
380 * @return boolean TRUE if access is allowed
381 */
382 protected function isValidLocalConfigurationPath($path) {
383 // Early return for white listed paths
384 foreach ($this->whiteListedLocalConfigurationPaths as $whiteListedPath) {
385 if (Utility\GeneralUtility::isFirstPartOfStr($path, $whiteListedPath)) {
386 return TRUE;
387 }
388 }
389 return Utility\ArrayUtility::isValidPath($this->getDefaultConfiguration(), $path);
390 }
391
392 }
393
394
395 ?>