‪TYPO3CMS  ‪main
PageViewHelper.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ServerRequestInterface;
23 use ‪TYPO3\CMS\Backend\Routing\UriBuilder as BackendUriBuilder;
29 use ‪TYPO3\CMS\Extbase\Mvc\RequestInterface as ExtbaseRequestInterface;
35 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
36 
82 final class ‪PageViewHelper extends AbstractTagBasedViewHelper
83 {
87  protected ‪$tagName = 'a';
88 
89  public function ‪initializeArguments(): void
90  {
91  parent::initializeArguments();
92  $this->registerUniversalTagAttributes();
93  $this->registerTagAttribute('target', 'string', 'Target of link', false);
94  $this->registerTagAttribute('rel', 'string', 'Specifies the relationship between the current document and the linked document', false);
95  $this->registerArgument('pageUid', 'int', 'Target page. See TypoLink destination');
96  $this->registerArgument('pageType', 'int', 'Type of the target page. See typolink.parameter');
97  $this->registerArgument('noCache', 'bool', 'Set this to disable caching for the target page. You should not need this.');
98  $this->registerArgument('language', 'string', 'link to a specific language - defaults to the current language, use a language ID or "current" to enforce a specific language', false);
99  $this->registerArgument('section', 'string', 'The anchor to be added to the URI');
100  $this->registerArgument('linkAccessRestrictedPages', 'bool', 'If set, links pointing to access restricted pages will still link to the page even though the page cannot be accessed.');
101  $this->registerArgument('additionalParams', 'array', 'Additional query parameters that won\'t be prefixed like $arguments (overrule $arguments)');
102  $this->registerArgument('absolute', 'bool', 'If set, the URI of the rendered link is absolute');
103  $this->registerArgument('addQueryString', 'string', 'If set, the current query parameters will be kept in the URL. If set to "untrusted", then ALL query parameters will be added. Be aware, that this might lead to problems when the generated link is cached.', false, false);
104  $this->registerArgument('argumentsToBeExcludedFromQueryString', 'array', 'Arguments to be removed from the URI. Only active if $addQueryString = TRUE');
105  }
106 
107  public function ‪render(): string
108  {
110  $renderingContext = $this->renderingContext;
111  $request = $renderingContext->getRequest();
112 
113  if ($request instanceof ExtbaseRequestInterface) {
114  return $this->‪renderWithExtbaseContext($request);
115  }
116  if ($request instanceof ServerRequestInterface) {
117  if (‪ApplicationType::fromRequest($request)->isFrontend()) {
118  // Use the regular typolink functionality.
119  return $this->‪renderFrontendLinkWithCoreContext($request);
120  }
121  $uri = $this->‪renderBackendLinkWithCoreContext($request);
122  if ($uri !== '') {
123  $this->tag->addAttribute('href', $uri);
124  $this->tag->setContent($this->renderChildren());
125  $this->tag->forceClosingTag(true);
126  $result = $this->tag->render();
127  } else {
128  $result = (string)$this->renderChildren();
129  }
130  return $result;
131  }
132  throw new \RuntimeException(
133  'The rendering context of ViewHelper f:link.page is missing a valid request object.',
134  1639819269
135  );
136  }
137 
138  protected function ‪renderFrontendLinkWithCoreContext(ServerRequestInterface $request): string
139  {
140  $pageUid = isset($this->arguments['pageUid']) ? (int)$this->arguments['pageUid'] : 'current';
141  $pageType = isset($this->arguments['pageType']) ? (int)$this->arguments['pageType'] : 0;
142  $noCache = isset($this->arguments['noCache']) && (bool)$this->arguments['noCache'];
143  $section = isset($this->arguments['section']) ? (string)$this->arguments['section'] : '';
144  $language = isset($this->arguments['language']) ? (string)$this->arguments['language'] : null;
145  $linkAccessRestrictedPages = isset($this->arguments['linkAccessRestrictedPages']) && (bool)$this->arguments['linkAccessRestrictedPages'];
146  $additionalParams = isset($this->arguments['additionalParams']) ? (array)$this->arguments['additionalParams'] : [];
147  $absolute = isset($this->arguments['absolute']) && (bool)$this->arguments['absolute'];
148  $addQueryString = $this->arguments['addQueryString'] ?? false;
149  $argumentsToBeExcludedFromQueryString = isset($this->arguments['argumentsToBeExcludedFromQueryString']) ? (array)$this->arguments['argumentsToBeExcludedFromQueryString'] : [];
150 
151  $typolinkConfiguration = [
152  'parameter' => $pageUid,
153  ];
154  if ($pageType) {
155  $typolinkConfiguration['parameter'] .= ',' . $pageType;
156  }
157  if ($noCache) {
158  $typolinkConfiguration['no_cache'] = 1;
159  }
160  if ($language !== null) {
161  $typolinkConfiguration['language'] = $language;
162  }
163  if ($section) {
164  $typolinkConfiguration['section'] = $section;
165  }
166  if ($linkAccessRestrictedPages) {
167  $typolinkConfiguration['linkAccessRestrictedPages'] = 1;
168  }
169  if ($additionalParams) {
170  $typolinkConfiguration['additionalParams'] = ‪HttpUtility::buildQueryString($additionalParams, '&');
171  }
172  if ($absolute) {
173  $typolinkConfiguration['forceAbsoluteUrl'] = true;
174  }
175  if ($addQueryString && $addQueryString !== 'false') {
176  $typolinkConfiguration['addQueryString'] = $addQueryString;
177  if ($argumentsToBeExcludedFromQueryString !== []) {
178  $typolinkConfiguration['addQueryString.']['exclude'] = implode(',', $argumentsToBeExcludedFromQueryString);
179  }
180  }
181 
182  try {
183  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
184  $cObj->setRequest($request);
185  $linkFactory = GeneralUtility::makeInstance(LinkFactory::class);
186  $linkResult = $linkFactory->create((string)$this->renderChildren(), $typolinkConfiguration, $cObj);
187 
188  // Removing TypoLink target here to ensure same behaviour with extbase uri builder in this context.
189  $linkResultAttributes = $linkResult->getAttributes();
190  unset($linkResultAttributes['target']);
191 
192  $this->tag->addAttributes($linkResultAttributes);
193  $this->tag->setContent($this->renderChildren());
194  $this->tag->forceClosingTag(true);
195  $result = $this->tag->render();
196  } catch (‪UnableToLinkException) {
197  $result = (string)$this->renderChildren();
198  }
199  return $result;
200  }
201 
202  protected function ‪renderBackendLinkWithCoreContext(ServerRequestInterface $request): string
203  {
204  $pageUid = isset($this->arguments['pageUid']) ? (int)$this->arguments['pageUid'] : null;
205  $section = isset($this->arguments['section']) ? (string)$this->arguments['section'] : '';
206  $additionalParams = isset($this->arguments['additionalParams']) ? (array)$this->arguments['additionalParams'] : [];
207  $absolute = isset($this->arguments['absolute']) && (bool)$this->arguments['absolute'];
208  $addQueryString = $this->arguments['addQueryString'] ?? false;
209  $argumentsToBeExcludedFromQueryString = isset($this->arguments['argumentsToBeExcludedFromQueryString']) ? (array)$this->arguments['argumentsToBeExcludedFromQueryString'] : [];
210 
211  $arguments = [];
212  if ($addQueryString && $addQueryString !== 'false') {
213  $arguments = $request->getQueryParams();
214  foreach ($argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) {
215  $argumentArrayToBeExcluded = [];
216  parse_str($argumentToBeExcluded, $argumentArrayToBeExcluded);
217  $arguments = ArrayUtility::arrayDiffKeyRecursive($arguments, $argumentArrayToBeExcluded);
218  }
219  }
220 
221  $id = $pageUid ?? $request->getQueryParams()['id'] ?? null;
222  if ($id !== null) {
223  $arguments['id'] = $id;
224  }
225  if (!isset($arguments['route']) && ($route = $request->getAttribute('route')) instanceof ‪Route) {
226  $arguments['route'] = $route->getOption('_identifier');
227  }
228  $arguments = array_replace_recursive($arguments, $additionalParams);
229  $routeName = $arguments['route'] ?? null;
230  unset($arguments['route'], $arguments['token']);
231  $backendUriBuilder = GeneralUtility::makeInstance(BackendUriBuilder::class);
232  try {
233  if ($absolute) {
234  $uri = (string)$backendUriBuilder->buildUriFromRoute($routeName, $arguments, BackendUriBuilder::ABSOLUTE_URL);
235  } else {
236  $uri = (string)$backendUriBuilder->buildUriFromRoute($routeName, $arguments, BackendUriBuilder::ABSOLUTE_PATH);
237  }
238  } catch (‪RouteNotFoundException) {
239  $uri = '';
240  }
241  if ($section !== '') {
242  $uri .= '#' . $section;
243  }
244  return $uri;
245  }
246 
247  protected function ‪renderWithExtbaseContext(ExtbaseRequestInterface $request): string
248  {
249  $pageUid = isset($this->arguments['pageUid']) ? (int)$this->arguments['pageUid'] : null;
250  $pageType = isset($this->arguments['pageType']) ? (int)$this->arguments['pageType'] : 0;
251  $noCache = isset($this->arguments['noCache']) && (bool)$this->arguments['noCache'];
252  $section = isset($this->arguments['section']) ? (string)$this->arguments['section'] : '';
253  $language = isset($this->arguments['language']) ? (string)$this->arguments['language'] : null;
254  $linkAccessRestrictedPages = isset($this->arguments['linkAccessRestrictedPages']) && (bool)$this->arguments['linkAccessRestrictedPages'];
255  $additionalParams = isset($this->arguments['additionalParams']) ? (array)$this->arguments['additionalParams'] : [];
256  $absolute = isset($this->arguments['absolute']) && (bool)$this->arguments['absolute'];
257  $addQueryString = $this->arguments['addQueryString'] ?? false;
258  $argumentsToBeExcludedFromQueryString = isset($this->arguments['argumentsToBeExcludedFromQueryString']) ? (array)$this->arguments['argumentsToBeExcludedFromQueryString'] : [];
259 
260  $uriBuilder = GeneralUtility::makeInstance(ExtbaseUriBuilder::class);
261  $uriBuilder->reset()
262  ->setRequest($request)
263  ->setTargetPageType($pageType)
264  ->setNoCache($noCache)
265  ->setSection($section)
266  ->setLanguage($language)
267  ->setLinkAccessRestrictedPages($linkAccessRestrictedPages)
268  ->setArguments($additionalParams)
269  ->setCreateAbsoluteUri($absolute)
270  ->setAddQueryString($addQueryString)
271  ->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString);
272 
274  $uriBuilder->setTargetPageUid((int)$pageUid);
275  }
276 
277  $uri = $uriBuilder->build();
278  if ($uri !== '') {
279  $this->tag->addAttribute('href', $uri);
280  $this->tag->setContent($this->renderChildren());
281  $this->tag->forceClosingTag(true);
282  $result = $this->tag->render();
283  } else {
284  $result = (string)$this->renderChildren();
285  }
286  return $result;
287  }
288 }
‪TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
Definition: UriBuilder.php:38
‪TYPO3\CMS\Backend\Routing\Route
Definition: Route.php:24
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
Definition: RouteNotFoundException.php:21
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Core\Utility\HttpUtility\buildQueryString
‪static string buildQueryString(array $parameters, string $prependCharacter='', bool $skipEmptyParameters=false)
Definition: HttpUtility.php:124
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:102
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:24
‪TYPO3\CMS\Core\Http\fromRequest
‪@ fromRequest
Definition: ApplicationType.php:66
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Fluid\Core\Rendering\RenderingContext
Definition: RenderingContext.php:35
‪TYPO3\CMS\Core\Http\ApplicationType
‪ApplicationType
Definition: ApplicationType.php:55