[!!!][TASK] Harden \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder 25/59625/12
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Mon, 15 Jul 2019 07:38:24 +0000 (09:38 +0200)
committerSusanne Moog <look@susi.dev>
Wed, 17 Jul 2019 08:36:42 +0000 (10:36 +0200)
- Use strict type mode
- Use type hints whereever possible

Releases: master
Resolves: #87629
Change-Id: I40d79cb6178886a6fc46edaf6c75fa900bf4ffc9
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/59625
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Benjamin Franzke <bfr@qbus.de>
Tested-by: Susanne Moog <look@susi.dev>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
Reviewed-by: Susanne Moog <look@susi.dev>
19 files changed:
typo3/sysext/core/Documentation/Changelog/master/Breaking-87594-HardenExtbase.rst
typo3/sysext/extbase/Classes/Mvc/Controller/AbstractController.php
typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php
typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/DownloadExtensionViewHelper.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/ReloadSqlDataViewHelper.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/RemoveExtensionViewHelper.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/ShowExtensionVersionsViewHelper.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/ToggleExtensionInstallationStateViewHelper.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/UpdateScriptViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Be/Menus/ActionMenuItemViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/FormViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Link/ActionViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Link/PageViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Uri/ActionViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Uri/PageViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Widget/LinkViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Widget/UriViewHelper.php
typo3/sysext/fluid/Tests/Unit/ViewHelpers/Link/PageViewHelperTest.php

index 23f2043..7ece6d5 100644 (file)
@@ -47,6 +47,34 @@ While hardening Extbase classes, method signatures changed due to an enforced st
 - :php:`\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::getContentObject`
 - :php:`\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::getConfiguration`
 - :php:`\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::isFeatureEnabled`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::reset()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::build()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::uriFor()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setAbsoluteUriScheme()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setAddQueryString()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setAddQueryStringMethod()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setArgumentPrefix()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setArguments()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setArgumentsToBeExcludedFromQueryString()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setCreateAbsoluteUri()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setFormat()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setLinkAccessRestrictedPages()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setNoCache()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setSection()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setTargetPageType()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setTargetPageUid()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setUseCacheHash()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getAddQueryString()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getAddQueryStringMethod()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getArguments()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getArgumentsToBeExcludedFromQueryString()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getCreateAbsoluteUri()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getFormat()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getLinkAccessRestrictedPages()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getNoCache()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getSection()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getTargetPageUid()`
+- :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::getUseCacheHash()`
 
 
 Impact
index 4758c5e..222692c 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Extbase\Mvc\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
 use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
@@ -281,7 +282,10 @@ abstract class AbstractController implements ControllerInterface
         if ($controllerName === null) {
             $controllerName = $this->request->getControllerName();
         }
-        $this->uriBuilder->reset()->setTargetPageUid($pageUid)->setCreateAbsoluteUri(true);
+        $this->uriBuilder->reset()->setCreateAbsoluteUri(true);
+        if (MathUtility::canBeInterpretedAsInteger($pageUid)) {
+            $this->uriBuilder->setTargetPageUid((int)$pageUid);
+        }
         if (\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SSL')) {
             $this->uriBuilder->setAbsoluteUriScheme('https');
         }
index 306c803..a324bdf 100644 (file)
@@ -1,4 +1,6 @@
 <?php
+declare(strict_types = 1);
+
 namespace TYPO3\CMS\Extbase\Mvc\Web\Routing;
 
 /*
@@ -45,7 +47,7 @@ class UriBuilder
     protected $contentObject;
 
     /**
-     * @var Request
+     * @var Request|null
      */
     protected $request;
 
@@ -84,7 +86,7 @@ class UriBuilder
     /**
      * @var string
      */
-    protected $addQueryStringMethod;
+    protected $addQueryStringMethod = '';
 
     /**
      * @var array
@@ -97,7 +99,7 @@ class UriBuilder
     protected $linkAccessRestrictedPages = false;
 
     /**
-     * @var int
+     * @var int|null
      */
     protected $targetPageUid;
 
@@ -117,7 +119,7 @@ class UriBuilder
     protected $format = '';
 
     /**
-     * @var string
+     * @var string|null
      */
     protected $argumentPrefix;
 
@@ -130,7 +132,7 @@ class UriBuilder
      * @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
+    public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager): void
     {
         $this->configurationManager = $configurationManager;
     }
@@ -139,7 +141,7 @@ class UriBuilder
      * @param \TYPO3\CMS\Extbase\Service\ExtensionService $extensionService
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function injectExtensionService(\TYPO3\CMS\Extbase\Service\ExtensionService $extensionService)
+    public function injectExtensionService(\TYPO3\CMS\Extbase\Service\ExtensionService $extensionService): void
     {
         $this->extensionService = $extensionService;
     }
@@ -148,7 +150,7 @@ class UriBuilder
      * @param \TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function injectEnvironmentService(\TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService)
+    public function injectEnvironmentService(\TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService): void
     {
         $this->environmentService = $environmentService;
     }
@@ -157,7 +159,7 @@ class UriBuilder
      * Life-cycle method that is called by the DI container as soon as this object is completely built
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function initializeObject()
+    public function initializeObject(): void
     {
         $this->contentObject = $this->configurationManager->getContentObject();
     }
@@ -166,20 +168,20 @@ class UriBuilder
      * Sets the current request
      *
      * @param Request $request
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function setRequest(Request $request)
+    public function setRequest(Request $request): UriBuilder
     {
         $this->request = $request;
         return $this;
     }
 
     /**
-     * @return Request
+     * @return Request|null
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function getRequest()
+    public function getRequest(): ?Request
     {
         return $this->request;
     }
@@ -190,9 +192,9 @@ class UriBuilder
      * array('prefix1' => array('foo' => 'bar')) gets "&prefix1[foo]=bar"
      *
      * @param array $arguments
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setArguments(array $arguments)
+    public function setArguments(array $arguments): UriBuilder
     {
         $this->arguments = $arguments;
         return $this;
@@ -200,8 +202,9 @@ class UriBuilder
 
     /**
      * @return array
+     * @internal
      */
-    public function getArguments()
+    public function getArguments(): array
     {
         return $this->arguments;
     }
@@ -210,9 +213,9 @@ class UriBuilder
      * If specified, adds a given HTML anchor to the URI (#...)
      *
      * @param string $section
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setSection($section)
+    public function setSection(string $section): UriBuilder
     {
         $this->section = $section;
         return $this;
@@ -220,8 +223,9 @@ class UriBuilder
 
     /**
      * @return string
+     * @internal
      */
-    public function getSection()
+    public function getSection(): string
     {
         return $this->section;
     }
@@ -230,9 +234,9 @@ class UriBuilder
      * Specifies the format of the target (e.g. "html" or "xml")
      *
      * @param string $format
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setFormat($format)
+    public function setFormat(string $format): UriBuilder
     {
         $this->format = $format;
         return $this;
@@ -240,8 +244,9 @@ class UriBuilder
 
     /**
      * @return string
+     * @internal
      */
-    public function getFormat()
+    public function getFormat(): string
     {
         return $this->format;
     }
@@ -250,9 +255,9 @@ class UriBuilder
      * If set, the URI is prepended with the current base URI. Defaults to FALSE.
      *
      * @param bool $createAbsoluteUri
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setCreateAbsoluteUri($createAbsoluteUri)
+    public function setCreateAbsoluteUri(bool $createAbsoluteUri): UriBuilder
     {
         $this->createAbsoluteUri = $createAbsoluteUri;
         return $this;
@@ -260,17 +265,18 @@ class UriBuilder
 
     /**
      * @return bool
+     * @internal
      */
-    public function getCreateAbsoluteUri()
+    public function getCreateAbsoluteUri(): bool
     {
         return $this->createAbsoluteUri;
     }
 
     /**
-     * @return string
+     * @return string|null
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function getAbsoluteUriScheme()
+    public function getAbsoluteUriScheme(): ?string
     {
         return $this->absoluteUriScheme;
     }
@@ -279,10 +285,9 @@ class UriBuilder
      * Sets the scheme that should be used for absolute URIs in FE mode
      *
      * @param string $absoluteUriScheme the scheme to be used for absolute URIs
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setAbsoluteUriScheme($absoluteUriScheme)
+    public function setAbsoluteUriScheme(string $absoluteUriScheme): UriBuilder
     {
         $this->absoluteUriScheme = $absoluteUriScheme;
         return $this;
@@ -292,32 +297,39 @@ class UriBuilder
      * If set, the current query parameters will be merged with $this->arguments. Defaults to FALSE.
      *
      * @param bool $addQueryString
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      * @see TSref/typolink.addQueryString
      */
-    public function setAddQueryString($addQueryString)
+    public function setAddQueryString(bool $addQueryString): UriBuilder
     {
-        $this->addQueryString = (bool)$addQueryString;
+        $this->addQueryString = $addQueryString;
         return $this;
     }
 
     /**
      * @return bool
+     * @internal
      */
-    public function getAddQueryString()
+    public function getAddQueryString(): bool
     {
         return $this->addQueryString;
     }
 
     /**
-     * Sets the method to get the addQueryString parameters. Defaults undefined
-     * which results in using QUERY_STRING.
+     * Sets the method to get the addQueryString parameters. Defaults to an empty string
+     * which results in calling GeneralUtility::getIndpEnv('QUERY_STRING').
+     *
+     * Possible values are:
+     * - GET
+     * - POST
+     * - GET,POST
+     * - POST,GET
      *
      * @param string $addQueryStringMethod
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      * @see TSref/typolink.addQueryString.method
      */
-    public function setAddQueryStringMethod($addQueryStringMethod)
+    public function setAddQueryStringMethod(string $addQueryStringMethod): UriBuilder
     {
         $this->addQueryStringMethod = $addQueryStringMethod;
         return $this;
@@ -325,10 +337,11 @@ class UriBuilder
 
     /**
      * @return string
+     * @internal
      */
-    public function getAddQueryStringMethod()
+    public function getAddQueryStringMethod(): string
     {
-        return (string)$this->addQueryStringMethod;
+        return $this->addQueryStringMethod;
     }
 
     /**
@@ -336,11 +349,11 @@ class UriBuilder
      * Only active if addQueryString is set
      *
      * @param array $argumentsToBeExcludedFromQueryString
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      * @see TSref/typolink.addQueryString.exclude
      * @see setAddQueryString()
      */
-    public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString)
+    public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString): UriBuilder
     {
         $this->argumentsToBeExcludedFromQueryString = $argumentsToBeExcludedFromQueryString;
         return $this;
@@ -348,8 +361,9 @@ class UriBuilder
 
     /**
      * @return array
+     * @internal
      */
-    public function getArgumentsToBeExcludedFromQueryString()
+    public function getArgumentsToBeExcludedFromQueryString(): array
     {
         return $this->argumentsToBeExcludedFromQueryString;
     }
@@ -358,20 +372,19 @@ class UriBuilder
      * Specifies the prefix to be used for all arguments.
      *
      * @param string $argumentPrefix
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setArgumentPrefix($argumentPrefix)
+    public function setArgumentPrefix(string $argumentPrefix): UriBuilder
     {
-        $this->argumentPrefix = (string)$argumentPrefix;
+        $this->argumentPrefix = $argumentPrefix;
         return $this;
     }
 
     /**
-     * @return string
+     * @return string|null
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function getArgumentPrefix()
+    public function getArgumentPrefix(): ?string
     {
         return $this->argumentPrefix;
     }
@@ -380,18 +393,19 @@ class UriBuilder
      * If set, URIs for pages without access permissions will be created
      *
      * @param bool $linkAccessRestrictedPages
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setLinkAccessRestrictedPages($linkAccessRestrictedPages)
+    public function setLinkAccessRestrictedPages(bool $linkAccessRestrictedPages): UriBuilder
     {
-        $this->linkAccessRestrictedPages = (bool)$linkAccessRestrictedPages;
+        $this->linkAccessRestrictedPages = $linkAccessRestrictedPages;
         return $this;
     }
 
     /**
      * @return bool
+     * @internal
      */
-    public function getLinkAccessRestrictedPages()
+    public function getLinkAccessRestrictedPages(): bool
     {
         return $this->linkAccessRestrictedPages;
     }
@@ -400,9 +414,9 @@ class UriBuilder
      * Uid of the target page
      *
      * @param int $targetPageUid
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setTargetPageUid($targetPageUid)
+    public function setTargetPageUid(int $targetPageUid): UriBuilder
     {
         $this->targetPageUid = $targetPageUid;
         return $this;
@@ -411,9 +425,10 @@ class UriBuilder
     /**
      * returns $this->targetPageUid.
      *
-     * @return int
+     * @return int|null
+     * @internal
      */
-    public function getTargetPageUid()
+    public function getTargetPageUid(): ?int
     {
         return $this->targetPageUid;
     }
@@ -422,11 +437,11 @@ class UriBuilder
      * Sets the page type of the target URI. Defaults to 0
      *
      * @param int $targetPageType
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setTargetPageType($targetPageType)
+    public function setTargetPageType(int $targetPageType): UriBuilder
     {
-        $this->targetPageType = (int)$targetPageType;
+        $this->targetPageType = $targetPageType;
         return $this;
     }
 
@@ -434,7 +449,7 @@ class UriBuilder
      * @return int
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function getTargetPageType()
+    public function getTargetPageType(): int
     {
         return $this->targetPageType;
     }
@@ -443,18 +458,19 @@ class UriBuilder
      * by default FALSE; if TRUE, &no_cache=1 will be appended to the URI
      *
      * @param bool $noCache
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setNoCache($noCache)
+    public function setNoCache(bool $noCache): UriBuilder
     {
-        $this->noCache = (bool)$noCache;
+        $this->noCache = $noCache;
         return $this;
     }
 
     /**
      * @return bool
+     * @internal
      */
-    public function getNoCache()
+    public function getNoCache(): bool
     {
         return $this->noCache;
     }
@@ -463,10 +479,9 @@ class UriBuilder
      * by default TRUE; if FALSE, no cHash parameter will be appended to the URI
      * If noCache is set, this setting will be ignored.
      *
-     * @param bool $useCacheHash
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function setUseCacheHash($useCacheHash)
+    public function setUseCacheHash(): UriBuilder
     {
         trigger_error('Calling UriBuilder->setUseCacheHash() will be removed in TYPO3 v11.0. TYPO3 Core routing is taking care of handling this argument. Simply remove the line to avoid the notice.', E_USER_DEPRECATED);
         return $this;
@@ -474,8 +489,9 @@ class UriBuilder
 
     /**
      * @return bool
+     * @internal
      */
-    public function getUseCacheHash()
+    public function getUseCacheHash(): bool
     {
         trigger_error('Calling UriBuilder->getUseCacheHash() will be removed in TYPO3 v11.0. TYPO3 Core routing is taking care of handling this argument. Simply remove the line to avoid the notice.', E_USER_DEPRECATED);
         return true;
@@ -488,7 +504,7 @@ class UriBuilder
      * @return array The last arguments
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function getLastArguments()
+    public function getLastArguments(): array
     {
         return $this->lastArguments;
     }
@@ -496,22 +512,28 @@ class UriBuilder
     /**
      * Resets all UriBuilder options to their default value
      *
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
+     * @return static the current UriBuilder to allow method chaining
      */
-    public function reset()
+    public function reset(): UriBuilder
     {
         $this->arguments = [];
         $this->section = '';
         $this->format = '';
         $this->createAbsoluteUri = false;
         $this->addQueryString = false;
-        $this->addQueryStringMethod = null;
+        $this->addQueryStringMethod = '';
         $this->argumentsToBeExcludedFromQueryString = [];
         $this->linkAccessRestrictedPages = false;
         $this->targetPageUid = null;
         $this->targetPageType = 0;
         $this->noCache = false;
         $this->argumentPrefix = null;
+        $this->absoluteUriScheme = null;
+        /*
+         * $this->request MUST NOT be reset here because the request is actually a hard dependency and not part
+         * of the internal state of this object.
+         * todo: consider making the request a constructor dependency or get rid of it's usage
+         */
         return $this;
     }
 
@@ -519,16 +541,23 @@ class UriBuilder
      * Creates an URI used for linking to an Extbase action.
      * Works in Frontend and Backend mode of TYPO3.
      *
-     * @param string $actionName Name of the action to be called
-     * @param array $controllerArguments Additional query parameters. Will be "namespaced" and merged with $this->arguments.
-     * @param string $controllerName Name of the target controller. If not set, current ControllerName is used.
-     * @param string $extensionName Name of the target extension, without underscores. If not set, current ExtensionName is used.
-     * @param string $pluginName Name of the target plugin. If not set, current PluginName is used.
+     * @param string|null $actionName Name of the action to be called
+     * @param array|null $controllerArguments Additional query parameters. Will be "namespaced" and merged with $this->arguments.
+     * @param string|null $controllerName Name of the target controller. If not set, current ControllerName is used.
+     * @param string|null $extensionName Name of the target extension, without underscores. If not set, current ExtensionName is used.
+     * @param string|null $pluginName Name of the target plugin. If not set, current PluginName is used.
      * @return string the rendered URI
      * @see build()
      */
-    public function uriFor($actionName = null, $controllerArguments = [], $controllerName = null, $extensionName = null, $pluginName = null)
-    {
+    public function uriFor(
+        ?string $actionName = null,
+        ?array $controllerArguments = null,
+        ?string $controllerName = null,
+        ?string $extensionName = null,
+        ?string $pluginName = null
+    ): string {
+        $controllerArguments = $controllerArguments ?? [];
+
         if ($actionName !== null) {
             $controllerArguments['action'] = $actionName;
         }
@@ -576,7 +605,7 @@ class UriBuilder
      * @param string $pluginName target plugin name
      * @return array
      */
-    protected function removeDefaultControllerAndAction(array $controllerArguments, $extensionName, $pluginName)
+    protected function removeDefaultControllerAndAction(array $controllerArguments, string $extensionName, string $pluginName): array
     {
         $defaultControllerName = $this->extensionService->getDefaultControllerNameByPlugin($extensionName, $pluginName);
         if (isset($controllerArguments['action'])) {
@@ -599,7 +628,7 @@ class UriBuilder
      * @see buildBackendUri()
      * @see buildFrontendUri()
      */
-    public function build()
+    public function build(): string
     {
         if ($this->environmentService->isEnvironmentInBackendMode()) {
             return $this->buildBackendUri();
@@ -615,8 +644,9 @@ class UriBuilder
      *
      * @return string The URI
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getQueryArguments
      */
-    public function buildBackendUri()
+    public function buildBackendUri(): string
     {
         $arguments = [];
         if ($this->addQueryString === true) {
@@ -692,7 +722,7 @@ class UriBuilder
      * @see buildTypolinkConfiguration()
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function buildFrontendUri()
+    public function buildFrontendUri(): string
     {
         $typolinkConfiguration = $this->buildTypolinkConfiguration();
         if ($this->createAbsoluteUri === true) {
@@ -701,7 +731,9 @@ class UriBuilder
                 $typolinkConfiguration['forceAbsoluteUrl.']['scheme'] = $this->absoluteUriScheme;
             }
         }
-        $uri = $this->contentObject->typoLink_URL($typolinkConfiguration);
+        // Other than stated in the doc block, typoLink_URL does not always return a string
+        // Thus, we explicitly cast to string here.
+        $uri = (string)$this->contentObject->typoLink_URL($typolinkConfiguration);
         return $uri;
     }
 
@@ -711,7 +743,7 @@ class UriBuilder
      * @return array typolink configuration array
      * @see TSref/typolink
      */
-    protected function buildTypolinkConfiguration()
+    protected function buildTypolinkConfiguration(): array
     {
         $typolinkConfiguration = [];
         $typolinkConfiguration['parameter'] = $this->targetPageUid ?? $GLOBALS['TSFE']->id;
@@ -733,7 +765,7 @@ class UriBuilder
                     'exclude' => implode(',', $this->argumentsToBeExcludedFromQueryString)
                 ];
             }
-            if ($this->addQueryStringMethod) {
+            if ($this->addQueryStringMethod !== '') {
                 $typolinkConfiguration['addQueryString.']['method'] = $this->addQueryStringMethod;
             }
         }
@@ -757,7 +789,7 @@ class UriBuilder
      * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException
      * @return array The modified arguments array
      */
-    protected function convertDomainObjectsToIdentityArrays(array $arguments)
+    protected function convertDomainObjectsToIdentityArrays(array $arguments): array
     {
         foreach ($arguments as $argumentKey => $argumentValue) {
             // if we have a LazyLoadingProxy here, make sure to get the real instance for further processing
@@ -789,7 +821,7 @@ class UriBuilder
      * @param \Iterator $iterator
      * @return array
      */
-    protected function convertIteratorToArray(\Iterator $iterator)
+    protected function convertIteratorToArray(\Iterator $iterator): array
     {
         if (method_exists($iterator, 'toArray')) {
             $array = $iterator->toArray();
@@ -807,7 +839,7 @@ class UriBuilder
      * @todo Refactore this into convertDomainObjectsToIdentityArrays()
      * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
-    public function convertTransientObjectToArray(\TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object)
+    public function convertTransientObjectToArray(\TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object): array
     {
         $result = [];
         foreach ($object->_getProperties() as $propertyName => $propertyValue) {
index 61ffb83..fbc34ce 100644 (file)
@@ -227,7 +227,6 @@ class UriBuilderTest extends UnitTestCase
         $_POST = [];
         $_POST['foo2'] = 'bar2';
         $this->uriBuilder->setAddQueryString(true);
-        $this->uriBuilder->setAddQueryStringMethod(null);
         $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&id=pageId&foo=bar';
         $actualResult = $this->uriBuilder->buildBackendUri();
         $this->assertEquals($expectedResult, $actualResult);
@@ -560,7 +559,22 @@ class UriBuilderTest extends UnitTestCase
      */
     public function resetSetsAllOptionsToTheirDefaultValue()
     {
-        $this->uriBuilder->setArguments(['test' => 'arguments'])->setSection('testSection')->setFormat('someFormat')->setCreateAbsoluteUri(true)->setAddQueryString(true)->setArgumentsToBeExcludedFromQueryString(['test' => 'addQueryStringExcludeArguments'])->setAddQueryStringMethod(null)->setArgumentPrefix('testArgumentPrefix')->setLinkAccessRestrictedPages(true)->setTargetPageUid(123)->setTargetPageType(321)->setNoCache(true);
+        $this->uriBuilder
+            ->setArguments(['test' => 'arguments'])
+            ->setSection('testSection')
+            ->setFormat('someFormat')
+            ->setCreateAbsoluteUri(true)
+            ->setAddQueryString(true)
+            ->setAddQueryStringMethod('test')
+            ->setArgumentsToBeExcludedFromQueryString(['test' => 'addQueryStringExcludeArguments'])
+            ->setLinkAccessRestrictedPages(true)
+            ->setTargetPageUid(123)
+            ->setTargetPageType(321)
+            ->setNoCache(true)
+            ->setArgumentPrefix('testArgumentPrefix')
+            ->setAbsoluteUriScheme('test')
+        ;
+
         $this->uriBuilder->reset();
         $this->assertEquals([], $this->uriBuilder->getArguments());
         $this->assertEquals('', $this->uriBuilder->getSection());
@@ -568,12 +582,14 @@ class UriBuilderTest extends UnitTestCase
         $this->assertEquals(false, $this->uriBuilder->getCreateAbsoluteUri());
         $this->assertEquals(false, $this->uriBuilder->getAddQueryString());
         $this->assertEquals([], $this->uriBuilder->getArgumentsToBeExcludedFromQueryString());
-        $this->assertEquals(null, $this->uriBuilder->getAddQueryStringMethod());
-        $this->assertEquals(null, $this->uriBuilder->getArgumentPrefix());
+        $this->assertEquals('', $this->uriBuilder->getAddQueryStringMethod());
+        $this->assertEquals('', $this->uriBuilder->getArgumentPrefix());
         $this->assertEquals(false, $this->uriBuilder->getLinkAccessRestrictedPages());
         $this->assertEquals(null, $this->uriBuilder->getTargetPageUid());
         $this->assertEquals(0, $this->uriBuilder->getTargetPageType());
         $this->assertEquals(false, $this->uriBuilder->getNoCache());
+        $this->assertEquals(false, $this->uriBuilder->getNoCache());
+        $this->assertEquals(null, $this->uriBuilder->getAbsoluteUriScheme());
     }
 
     /**
index b24a62c..959666e 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Extensionmanager\ViewHelpers;
 
 use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
 use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
 
@@ -79,6 +80,7 @@ class DownloadExtensionViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\Abst
                        </li>';
         }
         $pathSelector .= '</ul>';
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $action = 'checkDependencies';
         $uriBuilder->reset();
index 954b3ba..5bfc4dd 100644 (file)
@@ -19,6 +19,7 @@ use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Registry;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
 use TYPO3\CMS\Fluid\ViewHelpers\Link\ActionViewHelper;
 
@@ -73,6 +74,7 @@ class ReloadSqlDataViewHelper extends ActionViewHelper
             $languageKey = 'extensionList.databaseImport';
         }
 
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $uriBuilder->reset();
         $uri = $uriBuilder->uriFor('reloadExtensionData', ['extension' => $extension['key']], 'Action');
index ec4e451..a65d233 100644 (file)
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Extensionmanager\ViewHelpers;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Fluid\ViewHelpers\Link\ActionViewHelper;
 
 /**
@@ -54,6 +55,7 @@ class RemoveExtensionViewHelper extends ActionViewHelper
         ) {
             return '<span class="btn btn-default disabled">' . $iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>';
         }
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $action = 'removeExtension';
         $uriBuilder->reset();
index 0e74579..439c412 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Extensionmanager\ViewHelpers;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
 use TYPO3\CMS\Fluid\ViewHelpers\Link\ActionViewHelper;
 
@@ -47,6 +48,7 @@ class ShowExtensionVersionsViewHelper extends ActionViewHelper
         /** @var Extension $extension */
         $extension = $this->arguments['extension'];
 
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $action = 'showAllVersions';
         $uri = $uriBuilder->reset()->uriFor($action, [
index fad3b7f..90fe804 100644 (file)
@@ -18,6 +18,7 @@ use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
 use TYPO3\CMS\Fluid\ViewHelpers\Link\ActionViewHelper;
 
@@ -68,6 +69,7 @@ class ToggleExtensionInstallationStateViewHelper extends ActionViewHelper
             return '';
         }
 
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $action = 'toggleExtensionInstallationState';
         $uri = $uriBuilder->reset()->uriFor($action, [
index 4c81dfc..1fc5122 100644 (file)
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Extensionmanager\ViewHelpers;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Fluid\ViewHelpers\Link\ActionViewHelper;
 
 /**
@@ -61,6 +62,7 @@ class UpdateScriptViewHelper extends ActionViewHelper
         /** @var IconFactory $iconFactory */
         $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
         if ($updateScriptUtility->checkUpdateScriptExists($extensionKey)) {
+            /** @var UriBuilder $uriBuilder */
             $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
             $action = 'show';
             $uri = $uriBuilder->reset()->uriFor(
index 3cc72a7..adeccbc 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Be\Menus;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
 
 /**
@@ -79,6 +80,7 @@ class ActionMenuItemViewHelper extends AbstractTagBasedViewHelper
         $action = $this->arguments['action'];
         $arguments = $this->arguments['arguments'];
 
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $uri = $uriBuilder->reset()->uriFor($action, $arguments, $controller);
         $this->tag->addAttribute('value', $uri);
index 57c0e0c..0e98528 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Fluid\ViewHelpers;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
+
 /**
  * Form ViewHelper. Generates a :html:`<form>` Tag.
  *
@@ -199,28 +201,37 @@ class FormViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormViewH
             if (isset($this->arguments['noCacheHash'])) {
                 trigger_error('Using the argument "noCacheHash" in <f:form> ViewHelper has no effect anymore. Remove the argument in your fluid template, as it will result in a fatal error.', E_USER_DEPRECATED);
             }
-
-            $pageUid = (isset($this->arguments['pageUid']) && (int)$this->arguments['pageUid'] > 0) ? (int)$this->arguments['pageUid'] : null;
+            /** @var UriBuilder $uriBuilder */
             $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
-            $formActionUri = $uriBuilder
+            $uriBuilder
                 ->reset()
-                ->setTargetPageUid($pageUid)
                 ->setTargetPageType($this->arguments['pageType'] ?? 0)
                 ->setNoCache($this->arguments['noCache'] ?? false)
                 ->setSection($this->arguments['section'] ?? '')
                 ->setCreateAbsoluteUri($this->arguments['absolute'] ?? false)
                 ->setArguments(isset($this->arguments['additionalParams']) ? (array)$this->arguments['additionalParams'] : [])
                 ->setAddQueryString($this->arguments['addQueryString'] ?? false)
-                ->setAddQueryStringMethod($this->arguments['addQueryStringMethod'] ?? null)
                 ->setArgumentsToBeExcludedFromQueryString(isset($this->arguments['argumentsToBeExcludedFromQueryString']) ? (array)$this->arguments['argumentsToBeExcludedFromQueryString'] : [])
                 ->setFormat($this->arguments['format'] ?? '')
-                ->uriFor(
-                    $this->arguments['action'] ?? null,
-                    $this->arguments['arguments'] ?? [],
-                    $this->arguments['controller'] ?? null,
-                    $this->arguments['extensionName'] ?? null,
-                    $this->arguments['pluginName'] ?? null
-                );
+            ;
+
+            $addQueryStringMethod = $this->arguments['addQueryStringMethod'] ?? null;
+            if (is_string($addQueryStringMethod)) {
+                $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+            }
+
+            $pageUid = (int)($this->arguments['pageUid'] ?? 0);
+            if ($pageUid > 0) {
+                $uriBuilder->setTargetPageUid($pageUid);
+            }
+
+            $formActionUri = $uriBuilder->uriFor(
+                $this->arguments['action'] ?? null,
+                $this->arguments['arguments'] ?? [],
+                $this->arguments['controller'] ?? null,
+                $this->arguments['extensionName'] ?? null,
+                $this->arguments['pluginName'] ?? null
+            );
             $this->formActionUriArguments = $uriBuilder->getArguments();
         }
         $this->tag->addAttribute('action', $formActionUri);
index 11cfea3..d4c1f3b 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Link;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
 
 /**
@@ -94,10 +96,10 @@ class ActionViewHelper extends AbstractTagBasedViewHelper
         $argumentsToBeExcludedFromQueryString = (array)$this->arguments['argumentsToBeExcludedFromQueryString'];
         $addQueryStringMethod = $this->arguments['addQueryStringMethod'];
         $parameters = $this->arguments['arguments'];
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
-        $uri = $uriBuilder
+        $uriBuilder
             ->reset()
-            ->setTargetPageUid($pageUid)
             ->setTargetPageType($pageType)
             ->setNoCache($noCache)
             ->setSection($section)
@@ -107,8 +109,17 @@ class ActionViewHelper extends AbstractTagBasedViewHelper
             ->setCreateAbsoluteUri($absolute)
             ->setAddQueryString($addQueryString)
             ->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)
-            ->setAddQueryStringMethod($addQueryStringMethod)
-            ->uriFor($action, $parameters, $controller, $extensionName, $pluginName);
+        ;
+
+        if (MathUtility::canBeInterpretedAsInteger($pageUid)) {
+            $uriBuilder->setTargetPageUid((int)$pageUid);
+        }
+
+        if (is_string($addQueryStringMethod)) {
+            $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+        }
+
+        $uri = $uriBuilder->uriFor($action, $parameters, $controller, $extensionName, $pluginName);
         $this->tag->addAttribute('href', $uri);
         $this->tag->setContent($this->renderChildren());
         $this->tag->forceClosingTag(true);
index 6aead9f..b67807a 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Link;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
 
 /**
@@ -109,9 +111,9 @@ class PageViewHelper extends AbstractTagBasedViewHelper
         $addQueryString = isset($this->arguments['addQueryString']) ? (bool)$this->arguments['addQueryString'] : false;
         $argumentsToBeExcludedFromQueryString = isset($this->arguments['argumentsToBeExcludedFromQueryString']) ? (array)$this->arguments['argumentsToBeExcludedFromQueryString'] : [];
         $addQueryStringMethod = $this->arguments['addQueryStringMethod'] ?? null;
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
-        $uri = $uriBuilder->reset()
-            ->setTargetPageUid($pageUid)
+        $uriBuilder->reset()
             ->setTargetPageType($pageType)
             ->setNoCache($noCache)
             ->setSection($section)
@@ -120,9 +122,18 @@ class PageViewHelper extends AbstractTagBasedViewHelper
             ->setCreateAbsoluteUri($absolute)
             ->setAddQueryString($addQueryString)
             ->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)
-            ->setAddQueryStringMethod($addQueryStringMethod)
-            ->build();
-        if ((string)$uri !== '') {
+        ;
+
+        if (MathUtility::canBeInterpretedAsInteger($pageUid)) {
+            $uriBuilder->setTargetPageUid((int)$pageUid);
+        }
+
+        if (is_string($addQueryStringMethod)) {
+            $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+        }
+
+        $uri = $uriBuilder->build();
+        if ($uri !== '') {
             $this->tag->addAttribute('href', $uri);
             $this->tag->setContent($this->renderChildren());
             $this->tag->forceClosingTag(true);
index 8708c00..b3fc9b4 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Uri;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
@@ -69,40 +70,90 @@ class ActionViewHelper extends AbstractViewHelper
      */
     public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
     {
-        $pageUid = $arguments['pageUid'];
-        $pageType = $arguments['pageType'];
-        $noCache = $arguments['noCache'];
+        /** @var int $pageUid */
+        $pageUid = $arguments['pageUid'] ?? 0;
+        /** @var int $pageType */
+        $pageType = $arguments['pageType'] ?? 0;
+        /** @var bool $noCache */
+        $noCache = $arguments['noCache'] ?? false;
         if (isset($arguments['noCacheHash'])) {
             trigger_error('Using the argument "noCacheHash" in <f:uri.action> ViewHelper has no effect anymore. Remove the argument in your fluid template, as it will result in a fatal error.', E_USER_DEPRECATED);
         }
-        $section = $arguments['section'];
-        $format = $arguments['format'];
-        $linkAccessRestrictedPages = $arguments['linkAccessRestrictedPages'];
-        $additionalParams = $arguments['additionalParams'];
-        $absolute = $arguments['absolute'];
-        $addQueryString = $arguments['addQueryString'];
-        $argumentsToBeExcludedFromQueryString = $arguments['argumentsToBeExcludedFromQueryString'];
-        $addQueryStringMethod = $arguments['addQueryStringMethod'];
-        $action = $arguments['action'];
-        $controller = $arguments['controller'];
-        $extensionName = $arguments['extensionName'];
-        $pluginName = $arguments['pluginName'];
-        $arguments = $arguments['arguments'];
-
-        $uri = $renderingContext->getControllerContext()->getUriBuilder()
-            ->reset()
-            ->setTargetPageUid($pageUid)
-            ->setTargetPageType($pageType)
-            ->setNoCache($noCache)
-            ->setSection($section)
-            ->setFormat($format)
-            ->setLinkAccessRestrictedPages($linkAccessRestrictedPages)
-            ->setArguments($additionalParams)
-            ->setCreateAbsoluteUri($absolute)
-            ->setAddQueryString($addQueryString)
-            ->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)
-            ->setAddQueryStringMethod($addQueryStringMethod)
-            ->uriFor($action, $arguments, $controller, $extensionName, $pluginName);
-        return $uri;
+        /** @var string|null $section */
+        $section = $arguments['section'] ?? null;
+        /** @var string|null $format */
+        $format = $arguments['format'] ?? null;
+        /** @var bool $linkAccessRestrictedPages */
+        $linkAccessRestrictedPages = $arguments['linkAccessRestrictedPages'] ?? false;
+        /** @var array|null $additionalParams */
+        $additionalParams = $arguments['additionalParams'] ?? null;
+        /** @var bool $absolute */
+        $absolute = $arguments['absolute'] ?? false;
+        /** @var bool $addQueryString */
+        $addQueryString = $arguments['addQueryString'] ?? false;
+        /** @var array|null $argumentsToBeExcludedFromQueryString */
+        $argumentsToBeExcludedFromQueryString = $arguments['argumentsToBeExcludedFromQueryString'] ?? null;
+        /** @var string $addQueryStringMethod */
+        $addQueryStringMethod = $arguments['addQueryStringMethod'] ?? '';
+        /** @var string|null $action */
+        $action = $arguments['action'] ?? null;
+        /** @var string|null $controller */
+        $controller = $arguments['controller'] ?? null;
+        /** @var string|null $extensionName */
+        $extensionName = $arguments['extensionName'] ?? null;
+        /** @var string|null $pluginName */
+        $pluginName = $arguments['pluginName'] ?? null;
+        /** @var array|null $arguments */
+        $arguments = $arguments['arguments'] ?? [];
+
+        /** @var UriBuilder $uriBuilder */
+        $uriBuilder = $renderingContext->getControllerContext()->getUriBuilder();
+        $uriBuilder->reset();
+
+        if ($pageUid > 0) {
+            $uriBuilder->setTargetPageType($pageUid);
+        }
+
+        if ($pageType > 0) {
+            $uriBuilder->setTargetPageUid($pageType);
+        }
+
+        if ($noCache === true) {
+            $uriBuilder->setNoCache($noCache);
+        }
+
+        if (is_string($section)) {
+            $uriBuilder->setSection($section);
+        }
+
+        if (is_string($format)) {
+            $uriBuilder->setFormat($format);
+        }
+
+        if (is_array($additionalParams)) {
+            $uriBuilder->setArguments($additionalParams);
+        }
+
+        if ($absolute === true) {
+            $uriBuilder->setCreateAbsoluteUri($absolute);
+        }
+
+        if ($addQueryString === true) {
+            $uriBuilder->setAddQueryString($addQueryString);
+        }
+
+        if (is_array($argumentsToBeExcludedFromQueryString)) {
+            $uriBuilder->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString);
+        }
+
+        if ($addQueryStringMethod !== '') {
+            $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+        }
+
+        if ($linkAccessRestrictedPages === true) {
+            $uriBuilder->setLinkAccessRestrictedPages($linkAccessRestrictedPages);
+        }
+
+        return $uriBuilder->uriFor($action, $arguments, $controller, $extensionName, $pluginName);
     }
 }
index 75194c7..ada39dd 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Uri;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
@@ -102,8 +104,28 @@ class PageViewHelper extends AbstractViewHelper
         $argumentsToBeExcludedFromQueryString = $arguments['argumentsToBeExcludedFromQueryString'];
         $addQueryStringMethod = $arguments['addQueryStringMethod'];
 
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $renderingContext->getControllerContext()->getUriBuilder();
-        $uri = $uriBuilder->setTargetPageUid($pageUid)->setTargetPageType($pageType)->setNoCache($noCache)->setSection($section)->setLinkAccessRestrictedPages($linkAccessRestrictedPages)->setArguments($additionalParams)->setCreateAbsoluteUri($absolute)->setAddQueryString($addQueryString)->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)->setAddQueryStringMethod($addQueryStringMethod)->build();
-        return $uri;
+        $uri = $uriBuilder
+            ->reset()
+            ->setTargetPageType($pageType)
+            ->setNoCache($noCache)
+            ->setSection($section)
+            ->setLinkAccessRestrictedPages($linkAccessRestrictedPages)
+            ->setArguments($additionalParams)
+            ->setCreateAbsoluteUri($absolute)
+            ->setAddQueryString($addQueryString)
+            ->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)
+        ;
+
+        if (MathUtility::canBeInterpretedAsInteger($pageUid)) {
+            $uriBuilder->setTargetPageUid((int)$pageUid);
+        }
+
+        if (is_string($addQueryStringMethod)) {
+            $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+        }
+
+        return $uri->build();
     }
 }
index 82b7ec5..88f8f82 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Widget;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
 
 /**
@@ -106,6 +107,7 @@ class LinkViewHelper extends AbstractTagBasedViewHelper
      */
     protected function getWidgetUri()
     {
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $this->renderingContext->getControllerContext()->getUriBuilder();
         $argumentPrefix = $this->renderingContext->getControllerContext()->getRequest()->getArgumentPrefix();
         $arguments = $this->hasArgument('arguments') ? $this->arguments['arguments'] : [];
@@ -118,13 +120,19 @@ class LinkViewHelper extends AbstractTagBasedViewHelper
         if (isset($arguments['useCacheHash'])) {
             trigger_error('Using the argument "useCacheHash" in <f:widget.link> ViewHelper has no effect anymore. Remove the argument in your fluid template, as it will result in a fatal error.', E_USER_DEPRECATED);
         }
-        return $uriBuilder->reset()
+        $uriBuilder->reset()
             ->setArguments([$argumentPrefix => $arguments])
             ->setSection($this->arguments['section'])
             ->setAddQueryString(true)
-            ->setAddQueryStringMethod($this->arguments['addQueryStringMethod'])
             ->setArgumentsToBeExcludedFromQueryString([$argumentPrefix, 'cHash'])
             ->setFormat($this->arguments['format'])
-            ->build();
+        ;
+
+        $addQueryStringMethod = $this->arguments['addQueryStringMethod'] ?? null;
+        if (is_string($addQueryStringMethod)) {
+            $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+        }
+
+        return $uriBuilder->build();
     }
 }
index 3383ffb..8ba3d53 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers\Widget;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
@@ -100,6 +101,7 @@ class UriViewHelper extends AbstractViewHelper
     protected static function getWidgetUri(RenderingContextInterface $renderingContext, array $arguments)
     {
         $controllerContext = $renderingContext->getControllerContext();
+        /** @var UriBuilder $uriBuilder */
         $uriBuilder = $controllerContext->getUriBuilder();
         $argumentPrefix = $controllerContext->getRequest()->getArgumentPrefix();
         $parameters = $arguments['arguments'] ?? [];
@@ -112,13 +114,19 @@ class UriViewHelper extends AbstractViewHelper
         if (isset($arguments['useCacheHash'])) {
             trigger_error('Using the argument "useCacheHash" in <f:widget.uri> ViewHelper has no effect anymore. Remove the argument in your fluid template, as it will result in a fatal error.', E_USER_DEPRECATED);
         }
-        return $uriBuilder->reset()
+        $uriBuilder->reset()
             ->setArguments([$argumentPrefix => $parameters])
             ->setSection($arguments['section'])
             ->setAddQueryString(true)
-            ->setAddQueryStringMethod($arguments['addQueryStringMethod'])
             ->setArgumentsToBeExcludedFromQueryString([$argumentPrefix, 'cHash'])
             ->setFormat($arguments['format'])
-            ->build();
+        ;
+
+        $addQueryStringMethod = $arguments['addQueryStringMethod'] ?? null;
+        if (is_string($addQueryStringMethod)) {
+            $uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
+        }
+
+        return $uriBuilder->build();
     }
 }
index 8254e7f..3929c24 100644 (file)
@@ -57,7 +57,7 @@ class PageViewHelperTest extends ViewHelperBaseTestcase
      */
     public function renderWillNotProvideATagForNonValidLinkTarget()
     {
-        $this->uriBuilder->expects($this->once())->method('build')->will($this->returnValue(null));
+        $this->uriBuilder->expects($this->once())->method('build')->will($this->returnValue(''));
         $this->tagBuilder->expects($this->never())->method('render');
         $this->viewHelper->render();
     }