2 namespace TYPO3\CMS\Extbase\Mvc\Web\Routing
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Backend\Utility\BackendUtility
;
18 use TYPO3\CMS\Core\Utility\ArrayUtility
;
19 use TYPO3\CMS\Core\Utility\GeneralUtility
;
29 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
32 protected $configurationManager;
35 * @var \TYPO3\CMS\Extbase\Service\ExtensionService
38 protected $extensionService;
41 * An instance of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
43 * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
45 protected $contentObject;
48 * @var \TYPO3\CMS\Extbase\Mvc\Web\Request
55 protected $arguments = array();
58 * Arguments which have been used for building the last URI
62 protected $lastArguments = array();
67 protected $section = '';
72 protected $createAbsoluteUri = FALSE;
77 protected $absoluteUriScheme = NULL;
82 protected $addQueryString = FALSE;
87 protected $addQueryStringMethod = NULL;
92 protected $argumentsToBeExcludedFromQueryString = array();
97 protected $linkAccessRestrictedPages = FALSE;
102 protected $targetPageUid = NULL;
107 protected $targetPageType = 0;
112 protected $noCache = FALSE;
117 protected $useCacheHash = TRUE;
122 protected $format = '';
127 protected $argumentPrefix = NULL;
130 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
133 protected $environmentService;
136 * Life-cycle method that is called by the DI container as soon as this object is completely built
140 public function initializeObject() {
141 $this->contentObject
= $this->configurationManager
->getContentObject();
145 * Sets the current request
147 * @param \TYPO3\CMS\Extbase\Mvc\Request $request
148 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
150 public function setRequest(\TYPO3\CMS\Extbase\Mvc\Request
$request) {
151 $this->request
= $request;
156 * @return \TYPO3\CMS\Extbase\Mvc\Web\Request
158 public function getRequest() {
159 return $this->request
;
163 * Additional query parameters.
164 * If you want to "prefix" arguments, you can pass in multidimensional arrays:
165 * array('prefix1' => array('foo' => 'bar')) gets "&prefix1[foo]=bar"
167 * @param array $arguments
168 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
171 public function setArguments(array $arguments) {
172 $this->arguments
= $arguments;
180 public function getArguments() {
181 return $this->arguments
;
185 * If specified, adds a given HTML anchor to the URI (#...)
187 * @param string $section
188 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
191 public function setSection($section) {
192 $this->section
= $section;
200 public function getSection() {
201 return $this->section
;
205 * Specifies the format of the target (e.g. "html" or "xml")
207 * @param string $format
208 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
211 public function setFormat($format) {
212 $this->format
= $format;
220 public function getFormat() {
221 return $this->format
;
225 * If set, the URI is prepended with the current base URI. Defaults to FALSE.
227 * @param bool $createAbsoluteUri
228 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
231 public function setCreateAbsoluteUri($createAbsoluteUri) {
232 $this->createAbsoluteUri
= $createAbsoluteUri;
240 public function getCreateAbsoluteUri() {
241 return $this->createAbsoluteUri
;
247 public function getAbsoluteUriScheme() {
248 return $this->absoluteUriScheme
;
252 * Sets the scheme that should be used for absolute URIs in FE mode
254 * @param string $absoluteUriScheme the scheme to be used for absolute URIs
255 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
257 public function setAbsoluteUriScheme($absoluteUriScheme) {
258 $this->absoluteUriScheme
= $absoluteUriScheme;
263 * If set, the current query parameters will be merged with $this->arguments. Defaults to FALSE.
265 * @param bool $addQueryString
266 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
268 * @see TSref/typolink.addQueryString
270 public function setAddQueryString($addQueryString) {
271 $this->addQueryString
= (bool)$addQueryString;
279 public function getAddQueryString() {
280 return $this->addQueryString
;
284 * Sets the method to get the addQueryString parameters. Defaults undefined
285 * which results in using QUERY_STRING.
287 * @param string $addQueryStringMethod
288 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
290 * @see TSref/typolink.addQueryString.method
292 public function setAddQueryStringMethod($addQueryStringMethod) {
293 $this->addQueryStringMethod
= $addQueryStringMethod;
301 public function getAddQueryStringMethod() {
302 return (string)$this->addQueryStringMethod
;
306 * A list of arguments to be excluded from the query parameters
307 * Only active if addQueryString is set
309 * @param array $argumentsToBeExcludedFromQueryString
310 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
312 * @see TSref/typolink.addQueryString.exclude
313 * @see setAddQueryString()
315 public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString) {
316 $this->argumentsToBeExcludedFromQueryString
= $argumentsToBeExcludedFromQueryString;
324 public function getArgumentsToBeExcludedFromQueryString() {
325 return $this->argumentsToBeExcludedFromQueryString
;
329 * Specifies the prefix to be used for all arguments.
331 * @param string $argumentPrefix
332 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
334 public function setArgumentPrefix($argumentPrefix) {
335 $this->argumentPrefix
= (string)$argumentPrefix;
342 public function getArgumentPrefix() {
343 return $this->argumentPrefix
;
347 * If set, URIs for pages without access permissions will be created
349 * @param bool $linkAccessRestrictedPages
350 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
353 public function setLinkAccessRestrictedPages($linkAccessRestrictedPages) {
354 $this->linkAccessRestrictedPages
= (bool)$linkAccessRestrictedPages;
362 public function getLinkAccessRestrictedPages() {
363 return $this->linkAccessRestrictedPages
;
367 * Uid of the target page
369 * @param int $targetPageUid
370 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
373 public function setTargetPageUid($targetPageUid) {
374 $this->targetPageUid
= $targetPageUid;
379 * returns $this->targetPageUid.
384 public function getTargetPageUid() {
385 return $this->targetPageUid
;
389 * Sets the page type of the target URI. Defaults to 0
391 * @param int $targetPageType
392 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
395 public function setTargetPageType($targetPageType) {
396 $this->targetPageType
= (int)$targetPageType;
403 public function getTargetPageType() {
404 return $this->targetPageType
;
408 * by default FALSE; if TRUE, &no_cache=1 will be appended to the URI
409 * This overrules the useCacheHash setting
411 * @param bool $noCache
412 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
415 public function setNoCache($noCache) {
416 $this->noCache
= (bool)$noCache;
424 public function getNoCache() {
425 return $this->noCache
;
429 * by default TRUE; if FALSE, no cHash parameter will be appended to the URI
430 * If noCache is set, this setting will be ignored.
432 * @param bool $useCacheHash
433 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
436 public function setUseCacheHash($useCacheHash) {
437 $this->useCacheHash
= (bool)$useCacheHash;
445 public function getUseCacheHash() {
446 return $this->useCacheHash
;
450 * Returns the arguments being used for the last URI being built.
451 * This is only set after build() / uriFor() has been called.
453 * @return array The last arguments
455 public function getLastArguments() {
456 return $this->lastArguments
;
460 * Resets all UriBuilder options to their default value
462 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
465 public function reset() {
466 $this->arguments
= array();
469 $this->createAbsoluteUri
= FALSE;
470 $this->addQueryString
= FALSE;
471 $this->addQueryStringMethod
= NULL;
472 $this->argumentsToBeExcludedFromQueryString
= array();
473 $this->linkAccessRestrictedPages
= FALSE;
474 $this->targetPageUid
= NULL;
475 $this->targetPageType
= 0;
476 $this->noCache
= FALSE;
477 $this->useCacheHash
= TRUE;
478 $this->argumentPrefix
= NULL;
483 * Creates an URI used for linking to an Extbase action.
484 * Works in Frontend and Backend mode of TYPO3.
486 * @param string $actionName Name of the action to be called
487 * @param array $controllerArguments Additional query parameters. Will be "namespaced" and merged with $this->arguments.
488 * @param string $controllerName Name of the target controller. If not set, current ControllerName is used.
489 * @param string $extensionName Name of the target extension, without underscores. If not set, current ExtensionName is used.
490 * @param string $pluginName Name of the target plugin. If not set, current PluginName is used.
491 * @return string the rendered URI
495 public function uriFor($actionName = NULL, $controllerArguments = array(), $controllerName = NULL, $extensionName = NULL, $pluginName = NULL) {
496 if ($actionName !== NULL) {
497 $controllerArguments['action'] = $actionName;
499 if ($controllerName !== NULL) {
500 $controllerArguments['controller'] = $controllerName;
502 $controllerArguments['controller'] = $this->request
->getControllerName();
504 if ($extensionName === NULL) {
505 $extensionName = $this->request
->getControllerExtensionName();
507 if ($pluginName === NULL && $this->environmentService
->isEnvironmentInFrontendMode()) {
508 $pluginName = $this->extensionService
->getPluginNameByAction($extensionName, $controllerArguments['controller'], $controllerArguments['action']);
510 if ($pluginName === NULL) {
511 $pluginName = $this->request
->getPluginName();
514 $this->disableCacheHashForNonCacheableAction($controllerArguments);
516 if ($this->environmentService
->isEnvironmentInFrontendMode() && $this->configurationManager
->isFeatureEnabled('skipDefaultArguments')) {
517 $controllerArguments = $this->removeDefaultControllerAndAction($controllerArguments, $extensionName, $pluginName);
519 if ($this->targetPageUid
=== NULL && $this->environmentService
->isEnvironmentInFrontendMode()) {
520 $this->targetPageUid
= $this->extensionService
->getTargetPidByPlugin($extensionName, $pluginName);
522 if ($this->format
!== '') {
523 $controllerArguments['format'] = $this->format
;
525 if ($this->argumentPrefix
!== NULL) {
526 $prefixedControllerArguments = array($this->argumentPrefix
=> $controllerArguments);
528 $pluginNamespace = $this->extensionService
->getPluginNamespace($extensionName, $pluginName);
529 $prefixedControllerArguments = array($pluginNamespace => $controllerArguments);
531 ArrayUtility
::mergeRecursiveWithOverrule($this->arguments
, $prefixedControllerArguments);
532 return $this->build();
536 * Disable cache hash if the action is not cacheable
537 * and pointed to from an already uncached request
539 * @param array $controllerArguments the current controller arguments
542 protected function disableCacheHashForNonCacheableAction(array $controllerArguments) {
543 if (isset($controllerArguments['action']) && $this->getUseCacheHash()) {
544 $actionIsCacheable = $this->extensionService
->isActionCacheable(
547 $controllerArguments['controller'],
548 $controllerArguments['action']
550 $this->setUseCacheHash($this->request
->isCached() ||
$actionIsCacheable);
555 * This removes controller and/or action arguments from given controllerArguments
556 * if they are equal to the default controller/action of the target plugin.
557 * Note: This is only active in FE mode and if feature "skipDefaultArguments" is enabled
559 * @see \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::isFeatureEnabled()
560 * @param array $controllerArguments the current controller arguments to be modified
561 * @param string $extensionName target extension name
562 * @param string $pluginName target plugin name
565 protected function removeDefaultControllerAndAction(array $controllerArguments, $extensionName, $pluginName) {
566 $defaultControllerName = $this->extensionService
->getDefaultControllerNameByPlugin($extensionName, $pluginName);
567 if (isset($controllerArguments['action'])) {
568 $defaultActionName = $this->extensionService
->getDefaultActionNameByPluginAndController($extensionName, $pluginName, $controllerArguments['controller']);
569 if ($controllerArguments['action'] === $defaultActionName) {
570 unset($controllerArguments['action']);
573 if ($controllerArguments['controller'] === $defaultControllerName) {
574 unset($controllerArguments['controller']);
576 return $controllerArguments;
581 * Depending on the current context this calls buildBackendUri() or buildFrontendUri()
583 * @return string The URI
585 * @see buildBackendUri()
586 * @see buildFrontendUri()
588 public function build() {
589 if ($this->environmentService
->isEnvironmentInBackendMode()) {
590 return $this->buildBackendUri();
592 return $this->buildFrontendUri();
597 * Builds the URI, backend flavour
598 * The resulting URI is relative and starts with "mod.php".
599 * The settings pageUid, pageType, noCache, useCacheHash & linkAccessRestrictedPages
600 * will be ignored in the backend.
602 * @return string The URI
604 public function buildBackendUri() {
605 if ($this->addQueryString
=== TRUE) {
606 if ($this->addQueryStringMethod
) {
607 switch ($this->addQueryStringMethod
) {
609 $arguments = GeneralUtility
::_GET();
612 $arguments = GeneralUtility
::_POST();
615 $arguments = array_replace_recursive(GeneralUtility
::_GET(), GeneralUtility
::_POST());
618 $arguments = array_replace_recursive(GeneralUtility
::_POST(), GeneralUtility
::_GET());
621 $arguments = GeneralUtility
::explodeUrl2Array(GeneralUtility
::getIndpEnv('QUERY_STRING'), TRUE);
624 $arguments = GeneralUtility
::_GET();
626 foreach ($this->argumentsToBeExcludedFromQueryString
as $argumentToBeExcluded) {
627 $argumentToBeExcluded = GeneralUtility
::explodeUrl2Array($argumentToBeExcluded, TRUE);
628 $arguments = ArrayUtility
::arrayDiffAssocRecursive($arguments, $argumentToBeExcluded);
632 'M' => GeneralUtility
::_GP('M'),
633 'id' => GeneralUtility
::_GP('id')
636 ArrayUtility
::mergeRecursiveWithOverrule($arguments, $this->arguments
);
637 $arguments = $this->convertDomainObjectsToIdentityArrays($arguments);
638 $this->lastArguments
= $arguments;
639 $moduleName = $arguments['M'];
640 unset($arguments['M'], $arguments['moduleToken']);
641 $uri = BackendUtility
::getModuleUrl($moduleName, $arguments, '');
642 if ($this->section
!== '') {
643 $uri .= '#' . $this->section
;
645 if ($this->createAbsoluteUri
=== TRUE) {
646 $uri = $this->request
->getBaseUri() . $uri;
652 * Builds the URI, frontend flavour
654 * @return string The URI
655 * @see buildTypolinkConfiguration()
657 public function buildFrontendUri() {
658 $typolinkConfiguration = $this->buildTypolinkConfiguration();
659 if ($this->createAbsoluteUri
=== TRUE) {
660 $typolinkConfiguration['forceAbsoluteUrl'] = TRUE;
661 if ($this->absoluteUriScheme
!== NULL) {
662 $typolinkConfiguration['forceAbsoluteUrl.']['scheme'] = $this->absoluteUriScheme
;
665 $uri = $this->contentObject
->typoLink_URL($typolinkConfiguration);
670 * Builds a TypoLink configuration array from the current settings
672 * @return array typolink configuration array
673 * @see TSref/typolink
675 protected function buildTypolinkConfiguration() {
676 $typolinkConfiguration = array();
677 $typolinkConfiguration['parameter'] = $this->targetPageUid
!== NULL ?
$this->targetPageUid
: $GLOBALS['TSFE']->id
;
678 if ($this->targetPageType
!== 0) {
679 $typolinkConfiguration['parameter'] .= ',' . $this->targetPageType
;
680 } elseif ($this->format
!== '') {
681 $targetPageType = $this->extensionService
->getTargetPageTypeByFormat($this->request
->getControllerExtensionKey(), $this->format
);
682 $typolinkConfiguration['parameter'] .= ',' . $targetPageType;
684 if (count($this->arguments
) > 0) {
685 $arguments = $this->convertDomainObjectsToIdentityArrays($this->arguments
);
686 $this->lastArguments
= $arguments;
687 $typolinkConfiguration['additionalParams'] = GeneralUtility
::implodeArrayForUrl(NULL, $arguments);
689 if ($this->addQueryString
=== TRUE) {
690 $typolinkConfiguration['addQueryString'] = 1;
691 if (count($this->argumentsToBeExcludedFromQueryString
) > 0) {
692 $typolinkConfiguration['addQueryString.'] = array(
693 'exclude' => implode(',', $this->argumentsToBeExcludedFromQueryString
)
696 if ($this->addQueryStringMethod
) {
697 $typolinkConfiguration['addQueryString.']['method'] = $this->addQueryStringMethod
;
700 if ($this->noCache
=== TRUE) {
701 $typolinkConfiguration['no_cache'] = 1;
702 } elseif ($this->useCacheHash
) {
703 $typolinkConfiguration['useCacheHash'] = 1;
705 if ($this->section
!== '') {
706 $typolinkConfiguration['section'] = $this->section
;
708 if ($this->linkAccessRestrictedPages
=== TRUE) {
709 $typolinkConfiguration['linkAccessRestrictedPages'] = 1;
711 return $typolinkConfiguration;
715 * Recursively iterates through the specified arguments and turns instances of type \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
716 * into an arrays containing the uid of the domain object.
718 * @param array $arguments The arguments to be iterated
719 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException
720 * @return array The modified arguments array
722 protected function convertDomainObjectsToIdentityArrays(array $arguments) {
723 foreach ($arguments as $argumentKey => $argumentValue) {
724 // if we have a LazyLoadingProxy here, make sure to get the real instance for further processing
725 if ($argumentValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy
) {
726 $argumentValue = $argumentValue->_loadRealInstance();
727 // also update the value in the arguments array, because the lazyLoaded object could be
728 // hidden and thus the $argumentValue would be NULL.
729 $arguments[$argumentKey] = $argumentValue;
731 if ($argumentValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject
) {
732 if ($argumentValue->getUid() !== NULL) {
733 $arguments[$argumentKey] = $argumentValue->getUid();
734 } elseif ($argumentValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject
) {
735 $arguments[$argumentKey] = $this->convertTransientObjectToArray($argumentValue);
737 throw new \TYPO3\CMS\Extbase\Mvc\Exception\
InvalidArgumentValueException('Could not serialize Domain Object ' . get_class($argumentValue) . '. It is neither an Entity with identity properties set, nor a Value Object.', 1260881688);
739 } elseif (is_array($argumentValue)) {
740 $arguments[$argumentKey] = $this->convertDomainObjectsToIdentityArrays($argumentValue);
747 * Converts a given object recursively into an array.
749 * @param \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object
751 * @todo Refactore this into convertDomainObjectsToIdentityArrays()
753 public function convertTransientObjectToArray(\TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject
$object) {
755 foreach ($object->_getProperties() as $propertyName => $propertyValue) {
756 if ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject
) {
757 if ($propertyValue->getUid() !== NULL) {
758 $result[$propertyName] = $propertyValue->getUid();
760 $result[$propertyName] = $this->convertTransientObjectToArray($propertyValue);
762 } elseif (is_array($propertyValue)) {
763 $result[$propertyName] = $this->convertDomainObjectsToIdentityArrays($propertyValue);
765 $result[$propertyName] = $propertyValue;