3 * This script is part of the TYPO3 project - inspiring people to share! *
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. *
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. *
19 * @subpackage MVC\Web\Routing
23 class Tx_Extbase_MVC_Web_Routing_UriBuilder
{
26 * @var Tx_Extbase_Configuration_ConfigurationManagerInterface
28 protected $configurationManager;
31 * @var Tx_Extbase_Service_ExtensionService
33 protected $extensionService;
36 * An instance of tslib_cObj
40 protected $contentObject;
43 * @var Tx_Extbase_MVC_Web_Request
50 protected $arguments = array();
53 * Arguments which have been used for building the last URI
56 protected $lastArguments = array();
61 protected $section = '';
66 protected $createAbsoluteUri = FALSE
;
71 protected $addQueryString = FALSE
;
76 protected $argumentsToBeExcludedFromQueryString = array();
81 protected $linkAccessRestrictedPages = FALSE
;
86 protected $targetPageUid = NULL
;
91 protected $targetPageType = 0;
96 protected $noCache = FALSE
;
101 protected $useCacheHash = TRUE
;
106 protected $format = '';
111 protected $argumentPrefix = NULL
;
114 * @param Tx_Extbase_Configuration_ConfigurationManagerInterface $configurationManager
117 public function injectConfigurationManager(Tx_Extbase_Configuration_ConfigurationManagerInterface
$configurationManager) {
118 $this->configurationManager
= $configurationManager;
122 * @param Tx_Extbase_Service_ExtensionService $extensionService
125 public function injectExtensionService(Tx_Extbase_Service_ExtensionService
$extensionService) {
126 $this->extensionService
= $extensionService;
130 * Life-cycle method that is called by the DI container as soon as this object is completely built
134 public function initializeObject() {
135 $this->contentObject
= $this->configurationManager
->getContentObject();
139 * Sets the current request
141 * @param Tx_Extbase_MVC_Web_Request $request
142 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
144 public function setRequest(Tx_Extbase_MVC_Web_Request
$request) {
145 $this->request
= $request;
150 * @return Tx_Extbase_MVC_Web_Request
152 public function getRequest() {
153 return $this->request
;
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"
161 * @param array $arguments
162 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
165 public function setArguments(array $arguments) {
166 $this->arguments
= $arguments;
174 public function getArguments() {
175 return $this->arguments
;
179 * If specified, adds a given HTML anchor to the URI (#...)
181 * @param string $section
182 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
185 public function setSection($section) {
186 $this->section
= $section;
194 public function getSection() {
195 return $this->section
;
199 * Specifies the format of the target (e.g. "html" or "xml")
201 * @param string $section
202 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
205 public function setFormat($format) {
206 $this->format
= $format;
214 public function getFormat() {
215 return $this->format
;
219 * If set, the URI is prepended with the current base URI. Defaults to FALSE.
221 * @param boolean $createAbsoluteUri
222 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
225 public function setCreateAbsoluteUri($createAbsoluteUri) {
226 $this->createAbsoluteUri
= $createAbsoluteUri;
234 public function getCreateAbsoluteUri() {
235 return $this->createAbsoluteUri
;
239 * If set, the current query parameters will be merged with $this->arguments. Defaults to FALSE.
241 * @param boolean $addQueryString
242 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
244 * @see TSref/typolink.addQueryString
246 public function setAddQueryString($addQueryString) {
247 $this->addQueryString
= (boolean
)$addQueryString;
255 public function getAddQueryString() {
256 return $this->addQueryString
;
260 * A list of arguments to be excluded from the query parameters
261 * Only active if addQueryString is set
263 * @param array $argumentsToBeExcludedFromQueryString
264 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
266 * @see TSref/typolink.addQueryString.exclude
267 * @see setAddQueryString()
269 public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString) {
270 $this->argumentsToBeExcludedFromQueryString
= $argumentsToBeExcludedFromQueryString;
278 public function getArgumentsToBeExcludedFromQueryString() {
279 return $this->argumentsToBeExcludedFromQueryString
;
283 * Specifies the prefix to be used for all arguments.
285 * @param string $argumentPrefix
286 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
288 public function setArgumentPrefix($argumentPrefix) {
289 $this->argumentPrefix
= (string)$argumentPrefix;
296 public function getArgumentPrefix() {
297 return $this->argumentPrefix
;
301 * If set, URIs for pages without access permissions will be created
303 * @param boolean $linkAccessRestrictedPages
304 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
307 public function setLinkAccessRestrictedPages($linkAccessRestrictedPages) {
308 $this->linkAccessRestrictedPages
= (boolean
)$linkAccessRestrictedPages;
316 public function getLinkAccessRestrictedPages() {
317 return $this->linkAccessRestrictedPages
;
321 * Uid of the target page
323 * @param integer $pageUid
324 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
327 public function setTargetPageUid($targetPageUid) {
328 $this->targetPageUid
= $targetPageUid;
333 * returns $this->targetPageUid.
338 public function getTargetPageUid() {
339 return $this->targetPageUid
;
343 * Sets the page type of the target URI. Defaults to 0
345 * @param integer $pageType
346 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
349 public function setTargetPageType($targetPageType) {
350 $this->targetPageType
= (integer)$targetPageType;
358 public function getTargetPageType() {
359 return $this->targetPageType
;
363 * by default FALSE; if TRUE, &no_cache=1 will be appended to the URI
364 * This overrules the useCacheHash setting
366 * @param boolean $noCache
367 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
370 public function setNoCache($noCache) {
371 $this->noCache
= (boolean
)$noCache;
379 public function getNoCache() {
380 return $this->noCache
;
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.
387 * @param boolean $useCacheHash
388 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
391 public function setUseCacheHash($useCacheHash) {
392 $this->useCacheHash
= (boolean
)$useCacheHash;
400 public function getUseCacheHash() {
401 return $this->useCacheHash
;
405 * Returns the arguments being used for the last URI being built.
406 * This is only set after build() / uriFor() has been called.
408 * @return array The last arguments
409 * @author Sebastian Kurfürst <sebastian@typo3.org>
411 public function getLastArguments() {
412 return $this->lastArguments
;
416 * Resets all UriBuilder options to their default value
418 * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
421 public function reset() {
422 $this->arguments
= array();
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
;
439 * Creates an URI used for linking to an Extbase action.
440 * Works in Frontend and Backend mode of TYPO3.
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
451 public function uriFor($actionName = NULL
, $controllerArguments = array(), $controllerName = NULL
, $extensionName = NULL
, $pluginName = NULL
) {
452 if ($actionName !== NULL
) {
453 $controllerArguments['action'] = $actionName;
455 if ($controllerName !== NULL
) {
456 $controllerArguments['controller'] = $controllerName;
458 $controllerArguments['controller'] = $this->request
->getControllerName();
460 if ($extensionName === NULL
) {
461 $extensionName = $this->request
->getControllerExtensionName();
463 if ($pluginName === NULL
&& TYPO3_MODE
=== 'FE') {
464 $pluginName = $this->extensionService
->getPluginNameByAction($extensionName, $controllerArguments['controller'], $controllerArguments['action']);
466 if ($pluginName === NULL
) {
467 $pluginName = $this->request
->getPluginName();
469 if ($this->targetPageUid
=== NULL
&& TYPO3_MODE
=== 'FE') {
470 $this->targetPageUid
= $this->extensionService
->getTargetPidByPlugin($extensionName, $pluginName);
472 if ($this->format
!== '') {
473 $controllerArguments['format'] = $this->format
;
475 if ($this->argumentPrefix
!== NULL
) {
476 $prefixedControllerArguments = array($this->argumentPrefix
=> $controllerArguments);
478 $pluginNamespace = $this->extensionService
->getPluginNamespace($extensionName, $pluginName);
479 $prefixedControllerArguments = array($pluginNamespace => $controllerArguments);
481 $this->arguments
= t3lib_div
::array_merge_recursive_overrule($this->arguments
, $prefixedControllerArguments);
483 return $this->build();
488 * Depending on the current context this calls buildBackendUri() or buildFrontendUri()
490 * @return string The URI
492 * @see buildBackendUri()
493 * @see buildFrontendUri()
495 public function build() {
496 if (TYPO3_MODE
=== 'BE') {
497 return $this->buildBackendUri();
499 return $this->buildFrontendUri();
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.
509 * @return string The URI
511 public function buildBackendUri() {
512 if ($this->addQueryString
=== TRUE
) {
513 $arguments = t3lib_div
::_GET();
514 foreach($this->argumentsToBeExcludedFromQueryString
as $argumentToBeExcluded) {
515 unset($arguments[$argumentToBeExcluded]);
519 'M' => t3lib_div
::_GET('M'),
520 'id' => t3lib_div
::_GET('id')
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
;
530 if ($this->createAbsoluteUri
=== TRUE
) {
531 $uri = $this->request
->getBaseUri() . $uri;
537 * Builds the URI, frontend flavour
539 * @return string The URI
540 * @see buildTypolinkConfiguration()
542 public function buildFrontendUri() {
543 $typolinkConfiguration = $this->buildTypolinkConfiguration();
545 if ($this->createAbsoluteUri
=== TRUE
) {
546 $typolinkConfiguration['forceAbsoluteUrl'] = TRUE
;
549 $uri = $this->contentObject
->typoLink_URL($typolinkConfiguration);
555 * Builds a TypoLink configuration array from the current settings
557 * @return array typolink configuration array
558 * @see TSref/typolink
560 protected function buildTypolinkConfiguration() {
561 $typolinkConfiguration = array();
563 $typolinkConfiguration['parameter'] = $this->targetPageUid
!== NULL ?
$this->targetPageUid
: $GLOBALS['TSFE']->id
;
564 if ($this->targetPageType
!== 0) {
565 $typolinkConfiguration['parameter'] .= ',' . $this->targetPageType
;
568 if (count($this->arguments
) > 0) {
569 $arguments = $this->convertDomainObjectsToIdentityArrays($this->arguments
);
570 $this->lastArguments
= $arguments;
571 $typolinkConfiguration['additionalParams'] = t3lib_div
::implodeArrayForUrl(NULL
, $arguments);
574 if ($this->addQueryString
=== TRUE
) {
575 $typolinkConfiguration['addQueryString'] = 1;
576 if (count($this->argumentsToBeExcludedFromQueryString
) > 0) {
577 $typolinkConfiguration['addQueryString.'] = array(
578 'exclude' => implode(',', $this->argumentsToBeExcludedFromQueryString
)
581 // TODO: Support for __hmac and addQueryString!
584 if ($this->noCache
=== TRUE
) {
585 $typolinkConfiguration['no_cache'] = 1;
586 } elseif ($this->useCacheHash
) {
587 $typolinkConfiguration['useCacheHash'] = 1;
590 if ($this->section
!== '') {
591 $typolinkConfiguration['section'] = $this->section
;
594 if ($this->linkAccessRestrictedPages
=== TRUE
) {
595 $typolinkConfiguration['linkAccessRestrictedPages'] = 1;
598 return $typolinkConfiguration;
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.
605 * @param array $arguments The arguments to be iterated
606 * @return array The modified arguments array
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;
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);
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);
625 } elseif (is_array($argumentValue)) {
626 $arguments[$argumentKey] = $this->convertDomainObjectsToIdentityArrays($argumentValue);
633 * Converts a given object recursively into an array.
635 * @param Tx_Extbase_DomainObject_AbstractDomainObject $object
638 // TODO Refactore this into convertDomainObjectsToIdentityArrays()
639 public function convertTransientObjectToArray(Tx_Extbase_DomainObject_AbstractDomainObject
$object) {
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();
646 $result[$propertyName] = $this->convertTransientObjectToArray($propertyValue);
648 } elseif (is_array($propertyValue)) {
649 $result[$propertyName] = $this->convertDomainObjectsToIdentityArrays($propertyValue);
651 $result[$propertyName] = $propertyValue;