[BUGFIX] ConfigurationManager use FrontendSimulator only if neccessary
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / MVC / Web / Routing / UriBuilder.php
1 <?php
2 /* *
3 * This script is part of the TYPO3 project - inspiring people to share! *
4 * *
5 * TYPO3 is free software; you can redistribute it and/or modify it under *
6 * the terms of the GNU General Public License version 2 as published by *
7 * the Free Software Foundation. *
8 * *
9 * This script is distributed in the hope that it will be useful, but *
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
11 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
12 * Public License for more details. *
13 * */
14
15 /**
16 * An URI Builder
17 *
18 * @package Extbase
19 * @subpackage MVC\Web\Routing
20 * @version $Id$
21 * @api
22 */
23 class Tx_Extbase_MVC_Web_Routing_UriBuilder {
24
25 /**
26 * @var Tx_Extbase_Configuration_ConfigurationManagerInterface
27 */
28 protected $configurationManager;
29
30 /**
31 * @var Tx_Extbase_Service_ExtensionService
32 */
33 protected $extensionService;
34
35 /**
36 * An instance of tslib_cObj
37 *
38 * @var tslib_cObj
39 */
40 protected $contentObject;
41
42 /**
43 * @var Tx_Extbase_MVC_Web_Request
44 */
45 protected $request;
46
47 /**
48 * @var array
49 */
50 protected $arguments = array();
51
52 /**
53 * Arguments which have been used for building the last URI
54 * @var array
55 */
56 protected $lastArguments = array();
57
58 /**
59 * @var string
60 */
61 protected $section = '';
62
63 /**
64 * @var boolean
65 */
66 protected $createAbsoluteUri = FALSE;
67
68 /**
69 * @var boolean
70 */
71 protected $addQueryString = FALSE;
72
73 /**
74 * @var array
75 */
76 protected $argumentsToBeExcludedFromQueryString = array();
77
78 /**
79 * @var boolean
80 */
81 protected $linkAccessRestrictedPages = FALSE;
82
83 /**
84 * @var integer
85 */
86 protected $targetPageUid = NULL;
87
88 /**
89 * @var integer
90 */
91 protected $targetPageType = 0;
92
93 /**
94 * @var boolean
95 */
96 protected $noCache = FALSE;
97
98 /**
99 * @var boolean
100 */
101 protected $useCacheHash = TRUE;
102
103 /**
104 * @var string
105 */
106 protected $format = '';
107
108 /**
109 * @var string
110 */
111 protected $argumentPrefix = NULL;
112
113 /**
114 * @param Tx_Extbase_Configuration_ConfigurationManagerInterface $configurationManager
115 * @return void
116 */
117 public function injectConfigurationManager(Tx_Extbase_Configuration_ConfigurationManagerInterface $configurationManager) {
118 $this->configurationManager = $configurationManager;
119 }
120
121 /**
122 * @param Tx_Extbase_Service_ExtensionService $extensionService
123 * @return void
124 */
125 public function injectExtensionService(Tx_Extbase_Service_ExtensionService $extensionService) {
126 $this->extensionService = $extensionService;
127 }
128
129 /**
130 * Life-cycle method that is called by the DI container as soon as this object is completely built
131 *
132 * @return void
133 */
134 public function initializeObject() {
135 $this->contentObject = $this->configurationManager->getContentObject();
136 }
137
138 /**
139 * Sets the current request
140 *
141 * @param Tx_Extbase_MVC_Web_Request $request
142 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
143 */
144 public function setRequest(Tx_Extbase_MVC_Web_Request $request) {
145 $this->request = $request;
146 return $this;
147 }
148
149 /**
150 * @return Tx_Extbase_MVC_Web_Request
151 */
152 public function getRequest() {
153 return $this->request;
154 }
155
156 /**
157 * Additional query parameters.
158 * If you want to "prefix" arguments, you can pass in multidimensional arrays:
159 * array('prefix1' => array('foo' => 'bar')) gets "&prefix1[foo]=bar"
160 *
161 * @param array $arguments
162 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
163 * @api
164 */
165 public function setArguments(array $arguments) {
166 $this->arguments = $arguments;
167 return $this;
168 }
169
170 /**
171 * @return array
172 * @api
173 */
174 public function getArguments() {
175 return $this->arguments;
176 }
177
178 /**
179 * If specified, adds a given HTML anchor to the URI (#...)
180 *
181 * @param string $section
182 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
183 * @api
184 */
185 public function setSection($section) {
186 $this->section = $section;
187 return $this;
188 }
189
190 /**
191 * @return string
192 * @api
193 */
194 public function getSection() {
195 return $this->section;
196 }
197
198 /**
199 * Specifies the format of the target (e.g. "html" or "xml")
200 *
201 * @param string $section
202 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
203 * @api
204 */
205 public function setFormat($format) {
206 $this->format = $format;
207 return $this;
208 }
209
210 /**
211 * @return string
212 * @api
213 */
214 public function getFormat() {
215 return $this->format;
216 }
217
218 /**
219 * If set, the URI is prepended with the current base URI. Defaults to FALSE.
220 *
221 * @param boolean $createAbsoluteUri
222 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
223 * @api
224 */
225 public function setCreateAbsoluteUri($createAbsoluteUri) {
226 $this->createAbsoluteUri = $createAbsoluteUri;
227 return $this;
228 }
229
230 /**
231 * @return boolean
232 * @api
233 */
234 public function getCreateAbsoluteUri() {
235 return $this->createAbsoluteUri;
236 }
237
238 /**
239 * If set, the current query parameters will be merged with $this->arguments. Defaults to FALSE.
240 *
241 * @param boolean $addQueryString
242 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
243 * @api
244 * @see TSref/typolink.addQueryString
245 */
246 public function setAddQueryString($addQueryString) {
247 $this->addQueryString = (boolean)$addQueryString;
248 return $this;
249 }
250
251 /**
252 * @return boolean
253 * @api
254 */
255 public function getAddQueryString() {
256 return $this->addQueryString;
257 }
258
259 /**
260 * A list of arguments to be excluded from the query parameters
261 * Only active if addQueryString is set
262 *
263 * @param array $argumentsToBeExcludedFromQueryString
264 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
265 * @api
266 * @see TSref/typolink.addQueryString.exclude
267 * @see setAddQueryString()
268 */
269 public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString) {
270 $this->argumentsToBeExcludedFromQueryString = $argumentsToBeExcludedFromQueryString;
271 return $this;
272 }
273
274 /**
275 * @return array
276 * @api
277 */
278 public function getArgumentsToBeExcludedFromQueryString() {
279 return $this->argumentsToBeExcludedFromQueryString;
280 }
281
282 /**
283 * Specifies the prefix to be used for all arguments.
284 *
285 * @param string $argumentPrefix
286 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
287 */
288 public function setArgumentPrefix($argumentPrefix) {
289 $this->argumentPrefix = (string)$argumentPrefix;
290 return $this;
291 }
292
293 /**
294 * @return string
295 */
296 public function getArgumentPrefix() {
297 return $this->argumentPrefix;
298 }
299
300 /**
301 * If set, URIs for pages without access permissions will be created
302 *
303 * @param boolean $linkAccessRestrictedPages
304 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
305 * @api
306 */
307 public function setLinkAccessRestrictedPages($linkAccessRestrictedPages) {
308 $this->linkAccessRestrictedPages = (boolean)$linkAccessRestrictedPages;
309 return $this;
310 }
311
312 /**
313 * @return boolean
314 * @api
315 */
316 public function getLinkAccessRestrictedPages() {
317 return $this->linkAccessRestrictedPages;
318 }
319
320 /**
321 * Uid of the target page
322 *
323 * @param integer $pageUid
324 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
325 * @api
326 */
327 public function setTargetPageUid($targetPageUid) {
328 $this->targetPageUid = $targetPageUid;
329 return $this;
330 }
331
332 /**
333 * returns $this->targetPageUid.
334 *
335 * @return integer
336 * @api
337 */
338 public function getTargetPageUid() {
339 return $this->targetPageUid;
340 }
341
342 /**
343 * Sets the page type of the target URI. Defaults to 0
344 *
345 * @param integer $pageType
346 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
347 * @api
348 */
349 public function setTargetPageType($targetPageType) {
350 $this->targetPageType = (integer)$targetPageType;
351 return $this;
352 }
353
354 /**
355 * @return integer
356 * @api
357 */
358 public function getTargetPageType() {
359 return $this->targetPageType;
360 }
361
362 /**
363 * by default FALSE; if TRUE, &no_cache=1 will be appended to the URI
364 * This overrules the useCacheHash setting
365 *
366 * @param boolean $noCache
367 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
368 * @api
369 */
370 public function setNoCache($noCache) {
371 $this->noCache = (boolean)$noCache;
372 return $this;
373 }
374
375 /**
376 * @return boolean
377 * @api
378 */
379 public function getNoCache() {
380 return $this->noCache;
381 }
382
383 /**
384 * by default TRUE; if FALSE, no cHash parameter will be appended to the URI
385 * If noCache is set, this setting will be ignored.
386 *
387 * @param boolean $useCacheHash
388 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
389 * @api
390 */
391 public function setUseCacheHash($useCacheHash) {
392 $this->useCacheHash = (boolean)$useCacheHash;
393 return $this;
394 }
395
396 /**
397 * @return boolean
398 * @api
399 */
400 public function getUseCacheHash() {
401 return $this->useCacheHash;
402 }
403
404 /**
405 * Returns the arguments being used for the last URI being built.
406 * This is only set after build() / uriFor() has been called.
407 *
408 * @return array The last arguments
409 * @author Sebastian Kurf├╝rst <sebastian@typo3.org>
410 */
411 public function getLastArguments() {
412 return $this->lastArguments;
413 }
414
415 /**
416 * Resets all UriBuilder options to their default value
417 *
418 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
419 * @api
420 */
421 public function reset() {
422 $this->arguments = array();
423 $this->section = '';
424 $this->format = '';
425 $this->createAbsoluteUri = FALSE;
426 $this->addQueryString = FALSE;
427 $this->argumentsToBeExcludedFromQueryString = array();
428 $this->linkAccessRestrictedPages = FALSE;
429 $this->targetPageUid = NULL;
430 $this->targetPageType = 0;
431 $this->noCache = FALSE;
432 $this->useCacheHash = TRUE;
433 $this->argumentPrefix = NULL;
434
435 return $this;
436 }
437
438 /**
439 * Creates an URI used for linking to an Extbase action.
440 * Works in Frontend and Backend mode of TYPO3.
441 *
442 * @param string $actionName Name of the action to be called
443 * @param array $controllerArguments Additional query parameters. Will be "namespaced" and merged with $this->arguments.
444 * @param string $controllerName Name of the target controller. If not set, current ControllerName is used.
445 * @param string $extensionName Name of the target extension, without underscores. If not set, current ExtensionName is used.
446 * @param string $pluginName Name of the target plugin. If not set, current PluginName is used.
447 * @return string the rendered URI
448 * @api
449 * @see build()
450 */
451 public function uriFor($actionName = NULL, $controllerArguments = array(), $controllerName = NULL, $extensionName = NULL, $pluginName = NULL) {
452 if ($actionName !== NULL) {
453 $controllerArguments['action'] = $actionName;
454 }
455 if ($controllerName !== NULL) {
456 $controllerArguments['controller'] = $controllerName;
457 } else {
458 $controllerArguments['controller'] = $this->request->getControllerName();
459 }
460 if ($extensionName === NULL) {
461 $extensionName = $this->request->getControllerExtensionName();
462 }
463 if ($pluginName === NULL && TYPO3_MODE === 'FE') {
464 $pluginName = $this->extensionService->getPluginNameByAction($extensionName, $controllerArguments['controller'], $controllerArguments['action']);
465 }
466 if ($pluginName === NULL) {
467 $pluginName = $this->request->getPluginName();
468 }
469 if ($this->targetPageUid === NULL && TYPO3_MODE === 'FE') {
470 $this->targetPageUid = $this->extensionService->getTargetPidByPlugin($extensionName, $pluginName);
471 }
472 if ($this->format !== '') {
473 $controllerArguments['format'] = $this->format;
474 }
475 if ($this->argumentPrefix !== NULL) {
476 $prefixedControllerArguments = array($this->argumentPrefix => $controllerArguments);
477 } else {
478 $pluginNamespace = $this->extensionService->getPluginNamespace($extensionName, $pluginName);
479 $prefixedControllerArguments = array($pluginNamespace => $controllerArguments);
480 }
481 $this->arguments = t3lib_div::array_merge_recursive_overrule($this->arguments, $prefixedControllerArguments);
482
483 return $this->build();
484 }
485
486 /**
487 * Builds the URI
488 * Depending on the current context this calls buildBackendUri() or buildFrontendUri()
489 *
490 * @return string The URI
491 * @api
492 * @see buildBackendUri()
493 * @see buildFrontendUri()
494 */
495 public function build() {
496 if (TYPO3_MODE === 'BE') {
497 return $this->buildBackendUri();
498 } else {
499 return $this->buildFrontendUri();
500 }
501 }
502
503 /**
504 * Builds the URI, backend flavour
505 * The resulting URI is relative and starts with "mod.php".
506 * The settings pageUid, pageType, noCache, useCacheHash & linkAccessRestrictedPages
507 * will be ignored in the backend.
508 *
509 * @return string The URI
510 */
511 public function buildBackendUri() {
512 if ($this->addQueryString === TRUE) {
513 $arguments = t3lib_div::_GET();
514 foreach($this->argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) {
515 unset($arguments[$argumentToBeExcluded]);
516 }
517 } else {
518 $arguments = array(
519 'M' => t3lib_div::_GET('M'),
520 'id' => t3lib_div::_GET('id')
521 );
522 }
523 $arguments = t3lib_div::array_merge_recursive_overrule($arguments, $this->arguments);
524 $arguments = $this->convertDomainObjectsToIdentityArrays($arguments);
525 $this->lastArguments = $arguments;
526 $uri = 'mod.php?' . http_build_query($arguments, NULL, '&');
527 if ($this->section !== '') {
528 $uri .= '#' . $this->section;
529 }
530 if ($this->createAbsoluteUri === TRUE) {
531 $uri = $this->request->getBaseUri() . $uri;
532 }
533 return $uri;
534 }
535
536 /**
537 * Builds the URI, frontend flavour
538 *
539 * @return string The URI
540 * @see buildTypolinkConfiguration()
541 */
542 public function buildFrontendUri() {
543 $typolinkConfiguration = $this->buildTypolinkConfiguration();
544
545 if ($this->createAbsoluteUri === TRUE) {
546 $typolinkConfiguration['forceAbsoluteUrl'] = TRUE;
547 }
548
549 $uri = $this->contentObject->typoLink_URL($typolinkConfiguration);
550 return $uri;
551 }
552
553
554 /**
555 * Builds a TypoLink configuration array from the current settings
556 *
557 * @return array typolink configuration array
558 * @see TSref/typolink
559 */
560 protected function buildTypolinkConfiguration() {
561 $typolinkConfiguration = array();
562
563 $typolinkConfiguration['parameter'] = $this->targetPageUid !== NULL ? $this->targetPageUid : $GLOBALS['TSFE']->id;
564 if ($this->targetPageType !== 0) {
565 $typolinkConfiguration['parameter'] .= ',' . $this->targetPageType;
566 }
567
568 if (count($this->arguments) > 0) {
569 $arguments = $this->convertDomainObjectsToIdentityArrays($this->arguments);
570 $this->lastArguments = $arguments;
571 $typolinkConfiguration['additionalParams'] = t3lib_div::implodeArrayForUrl(NULL, $arguments);
572 }
573
574 if ($this->addQueryString === TRUE) {
575 $typolinkConfiguration['addQueryString'] = 1;
576 if (count($this->argumentsToBeExcludedFromQueryString) > 0) {
577 $typolinkConfiguration['addQueryString.'] = array(
578 'exclude' => implode(',', $this->argumentsToBeExcludedFromQueryString)
579 );
580 }
581 // TODO: Support for __hmac and addQueryString!
582 }
583
584 if ($this->noCache === TRUE) {
585 $typolinkConfiguration['no_cache'] = 1;
586 } elseif ($this->useCacheHash) {
587 $typolinkConfiguration['useCacheHash'] = 1;
588 }
589
590 if ($this->section !== '') {
591 $typolinkConfiguration['section'] = $this->section;
592 }
593
594 if ($this->linkAccessRestrictedPages === TRUE) {
595 $typolinkConfiguration['linkAccessRestrictedPages'] = 1;
596 }
597
598 return $typolinkConfiguration;
599 }
600
601 /**
602 * Recursively iterates through the specified arguments and turns instances of type Tx_Extbase_DomainObject_AbstractEntity
603 * into an arrays containing the uid of the domain object.
604 *
605 * @param array $arguments The arguments to be iterated
606 * @return array The modified arguments array
607 */
608 protected function convertDomainObjectsToIdentityArrays(array $arguments) {
609 foreach ($arguments as $argumentKey => $argumentValue) {
610 // if we have a LazyLoadingProxy here, make sure to get the real instance for further processing
611 if ($argumentValue instanceof Tx_Extbase_Persistence_LazyLoadingProxy) {
612 $argumentValue = $argumentValue->_loadRealInstance();
613 // also update the value in the arguments array, because the lazyLoaded object could be
614 // hidden and thus the $argumentValue would be NULL.
615 $arguments[$argumentKey] = $argumentValue;
616 }
617 if ($argumentValue instanceof Tx_Extbase_DomainObject_AbstractDomainObject) {
618 if ($argumentValue->getUid() !== NULL) {
619 $arguments[$argumentKey] = $argumentValue->getUid();
620 } elseif ($argumentValue instanceof Tx_Extbase_DomainObject_AbstractValueObject) {
621 $arguments[$argumentKey] = $this->convertTransientObjectToArray($argumentValue);
622 } else {
623 throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('Could not serialize Domain Object ' . get_class($argumentValue) . '. It is neither an Entity with identity properties set, nor a Value Object.', 1260881688);
624 }
625 } elseif (is_array($argumentValue)) {
626 $arguments[$argumentKey] = $this->convertDomainObjectsToIdentityArrays($argumentValue);
627 }
628 }
629 return $arguments;
630 }
631
632 /**
633 * Converts a given object recursively into an array.
634 *
635 * @param Tx_Extbase_DomainObject_AbstractDomainObject $object
636 * @return void
637 */
638 // TODO Refactore this into convertDomainObjectsToIdentityArrays()
639 public function convertTransientObjectToArray(Tx_Extbase_DomainObject_AbstractDomainObject $object) {
640 $result = array();
641 foreach ($object->_getProperties() as $propertyName => $propertyValue) {
642 if ($propertyValue instanceof Tx_Extbase_DomainObject_AbstractDomainObject) {
643 if ($propertyValue->getUid() !== NULL) {
644 $result[$propertyName] = $propertyValue->getUid();
645 } else {
646 $result[$propertyName] = $this->convertTransientObjectToArray($propertyValue);
647 }
648 } elseif (is_array($propertyValue)) {
649 $result[$propertyName] = $this->convertDomainObjectsToIdentityArrays($propertyValue);
650 } else {
651 $result[$propertyName] = $propertyValue;
652 }
653 }
654 return $result;
655 }
656
657 }
658 ?>