00e6caf965f0c100acd45ca18a3bbc3de06db982
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Web / RequestBuilder.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Web;
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 * Builds a web request.
32 */
33 class RequestBuilder implements \TYPO3\CMS\Core\SingletonInterface {
34
35 /**
36 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
37 */
38 protected $objectManager;
39
40 /**
41 * This is the vendor name of the extension
42 *
43 * @var string
44 */
45 protected $vendorName;
46
47 /**
48 * This is a unique key for a plugin (not the extension key!)
49 *
50 * @var string
51 */
52 protected $pluginName = 'plugin';
53
54 /**
55 * The name of the extension (in UpperCamelCase)
56 *
57 * @var string
58 */
59 protected $extensionName;
60
61 /**
62 * The default controller name
63 *
64 * @var string
65 */
66 protected $defaultControllerName;
67
68 /**
69 * The default format of the response object
70 *
71 * @var string
72 */
73 protected $defaultFormat = 'html';
74
75 /**
76 * The allowed actions of the controller. This actions can be called via $_GET and $_POST.
77 *
78 * @var array
79 */
80 protected $allowedControllerActions = array();
81
82 /**
83 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
84 */
85 protected $configurationManager;
86
87 /**
88 * @var \TYPO3\CMS\Extbase\Service\ExtensionService
89 */
90 protected $extensionService;
91
92 /**
93 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
94 */
95 protected $environmentService;
96
97 /**
98 * @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
99 */
100 public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager) {
101 $this->configurationManager = $configurationManager;
102 }
103
104 /**
105 * Injects the object manager
106 *
107 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
108 * @return void
109 */
110 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager) {
111 $this->objectManager = $objectManager;
112 }
113
114 /**
115 * @param \TYPO3\CMS\Extbase\Service\ExtensionService $extensionService
116 * @return void
117 */
118 public function injectExtensionService(\TYPO3\CMS\Extbase\Service\ExtensionService $extensionService) {
119 $this->extensionService = $extensionService;
120 }
121
122 /**
123 * @param \TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService
124 * @return void
125 */
126 public function injectEnvironmentService(\TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService) {
127 $this->environmentService = $environmentService;
128 }
129
130 /**
131 * @throws \TYPO3\CMS\Extbase\Mvc\Exception
132 * @return void
133 */
134 protected function loadDefaultValues() {
135 $configuration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
136 if (empty($configuration['extensionName'])) {
137 throw new \TYPO3\CMS\Extbase\Mvc\Exception('"extensionName" is not properly configured. Request can\'t be dispatched!', 1289843275);
138 }
139 if (empty($configuration['pluginName'])) {
140 throw new \TYPO3\CMS\Extbase\Mvc\Exception('"pluginName" is not properly configured. Request can\'t be dispatched!', 1289843277);
141 }
142 if (!empty($configuration['vendorName'])) {
143 $this->vendorName = $configuration['vendorName'];
144 } else {
145 $this->vendorName = NULL;
146 }
147 $this->extensionName = $configuration['extensionName'];
148 $this->pluginName = $configuration['pluginName'];
149 $this->defaultControllerName = current(array_keys($configuration['controllerConfiguration']));
150 $this->allowedControllerActions = array();
151 foreach ($configuration['controllerConfiguration'] as $controllerName => $controllerActions) {
152 $this->allowedControllerActions[$controllerName] = $controllerActions['actions'];
153 }
154 if (!empty($configuration['format'])) {
155 $this->defaultFormat = $configuration['format'];
156 }
157 }
158
159 /**
160 * Builds a web request object from the raw HTTP information and the configuration
161 *
162 * @return \TYPO3\CMS\Extbase\Mvc\Web\Request The web request as an object
163 */
164 public function build() {
165 $this->loadDefaultValues();
166 $pluginNamespace = $this->extensionService->getPluginNamespace($this->extensionName, $this->pluginName);
167 $parameters = \TYPO3\CMS\Core\Utility\GeneralUtility::_GPmerged($pluginNamespace);
168 $files = $this->untangleFilesArray($_FILES);
169 if (isset($files[$pluginNamespace]) && is_array($files[$pluginNamespace])) {
170 $parameters = \TYPO3\CMS\Extbase\Utility\ArrayUtility::arrayMergeRecursiveOverrule($parameters, $files[$pluginNamespace]);
171 }
172 $controllerName = $this->resolveControllerName($parameters);
173 $actionName = $this->resolveActionName($controllerName, $parameters);
174 /** @var $request \TYPO3\CMS\Extbase\Mvc\Web\Request */
175 $request = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request');
176 if ($this->vendorName !== NULL) {
177 $request->setControllerVendorName($this->vendorName);
178 }
179 $request->setPluginName($this->pluginName);
180 $request->setControllerExtensionName($this->extensionName);
181 $request->setControllerName($controllerName);
182 $request->setControllerActionName($actionName);
183 $request->setRequestUri(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'));
184 $request->setBaseUri(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL'));
185 $request->setMethod($this->environmentService->getServerRequestMethod());
186 if (is_string($parameters['format']) && strlen($parameters['format'])) {
187 $request->setFormat(filter_var($parameters['format'], FILTER_SANITIZE_STRING));
188 } else {
189 $request->setFormat($this->defaultFormat);
190 }
191 foreach ($parameters as $argumentName => $argumentValue) {
192 $request->setArgument($argumentName, $argumentValue);
193 }
194 return $request;
195 }
196
197 /**
198 * Returns the current ControllerName extracted from given $parameters.
199 * If no controller is specified, the defaultControllerName will be returned.
200 * If that's not available, an exception is thrown.
201 *
202 * @param array $parameters
203 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidControllerNameException
204 * @throws \TYPO3\CMS\Extbase\Mvc\Exception if the controller could not be resolved
205 * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
206 * @return string
207 */
208 protected function resolveControllerName(array $parameters) {
209 if (!isset($parameters['controller']) || strlen($parameters['controller']) === 0) {
210 if (strlen($this->defaultControllerName) === 0) {
211 throw new \TYPO3\CMS\Extbase\Mvc\Exception('The default controller for extension "' . $this->extensionName . '" and plugin "' . $this->pluginName . '" can not be determined. Please check for TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.', 1316104317);
212 }
213 return $this->defaultControllerName;
214 }
215 $allowedControllerNames = array_keys($this->allowedControllerActions);
216 if (!in_array($parameters['controller'], $allowedControllerNames)) {
217 $configuration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
218 if (isset($configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) && (boolean) $configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) {
219 throw new \TYPO3\CMS\Core\Error\Http\PageNotFoundException('The requested resource was not found', 1313857897);
220 } elseif (isset($configuration['mvc']['callDefaultActionIfActionCantBeResolved']) && (boolean) $configuration['mvc']['callDefaultActionIfActionCantBeResolved']) {
221 return $this->defaultControllerName;
222 }
223 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidControllerNameException('The controller "' . $parameters['controller'] . '" is not allowed by this plugin. Please check for TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.', 1313855173);
224 }
225 return filter_var($parameters['controller'], FILTER_SANITIZE_STRING);
226 }
227
228 /**
229 * Returns the current actionName extracted from given $parameters.
230 * If no action is specified, the defaultActionName will be returned.
231 * If that's not available or the specified action is not defined in the current plugin, an exception is thrown.
232 *
233 * @param string $controllerName
234 * @param array $parameters
235 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidActionNameException
236 * @throws \TYPO3\CMS\Extbase\Mvc\Exception
237 * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
238 * @return string
239 */
240 protected function resolveActionName($controllerName, array $parameters) {
241 $defaultActionName = is_array($this->allowedControllerActions[$controllerName]) ? current($this->allowedControllerActions[$controllerName]) : '';
242 if (!isset($parameters['action']) || strlen($parameters['action']) === 0) {
243 if (strlen($defaultActionName) === 0) {
244 throw new \TYPO3\CMS\Extbase\Mvc\Exception('The default action can not be determined for controller "' . $controllerName . '". Please check TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.', 1295479651);
245 }
246 return $defaultActionName;
247 }
248 $actionName = $parameters['action'];
249 $allowedActionNames = $this->allowedControllerActions[$controllerName];
250 if (!in_array($actionName, $allowedActionNames)) {
251 $configuration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
252 if (isset($configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) && (boolean) $configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) {
253 throw new \TYPO3\CMS\Core\Error\Http\PageNotFoundException('The requested resource was not found', 1313857897);
254 } elseif (isset($configuration['mvc']['callDefaultActionIfActionCantBeResolved']) && (boolean) $configuration['mvc']['callDefaultActionIfActionCantBeResolved']) {
255 return $defaultActionName;
256 }
257 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidActionNameException('The action "' . $actionName . '" (controller "' . $controllerName . '") is not allowed by this plugin. Please check TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.', 1313855175);
258 }
259 return filter_var($actionName, FILTER_SANITIZE_STRING);
260 }
261
262 /**
263 * Transforms the convoluted _FILES superglobal into a manageable form.
264 *
265 * @param array $convolutedFiles The _FILES superglobal
266 * @return array Untangled files
267 * @see TYPO3\FLOW3\Utility\Environment
268 */
269 protected function untangleFilesArray(array $convolutedFiles) {
270 $untangledFiles = array();
271 $fieldPaths = array();
272 foreach ($convolutedFiles as $firstLevelFieldName => $fieldInformation) {
273 if (!is_array($fieldInformation['error'])) {
274 $fieldPaths[] = array($firstLevelFieldName);
275 } else {
276 $newFieldPaths = $this->calculateFieldPaths($fieldInformation['error'], $firstLevelFieldName);
277 array_walk($newFieldPaths, function (&$value, $key) {
278 $value = explode('/', $value);
279 });
280 $fieldPaths = array_merge($fieldPaths, $newFieldPaths);
281 }
282 }
283 foreach ($fieldPaths as $fieldPath) {
284 if (count($fieldPath) === 1) {
285 $fileInformation = $convolutedFiles[$fieldPath[0]];
286 } else {
287 $fileInformation = array();
288 foreach ($convolutedFiles[$fieldPath[0]] as $key => $subStructure) {
289 $fileInformation[$key] = \TYPO3\CMS\Extbase\Utility\ArrayUtility::getValueByPath($subStructure, array_slice($fieldPath, 1));
290 }
291 }
292 $untangledFiles = \TYPO3\CMS\Extbase\Utility\ArrayUtility::setValueByPath($untangledFiles, $fieldPath, $fileInformation);
293 }
294 return $untangledFiles;
295 }
296
297 /**
298 * Returns an array of all possibles "field paths" for the given array.
299 *
300 * @param array $structure The array to walk through
301 * @param string $firstLevelFieldName
302 * @return array An array of paths (as strings) in the format "key1/key2/key3" ...
303 */
304 protected function calculateFieldPaths(array $structure, $firstLevelFieldName = NULL) {
305 $fieldPaths = array();
306 if (is_array($structure)) {
307 foreach ($structure as $key => $subStructure) {
308 $fieldPath = ($firstLevelFieldName !== NULL ? $firstLevelFieldName . '/' : '') . $key;
309 if (is_array($subStructure)) {
310 foreach ($this->calculateFieldPaths($subStructure) as $subFieldPath) {
311 $fieldPaths[] = $fieldPath . '/' . $subFieldPath;
312 }
313 } else {
314 $fieldPaths[] = $fieldPath;
315 }
316 }
317 }
318 return $fieldPaths;
319 }
320 }
321
322 ?>