‪TYPO3CMS  10.4
AbstractTypolinkBuilder.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 
34 
40 {
44  protected ‪$contentObjectRenderer;
45 
50 
58  {
59  $this->contentObjectRenderer = ‪$contentObjectRenderer;
60  $this->typoScriptFrontendController = ‪$typoScriptFrontendController ?? ‪$GLOBALS['TSFE'] ?? null;
61  }
62 
75  abstract public function ‪build(array &$linkDetails, string $linkText, string $target, array $conf): array;
76 
84  protected function ‪forceAbsoluteUrl(string $url, array $configuration): string
85  {
86  if (!empty($url) && !empty($configuration['forceAbsoluteUrl']) && preg_match('#^(?:([a-z]+)(://)([^/]*)/?)?(.*)$#', $url, $matches)) {
87  $urlParts = [
88  'scheme' => $matches[1],
89  'delimiter' => '://',
90  'host' => $matches[3],
91  'path' => $matches[4]
92  ];
93  $isUrlModified = false;
94  // Set scheme and host if not yet part of the URL:
95  if (empty($urlParts['host'])) {
96  $urlParts['scheme'] = GeneralUtility::getIndpEnv('TYPO3_SSL') ? 'https' : 'http';
97  $urlParts['host'] = GeneralUtility::getIndpEnv('HTTP_HOST');
98  $urlParts['path'] = '/' . ltrim($urlParts['path'], '/');
99  // absRefPrefix has been prepended to $url beforehand
100  // so we only modify the path if no absRefPrefix has been set
101  // otherwise we would destroy the path
102  if ($this->‪getTypoScriptFrontendController()->absRefPrefix === '') {
103  $urlParts['path'] = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH') . ltrim($urlParts['path'], '/');
104  }
105  $isUrlModified = true;
106  }
107  // Override scheme:
108  $forcedScheme = $configuration['forceAbsoluteUrl.']['scheme'] ?? null;
109  if (!empty($forcedScheme) && $urlParts['scheme'] !== $forcedScheme) {
110  $urlParts['scheme'] = $forcedScheme;
111  $isUrlModified = true;
112  }
113  // Also ensure the path has a "/" at the beginning when concatenating everything else together
114  if ($urlParts['path'] !== '') {
115  $urlParts['path'] = '/' . ltrim($urlParts['path'], '/');
116  $isUrlModified = true;
117  }
118  // Recreate the absolute URL:
119  if ($isUrlModified) {
120  $url = implode('', $urlParts);
121  }
122  }
123  return $url;
124  }
125 
131  protected function ‪isLibParseFuncDefined(): bool
132  {
133  $configuration = $this->contentObjectRenderer->mergeTSRef(
134  ['parseFunc' => '< lib.parseFunc'],
135  'parseFunc'
136  );
137  return !empty($configuration['parseFunc.']) && is_array($configuration['parseFunc.']);
138  }
139 
147  protected function ‪parseFallbackLinkTextIfLinkTextIsEmpty(string $originalLinkText, string $fallbackLinkText): string
148  {
149  if ($originalLinkText !== '') {
150  return $originalLinkText;
151  }
152  if ($this->‪isLibParseFuncDefined()) {
153  return $this->contentObjectRenderer->parseFunc($fallbackLinkText, ['makelinks' => 0], '< lib.parseFunc');
154  }
155  // encode in case `lib.parseFunc` is not configured
156  return $this->‪encodeFallbackLinkTextIfLinkTextIsEmpty($originalLinkText, $fallbackLinkText);
157  }
158 
166  protected function ‪encodeFallbackLinkTextIfLinkTextIsEmpty(string $originalLinkText, string $fallbackLinkText): string
167  {
168  if ($originalLinkText !== '') {
169  return $originalLinkText;
170  }
171  return htmlspecialchars($fallbackLinkText, ENT_QUOTES);
172  }
173 
183  protected function ‪resolveTargetAttribute(array $conf, string $name, bool $respectFrameSetOption = false, string $fallbackTarget = ''): string
184  {
185  $tsfe = $this->‪getTypoScriptFrontendController();
186  $targetAttributeAllowed = !$respectFrameSetOption
187  || (!isset($tsfe->config['config']['doctype']) || !$tsfe->config['config']['doctype'])
188  || in_array((string)$tsfe->config['config']['doctype'], ['xhtml_trans', 'xhtml_basic', 'html5'], true);
189 
190  $target = '';
191  if (isset($conf[$name])) {
192  $target = $conf[$name];
193  } elseif ($targetAttributeAllowed && !($conf['directImageLink'] ?? false)) {
194  $target = $fallbackTarget;
195  }
196  if (isset($conf[$name . '.']) && $conf[$name . '.']) {
197  $target = (string)$this->contentObjectRenderer->stdWrap($target, $conf[$name . '.'] ?? []);
198  }
199  return $target;
200  }
201 
211  protected function ‪processUrl(string $context, string $url, array $typolinkConfiguration = [])
212  {
213  $urlProcessors = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['urlProcessing']['urlProcessors'] ?? false;
214  if (!$urlProcessors) {
215  return $url;
216  }
217 
218  foreach ($urlProcessors as $identifier => $configuration) {
219  if (empty($configuration) || !is_array($configuration)) {
220  throw new \RuntimeException('Missing configuration for URI processor "' . $identifier . '".', 1491130459);
221  }
222  if (!is_string($configuration['processor']) || empty($configuration['processor']) || !class_exists($configuration['processor']) || !is_subclass_of($configuration['processor'], UrlProcessorInterface::class)) {
223  throw new \RuntimeException('The URI processor "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . UrlProcessorInterface::class . '".', 1491130460);
224  }
225  }
226 
227  $orderedProcessors = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($urlProcessors);
228  $keepProcessing = true;
229 
230  foreach ($orderedProcessors as $configuration) {
232  $urlProcessor = GeneralUtility::makeInstance($configuration['processor']);
233  $url = $urlProcessor->process($context, $url, $typolinkConfiguration, $this->contentObjectRenderer, $keepProcessing);
234  if (!$keepProcessing) {
235  break;
236  }
237  }
238 
239  return $url;
240  }
241 
246  {
247  if ($this->typoScriptFrontendController instanceof ‪TypoScriptFrontendController) {
249  }
250 
251  // This usually happens when typolink is created by the TYPO3 Backend, where no TSFE object
252  // is there. This functionality is currently completely internal, as these links cannot be
253  // created properly from the Backend.
254  // However, this is added to avoid any exceptions when trying to create a link.
255  // Detecting the "first" site usually comes from the fact that TSFE needs to be instantiated
256  // during tests
257  $request = ‪$GLOBALS['TYPO3_REQUEST'] ?? ‪ServerRequestFactory::fromGlobals();
258  $site = $request->getAttribute('site');
259  if (!$site instanceof ‪Site) {
260  $sites = GeneralUtility::makeInstance(SiteFinder::class)->getAllSites();
261  $site = reset($sites);
262  if (!$site instanceof ‪Site) {
263  $site = new ‪NullSite();
264  }
265  }
266  $language = $request->getAttribute('language');
267  if (!$language instanceof ‪SiteLanguage) {
268  $language = $site->getDefaultLanguage();
269  }
270 
271  $id = $request->getQueryParams()['id'] ?? $request->getParsedBody()['id'] ?? $site->getRootPageId();
272  $type = $request->getQueryParams()['type'] ?? $request->getParsedBody()['type'] ?? '0';
273 
274  $this->typoScriptFrontendController = GeneralUtility::makeInstance(
275  TypoScriptFrontendController::class,
276  GeneralUtility::makeInstance(Context::class),
277  $site,
278  $language,
279  $request->getAttribute('routing', new ‪PageArguments((int)$id, (string)$type, []))
280  );
281  $this->typoScriptFrontendController->sys_page = GeneralUtility::makeInstance(PageRepository::class);
282  $this->typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
284  }
285 }
‪TYPO3\CMS\Core\Routing\PageArguments
Definition: PageArguments.php:26
‪TYPO3\CMS\Frontend\Http\UrlProcessorInterface
Definition: UrlProcessorInterface.php:27
‪TYPO3\CMS\Core\Site\Entity\NullSite
Definition: NullSite.php:32
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:40
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:26
‪TYPO3\CMS\Core\Http\ServerRequestFactory
Definition: ServerRequestFactory.php:34
‪TYPO3\CMS\Core\Service\DependencyOrderingService
Definition: DependencyOrderingService.php:32
‪TYPO3\CMS\Core\TypoScript\TemplateService
Definition: TemplateService.php:46
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:98
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:97
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Http\ServerRequestFactory\fromGlobals
‪static ServerRequest fromGlobals()
Definition: ServerRequestFactory.php:59