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