[BUGFIX] Allow non critical request arguments with @
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Request.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc;
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 use TYPO3\CMS\Core\Utility\ClassNamingUtility;
18
19 /**
20 * Represents a generic request.
21 *
22 * @api
23 */
24 class Request implements RequestInterface
25 {
26 const PATTERN_MATCH_FORMAT = '/^[a-z0-9]{1,5}$/';
27
28 /**
29 * Pattern after which the controller object name is built
30 *
31 * @var string
32 */
33 protected $controllerObjectNamePattern = 'Tx_@extension_@subpackage_Controller_@controllerController';
34
35 /**
36 * Pattern after which the namespaced controller object name is built
37 *
38 * @var string
39 */
40 protected $namespacedControllerObjectNamePattern = '@vendor\@extension\@subpackage\Controller\@controllerController';
41
42 /**
43 * @var string Key of the plugin which identifies the plugin. It must be a string containing [a-z0-9]
44 */
45 protected $pluginName = '';
46
47 /**
48 * @var string Name of the extension which is supposed to handle this request. This is the extension name converted to UpperCamelCase
49 */
50 protected $controllerExtensionName = null;
51
52 /**
53 * @var string vendor prefix
54 */
55 protected $controllerVendorName = null;
56
57 /**
58 * Subpackage key of the controller which is supposed to handle this request.
59 *
60 * @var string
61 */
62 protected $controllerSubpackageKey = null;
63
64 /**
65 * @var string Object name of the controller which is supposed to handle this request.
66 */
67 protected $controllerName = 'Standard';
68
69 /**
70 * @var string Name of the action the controller is supposed to take.
71 */
72 protected $controllerActionName = 'index';
73
74 /**
75 * @var array The arguments for this request
76 */
77 protected $arguments = array();
78
79 /**
80 * Framework-internal arguments for this request, such as __referrer.
81 * All framework-internal arguments start with double underscore (__),
82 * and are only used from within the framework. Not for user consumption.
83 * Internal Arguments can be objects, in contrast to public arguments
84 *
85 * @var array
86 */
87 protected $internalArguments = array();
88
89 /**
90 * @var string The requested representation format
91 */
92 protected $format = 'txt';
93
94 /**
95 * @var bool If this request has been changed and needs to be dispatched again
96 */
97 protected $dispatched = false;
98
99 /**
100 * If this request is a forward because of an error, the original request gets filled.
101 *
102 * @var \TYPO3\CMS\Extbase\Mvc\Request
103 */
104 protected $originalRequest = null;
105
106 /**
107 * If the request is a forward because of an error, these mapping results get filled here.
108 *
109 * @var \TYPO3\CMS\Extbase\Error\Result
110 */
111 protected $originalRequestMappingResults = null;
112
113 /**
114 * Sets the dispatched flag
115 *
116 * @param bool $flag If this request has been dispatched
117 * @return void
118 * @api
119 */
120 public function setDispatched($flag)
121 {
122 $this->dispatched = (bool)$flag;
123 }
124
125 /**
126 * If this request has been dispatched and addressed by the responsible
127 * controller and the response is ready to be sent.
128 *
129 * The dispatcher will try to dispatch the request again if it has not been
130 * addressed yet.
131 *
132 * @return bool TRUE if this request has been disptached successfully
133 * @api
134 */
135 public function isDispatched()
136 {
137 return $this->dispatched;
138 }
139
140 /**
141 * Returns the object name of the controller defined by the extension name and
142 * controller name
143 *
144 * @return string The controller's Object Name
145 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchControllerException if the controller does not exist
146 * @api
147 */
148 public function getControllerObjectName()
149 {
150 if (null !== $this->controllerVendorName) {
151 // It's safe to assume a namespaced name as namespaced names have to follow PSR-0
152 $objectName = str_replace(
153 array(
154 '@extension',
155 '@subpackage',
156 '@controller',
157 '@vendor',
158 '\\\\'
159 ),
160 array(
161 $this->controllerExtensionName,
162 $this->controllerSubpackageKey,
163 $this->controllerName,
164 $this->controllerVendorName,
165 '\\'
166 ),
167 $this->namespacedControllerObjectNamePattern
168 );
169 } else {
170 $objectName = str_replace(
171 array(
172 '@extension',
173 '@subpackage',
174 '@controller',
175 '__'
176 ),
177 array(
178 $this->controllerExtensionName,
179 $this->controllerSubpackageKey,
180 $this->controllerName,
181 '_'
182 ),
183 $this->controllerObjectNamePattern
184 );
185 }
186 // @todo implement getCaseSensitiveObjectName()
187 if ($objectName === false) {
188 throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchControllerException('The controller object "' . $objectName . '" does not exist.', 1220884009);
189 }
190 return $objectName;
191 }
192
193 /**
194 * Explicitly sets the object name of the controller
195 *
196 * @param string $controllerObjectName The fully qualified controller object name
197 *
198 * @return void
199 */
200 public function setControllerObjectName($controllerObjectName)
201 {
202 $nameParts = ClassNamingUtility::explodeObjectControllerName($controllerObjectName);
203 $this->controllerVendorName = isset($nameParts['vendorName']) ? $nameParts['vendorName'] : null;
204 $this->controllerExtensionName = $nameParts['extensionName'];
205 $this->controllerSubpackageKey = isset($nameParts['subpackageKey']) ? $nameParts['subpackageKey'] : null;
206 $this->controllerName = $nameParts['controllerName'];
207 }
208
209 /**
210 * Sets the plugin name.
211 *
212 * @param string|NULL $pluginName
213 *
214 * @return void
215 */
216 public function setPluginName($pluginName = null)
217 {
218 if ($pluginName !== null) {
219 $this->pluginName = $pluginName;
220 }
221 }
222
223 /**
224 * Returns the plugin key.
225 *
226 * @return string The plugin key
227 * @api
228 */
229 public function getPluginName()
230 {
231 return $this->pluginName;
232 }
233
234 /**
235 * Sets the extension name of the controller.
236 *
237 * @param string $controllerExtensionName The extension name.
238 *
239 * @return void
240 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidExtensionNameException if the extension name is not valid
241 */
242 public function setControllerExtensionName($controllerExtensionName)
243 {
244 if ($controllerExtensionName !== null) {
245 $this->controllerExtensionName = $controllerExtensionName;
246 }
247 }
248
249 /**
250 * Returns the extension name of the specified controller.
251 *
252 * @return string The extension name
253 * @api
254 */
255 public function getControllerExtensionName()
256 {
257 return $this->controllerExtensionName;
258 }
259
260 /**
261 * Returns the extension name of the specified controller.
262 *
263 * @return string The extension key
264 * @api
265 */
266 public function getControllerExtensionKey()
267 {
268 return \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($this->controllerExtensionName);
269 }
270
271 /**
272 * Sets the subpackage key of the controller.
273 *
274 * @param string $subpackageKey The subpackage key.
275 *
276 * @return void
277 */
278 public function setControllerSubpackageKey($subpackageKey)
279 {
280 $this->controllerSubpackageKey = $subpackageKey;
281 }
282
283 /**
284 * Returns the subpackage key of the specified controller.
285 * If there is no subpackage key set, the method returns NULL
286 *
287 * @return string The subpackage key
288 */
289 public function getControllerSubpackageKey()
290 {
291 return $this->controllerSubpackageKey;
292 }
293
294 /**
295 * Sets the name of the controller which is supposed to handle the request.
296 * Note: This is not the object name of the controller!
297 *
298 * @param string $controllerName Name of the controller
299 *
300 * @throws Exception\InvalidControllerNameException
301 * @return void
302 */
303 public function setControllerName($controllerName)
304 {
305 if (!is_string($controllerName) && $controllerName !== null) {
306 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidControllerNameException('The controller name must be a valid string, ' . gettype($controllerName) . ' given.', 1187176358);
307 }
308 if (strpos($controllerName, '_') !== false) {
309 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidControllerNameException('The controller name must not contain underscores.', 1217846412);
310 }
311 if ($controllerName !== null) {
312 $this->controllerName = $controllerName;
313 }
314 }
315
316 /**
317 * Returns the object name of the controller supposed to handle this request, if one
318 * was set already (if not, the name of the default controller is returned)
319 *
320 * @return string Object name of the controller
321 * @api
322 */
323 public function getControllerName()
324 {
325 return $this->controllerName;
326 }
327
328 /**
329 * Sets the name of the action contained in this request.
330 *
331 * Note that the action name must start with a lower case letter and is case sensitive.
332 *
333 * @param string $actionName Name of the action to execute by the controller
334 *
335 * @return void
336 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidActionNameException if the action name is not valid
337 */
338 public function setControllerActionName($actionName)
339 {
340 if (!is_string($actionName) && $actionName !== null) {
341 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidActionNameException('The action name must be a valid string, ' . gettype($actionName) . ' given (' . $actionName . ').', 1187176359);
342 }
343 if ($actionName[0] !== strtolower($actionName[0]) && $actionName !== null) {
344 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidActionNameException('The action name must start with a lower case letter, "' . $actionName . '" does not match this criteria.', 1218473352);
345 }
346 if ($actionName !== null) {
347 $this->controllerActionName = $actionName;
348 }
349 }
350
351 /**
352 * Returns the name of the action the controller is supposed to execute.
353 *
354 * @return string Action name
355 * @api
356 */
357 public function getControllerActionName()
358 {
359 $controllerObjectName = $this->getControllerObjectName();
360 if ($controllerObjectName !== '' && $this->controllerActionName === strtolower($this->controllerActionName)) {
361 $actionMethodName = $this->controllerActionName . 'Action';
362 $classMethods = get_class_methods($controllerObjectName);
363 if (is_array($classMethods)) {
364 foreach ($classMethods as $existingMethodName) {
365 if (strtolower($existingMethodName) === strtolower($actionMethodName)) {
366 $this->controllerActionName = substr($existingMethodName, 0, -6);
367 break;
368 }
369 }
370 }
371 }
372 return $this->controllerActionName;
373 }
374
375 /**
376 * Sets the value of the specified argument
377 *
378 * @param string $argumentName Name of the argument to set
379 * @param mixed $value The new value
380 *
381 * @throws Exception\InvalidArgumentNameException
382 * @return void
383 */
384 public function setArgument($argumentName, $value)
385 {
386 if (!is_string($argumentName) || $argumentName === '') {
387 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException('Invalid argument name.', 1210858767);
388 }
389 if ($argumentName[0] === '_' && $argumentName[1] === '_') {
390 $this->internalArguments[$argumentName] = $value;
391 return;
392 }
393 if (!in_array($argumentName, array('@extension', '@subpackage', '@controller', '@action', '@format', '@vendor'), true)) {
394 $this->arguments[$argumentName] = $value;
395 }
396 }
397
398 /**
399 * sets the VendorName
400 *
401 * @param string $vendorName
402 *
403 * @return void
404 */
405 public function setControllerVendorName($vendorName)
406 {
407 $this->controllerVendorName = $vendorName;
408 }
409
410 /**
411 * get the VendorName
412 *
413 * @return string
414 */
415 public function getControllerVendorName()
416 {
417 return $this->controllerVendorName;
418 }
419
420 /**
421 * Sets the whole arguments array and therefore replaces any arguments
422 * which existed before.
423 *
424 * @param array $arguments An array of argument names and their values
425 *
426 * @return void
427 */
428 public function setArguments(array $arguments)
429 {
430 $this->arguments = array();
431 foreach ($arguments as $argumentName => $argumentValue) {
432 $this->setArgument($argumentName, $argumentValue);
433 }
434 }
435
436 /**
437 * Returns an array of arguments and their values
438 *
439 * @return array Associative array of arguments and their values (which may be arguments and values as well)
440 * @api
441 */
442 public function getArguments()
443 {
444 return $this->arguments;
445 }
446
447 /**
448 * Returns the value of the specified argument
449 *
450 * @param string $argumentName Name of the argument
451 *
452 * @return string Value of the argument
453 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException if such an argument does not exist
454 * @api
455 */
456 public function getArgument($argumentName)
457 {
458 if (!isset($this->arguments[$argumentName])) {
459 throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException('An argument "' . $argumentName . '" does not exist for this request.', 1176558158);
460 }
461 return $this->arguments[$argumentName];
462 }
463
464 /**
465 * Checks if an argument of the given name exists (is set)
466 *
467 * @param string $argumentName Name of the argument to check
468 *
469 * @return bool TRUE if the argument is set, otherwise FALSE
470 * @api
471 */
472 public function hasArgument($argumentName)
473 {
474 return isset($this->arguments[$argumentName]);
475 }
476
477 /**
478 * Sets the requested representation format
479 *
480 * @param string $format The desired format, something like "html", "xml", "png", "json" or the like. Can even be something like "rss.xml".
481 *
482 * @return void
483 */
484 public function setFormat($format)
485 {
486 $this->format = $format;
487 }
488
489 /**
490 * Returns the requested representation format
491 *
492 * @return string The desired format, something like "html", "xml", "png", "json" or the like.
493 * @api
494 */
495 public function getFormat()
496 {
497 return $this->format;
498 }
499
500 /**
501 * Returns the original request. Filled only if a property mapping error occurred.
502 *
503 * @return \TYPO3\CMS\Extbase\Mvc\Request the original request.
504 */
505 public function getOriginalRequest()
506 {
507 return $this->originalRequest;
508 }
509
510 /**
511 * @param \TYPO3\CMS\Extbase\Mvc\Request $originalRequest
512 *
513 * @return void
514 */
515 public function setOriginalRequest(\TYPO3\CMS\Extbase\Mvc\Request $originalRequest)
516 {
517 $this->originalRequest = $originalRequest;
518 }
519
520 /**
521 * Get the request mapping results for the original request.
522 *
523 * @return \TYPO3\CMS\Extbase\Error\Result
524 */
525 public function getOriginalRequestMappingResults()
526 {
527 if ($this->originalRequestMappingResults === null) {
528 return new \TYPO3\CMS\Extbase\Error\Result();
529 }
530 return $this->originalRequestMappingResults;
531 }
532
533 /**
534 * @param \TYPO3\CMS\Extbase\Error\Result $originalRequestMappingResults
535 */
536 public function setOriginalRequestMappingResults(\TYPO3\CMS\Extbase\Error\Result $originalRequestMappingResults)
537 {
538 $this->originalRequestMappingResults = $originalRequestMappingResults;
539 }
540
541 /**
542 * Get the internal arguments of the request, i.e. every argument starting
543 * with two underscores.
544 *
545 * @return array
546 */
547 public function getInternalArguments()
548 {
549 return $this->internalArguments;
550 }
551
552 /**
553 * Returns the value of the specified argument
554 *
555 * @param string $argumentName Name of the argument
556 *
557 * @return string Value of the argument, or NULL if not set.
558 */
559 public function getInternalArgument($argumentName)
560 {
561 if (!isset($this->internalArguments[$argumentName])) {
562 return null;
563 }
564 return $this->internalArguments[$argumentName];
565 }
566 }