[BUGFIX] storagePid is lost when persistence.recursive is set
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Configuration / AbstractConfigurationManager.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Configuration;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
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 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * Abstract base class for a general purpose configuration manager
32 */
33 abstract class AbstractConfigurationManager implements \TYPO3\CMS\Core\SingletonInterface {
34
35 /**
36 * Default backend storage PID
37 */
38 const DEFAULT_BACKEND_STORAGE_PID = 0;
39
40 /**
41 * Storage of the raw TypoScript configuration
42 *
43 * @var array
44 */
45 protected $configuration = array();
46
47 /**
48 * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
49 */
50 protected $contentObject;
51
52 /**
53 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
54 * @inject
55 */
56 protected $objectManager;
57
58 /**
59 * @var \TYPO3\CMS\Extbase\Service\TypoScriptService
60 * @inject
61 */
62 protected $typoScriptService;
63
64 /**
65 * name of the extension this Configuration Manager instance belongs to
66 *
67 * @var string
68 */
69 protected $extensionName;
70
71 /**
72 * name of the plugin this Configuration Manager instance belongs to
73 *
74 * @var string
75 */
76 protected $pluginName;
77
78 /**
79 * 1st level configuration cache
80 *
81 * @var array
82 */
83 protected $configurationCache = array();
84
85 /**
86 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
87 * @inject
88 */
89 protected $environmentService;
90
91 /**
92 * @param \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $contentObject
93 * @return void
94 */
95 public function setContentObject(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $contentObject = NULL) {
96 $this->contentObject = $contentObject;
97 }
98
99 /**
100 * @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer|NULL
101 */
102 public function getContentObject() {
103 if ($this->contentObject !== NULL) {
104 return $this->contentObject;
105 }
106 return NULL;
107 }
108
109 /**
110 * Sets the specified raw configuration coming from the outside.
111 * Note that this is a low level method and only makes sense to be used by Extbase internally.
112 *
113 * @param array $configuration The new configuration
114 * @return void
115 */
116 public function setConfiguration(array $configuration = array()) {
117 // reset 1st level cache
118 $this->configurationCache = array();
119 $this->extensionName = isset($configuration['extensionName']) ? $configuration['extensionName'] : NULL;
120 $this->pluginName = isset($configuration['pluginName']) ? $configuration['pluginName'] : NULL;
121 $this->configuration = $this->typoScriptService->convertTypoScriptArrayToPlainArray($configuration);
122 }
123
124 /**
125 * Loads the Extbase Framework configuration.
126 *
127 * The Extbase framework configuration HAS TO be retrieved using this method, as they are come from different places than the normal settings.
128 * Framework configuration is, in contrast to normal settings, needed for the Extbase framework to operate correctly.
129 *
130 * @param string $extensionName if specified, the configuration for the given extension will be returned (plugin.tx_extensionname)
131 * @param string $pluginName if specified, the configuration for the given plugin will be returned (plugin.tx_extensionname_pluginname)
132 * @return array the Extbase framework configuration
133 */
134 public function getConfiguration($extensionName = NULL, $pluginName = NULL) {
135 // 1st level cache
136 $configurationCacheKey = strtolower(($extensionName ?: $this->extensionName) . '_' . ($pluginName ?: $this->pluginName));
137 if (isset($this->configurationCache[$configurationCacheKey])) {
138 return $this->configurationCache[$configurationCacheKey];
139 }
140 $frameworkConfiguration = $this->getExtbaseConfiguration();
141 if (!isset($frameworkConfiguration['persistence']['storagePid'])) {
142 $frameworkConfiguration['persistence']['storagePid'] = $this->getDefaultBackendStoragePid();
143 }
144 // only merge $this->configuration and override switchableControllerActions when retrieving configuration of the current plugin
145 if ($extensionName === NULL || $extensionName === $this->extensionName && $pluginName === $this->pluginName) {
146 $pluginConfiguration = $this->getPluginConfiguration($this->extensionName, $this->pluginName);
147 $pluginConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($pluginConfiguration, $this->configuration);
148 $pluginConfiguration['controllerConfiguration'] = $this->getSwitchableControllerActions($this->extensionName, $this->pluginName);
149 if (isset($this->configuration['switchableControllerActions'])) {
150 $this->overrideSwitchableControllerActions($pluginConfiguration, $this->configuration['switchableControllerActions']);
151 }
152 } else {
153 $pluginConfiguration = $this->getPluginConfiguration($extensionName, $pluginName);
154 $pluginConfiguration['controllerConfiguration'] = $this->getSwitchableControllerActions($extensionName, $pluginName);
155 }
156 $frameworkConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($frameworkConfiguration, $pluginConfiguration);
157 // only load context specific configuration when retrieving configuration of the current plugin
158 if ($extensionName === NULL || $extensionName === $this->extensionName && $pluginName === $this->pluginName) {
159 $frameworkConfiguration = $this->getContextSpecificFrameworkConfiguration($frameworkConfiguration);
160 }
161
162 if (!empty($frameworkConfiguration['persistence']['storagePid'])) {
163 if (is_array($frameworkConfiguration['persistence']['storagePid'])) {
164 /**
165 * We simulate the frontend to enable the use of cObjects in
166 * stdWrap. Than we convert the configuration to normal TypoScript
167 * and apply the stdWrap to the storagePid
168 */
169 if (!$this->environmentService->isEnvironmentInFrontendMode()) {
170 \TYPO3\CMS\Extbase\Utility\FrontendSimulatorUtility::simulateFrontendEnvironment($this->getContentObject());
171 }
172 $conf = $this->typoScriptService->convertPlainArrayToTypoScriptArray($frameworkConfiguration['persistence']);
173 $frameworkConfiguration['persistence']['storagePid'] = $GLOBALS['TSFE']->cObj->stdWrap($conf['storagePid'], $conf['storagePid.']);
174 if (!$this->environmentService->isEnvironmentInFrontendMode()) {
175 \TYPO3\CMS\Extbase\Utility\FrontendSimulatorUtility::resetFrontendEnvironment();
176 }
177 }
178
179 if (!empty($frameworkConfiguration['persistence']['recursive'])) {
180 // All implementations of getTreeList allow to pass the ids negative to include them into the result
181 // otherwise only childpages are returned
182 $storagePids = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid']);
183 array_walk($storagePids, function (&$storagePid) {
184 if ($storagePid > 0) {
185 $storagePid = -$storagePid;
186 }
187 });
188 $frameworkConfiguration['persistence']['storagePid'] = $this->getRecursiveStoragePids(
189 implode(',', $storagePids),
190 (int) $frameworkConfiguration['persistence']['recursive']
191 );
192 }
193 }
194 // 1st level cache
195 $this->configurationCache[$configurationCacheKey] = $frameworkConfiguration;
196 return $frameworkConfiguration;
197 }
198
199 /**
200 * Returns the TypoScript configuration found in config.tx_extbase
201 *
202 * @return array
203 */
204 protected function getExtbaseConfiguration() {
205 $setup = $this->getTypoScriptSetup();
206 $extbaseConfiguration = array();
207 if (isset($setup['config.']['tx_extbase.'])) {
208 $extbaseConfiguration = $this->typoScriptService->convertTypoScriptArrayToPlainArray($setup['config.']['tx_extbase.']);
209 }
210 return $extbaseConfiguration;
211 }
212
213 /**
214 * Returns the default backend storage pid
215 *
216 * @return string
217 */
218 public function getDefaultBackendStoragePid() {
219 return self::DEFAULT_BACKEND_STORAGE_PID;
220 }
221
222 /**
223 * @param array &$frameworkConfiguration
224 * @param array $switchableControllerActions
225 * @return void
226 */
227 protected function overrideSwitchableControllerActions(array &$frameworkConfiguration, array $switchableControllerActions) {
228 $overriddenSwitchableControllerActions = array();
229 foreach ($switchableControllerActions as $controllerName => $actions) {
230 if (!isset($frameworkConfiguration['controllerConfiguration'][$controllerName])) {
231 continue;
232 }
233 $overriddenSwitchableControllerActions[$controllerName] = array('actions' => $actions);
234 $nonCacheableActions = $frameworkConfiguration['controllerConfiguration'][$controllerName]['nonCacheableActions'];
235 if (!is_array($nonCacheableActions)) {
236 // There are no non-cacheable actions, thus we can directly continue
237 // with the next controller name.
238 continue;
239 }
240 $overriddenNonCacheableActions = array_intersect($nonCacheableActions, $actions);
241 if (!empty($overriddenNonCacheableActions)) {
242 $overriddenSwitchableControllerActions[$controllerName]['nonCacheableActions'] = $overriddenNonCacheableActions;
243 }
244 }
245 $frameworkConfiguration['controllerConfiguration'] = $overriddenSwitchableControllerActions;
246 }
247
248 /**
249 * The context specific configuration returned by this method
250 * will override the framework configuration which was
251 * obtained from TypoScript. This can be used f.e. to override the storagePid
252 * with the value set inside the Plugin Instance.
253 *
254 * WARNING: Make sure this method ALWAYS returns an array!
255 *
256 * @param array $frameworkConfiguration The framework configuration until now
257 * @return array context specific configuration which will override the configuration obtained by TypoScript
258 */
259 abstract protected function getContextSpecificFrameworkConfiguration(array $frameworkConfiguration);
260
261 /**
262 * Returns TypoScript Setup array from current Environment.
263 *
264 * @return array the TypoScript setup
265 */
266 abstract public function getTypoScriptSetup();
267
268 /**
269 * Returns the TypoScript configuration found in plugin.tx_yourextension_yourplugin / module.tx_yourextension_yourmodule
270 * merged with the global configuration of your extension from plugin.tx_yourextension / module.tx_yourextension
271 *
272 * @param string $extensionName
273 * @param string $pluginName in FE mode this is the specified plugin name, in BE mode this is the full module signature
274 * @return array
275 */
276 abstract protected function getPluginConfiguration($extensionName, $pluginName = NULL);
277
278 /**
279 * Returns the configured controller/action pairs of the specified plugin/module in the format
280 * array(
281 * 'Controller1' => array('action1', 'action2'),
282 * 'Controller2' => array('action3', 'action4')
283 * )
284 *
285 * @param string $extensionName
286 * @param string $pluginName in FE mode this is the specified plugin name, in BE mode this is the full module signature
287 * @return array
288 */
289 abstract protected function getSwitchableControllerActions($extensionName, $pluginName);
290
291 /**
292 * The implementation of the methods to return a list of storagePid that are below a certain
293 * storage pid.
294 *
295 * @param string $storagePid Storage PID to start at; multiple PIDs possible as comma-separated list
296 * @param integer $recursionDepth Maximum number of levels to search, 0 to disable recursive lookup
297 * @return string storage PIDs
298 */
299 abstract protected function getRecursiveStoragePids($storagePid, $recursionDepth = 0);
300
301 }
302
303 ?>