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