[CLEANUP] The correct case must be used for standard PHP types in phpdoc
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Typolink / AbstractTypolinkBuilder.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Frontend\Typolink;
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
18 use TYPO3\CMS\Core\Service\DependencyOrderingService;
19 use TYPO3\CMS\Core\TypoScript\TemplateService;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
22 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
23 use TYPO3\CMS\Frontend\Http\UrlProcessorInterface;
24 use TYPO3\CMS\Frontend\Page\PageRepository;
25
26 /**
27 * Abstract class to provide proper helper for most types necessary
28 * Hands in the contentobject which is needed here for all the stdWrap magic.
29 */
30 abstract class AbstractTypolinkBuilder
31 {
32 /**
33 * @var ContentObjectRenderer
34 */
35 protected $contentObjectRenderer;
36
37 /**
38 * AbstractTypolinkBuilder constructor.
39 *
40 * @param $contentObjectRenderer ContentObjectRenderer
41 */
42 public function __construct(ContentObjectRenderer $contentObjectRenderer)
43 {
44 $this->contentObjectRenderer = $contentObjectRenderer;
45 }
46
47 /**
48 * Should be implemented by all subclasses to return an array with three parts:
49 * - URL
50 * - Link Text (can be modified)
51 * - Target (can be modified)
52 *
53 * @param array $linkDetails parsed link details by the LinkService
54 * @param string $linkText the link text
55 * @param string $target the target to point to
56 * @param array $conf the TypoLink configuration array
57 * @return array an array with three parts (URL, Link Text, Target)
58 */
59 abstract public function build(array &$linkDetails, string $linkText, string $target, array $conf): array;
60
61 /**
62 * Forces a given URL to be absolute.
63 *
64 * @param string $url The URL to be forced to be absolute
65 * @param array $configuration TypoScript configuration of typolink
66 * @return string The absolute URL
67 */
68 protected function forceAbsoluteUrl(string $url, array $configuration): string
69 {
70 if (!empty($url) && !empty($configuration['forceAbsoluteUrl']) && preg_match('#^(?:([a-z]+)(://)([^/]*)/?)?(.*)$#', $url, $matches)) {
71 $urlParts = [
72 'scheme' => $matches[1],
73 'delimiter' => '://',
74 'host' => $matches[3],
75 'path' => $matches[4]
76 ];
77 $isUrlModified = false;
78 // Set scheme and host if not yet part of the URL:
79 if (empty($urlParts['host'])) {
80 $urlParts['scheme'] = GeneralUtility::getIndpEnv('TYPO3_SSL') ? 'https' : 'http';
81 $urlParts['host'] = GeneralUtility::getIndpEnv('HTTP_HOST');
82 $urlParts['path'] = '/' . ltrim($urlParts['path'], '/');
83 // absRefPrefix has been prepended to $url beforehand
84 // so we only modify the path if no absRefPrefix has been set
85 // otherwise we would destroy the path
86 if ($this->getTypoScriptFrontendController()->absRefPrefix === '') {
87 $urlParts['path'] = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH') . ltrim($urlParts['path'], '/');
88 }
89 $isUrlModified = true;
90 }
91 // Override scheme:
92 $forceAbsoluteUrl = &$configuration['forceAbsoluteUrl.']['scheme'];
93 if (!empty($forceAbsoluteUrl) && $urlParts['scheme'] !== $forceAbsoluteUrl) {
94 $urlParts['scheme'] = $forceAbsoluteUrl;
95 $isUrlModified = true;
96 }
97 // Recreate the absolute URL:
98 if ($isUrlModified) {
99 $url = implode('', $urlParts);
100 }
101 }
102 return $url;
103 }
104
105 /**
106 * Helper method to a fallback method parsing HTML out of it
107 *
108 * @param string $originalLinkText the original string, if empty, the fallback link text
109 * @param string $fallbackLinkText the string to be used.
110 * @return string the final text
111 */
112 protected function parseFallbackLinkTextIfLinkTextIsEmpty(string $originalLinkText, string $fallbackLinkText): string
113 {
114 if ($originalLinkText === '') {
115 return $this->contentObjectRenderer->parseFunc($fallbackLinkText, ['makelinks' => 0], '< lib.parseFunc');
116 }
117 return $originalLinkText;
118 }
119
120 /**
121 * Creates the value for target="..." in a typolink configuration
122 *
123 * @param array $conf the typolink configuration
124 * @param string $name the key, usually "target", "extTarget" or "fileTarget"
125 * @param bool $respectFrameSetOption if set, then the fallback is only used as target if the doctype allows it
126 * @param string $fallbackTarget the string to be used when no target is found in the configuration
127 * @return string the value of the target attribute, if there is one
128 */
129 protected function resolveTargetAttribute(array $conf, string $name, bool $respectFrameSetOption = false, string $fallbackTarget = ''): string
130 {
131 $tsfe = $this->getTypoScriptFrontendController();
132 $targetAttributeAllowed = (!$respectFrameSetOption || !$tsfe->config['config']['doctype'] ||
133 in_array((string)$tsfe->config['config']['doctype'], ['xhtml_trans', 'xhtml_basic', 'html5'], true));
134
135 $target = '';
136 if (isset($conf[$name])) {
137 $target = $conf[$name];
138 } elseif ($targetAttributeAllowed) {
139 $target = $fallbackTarget;
140 }
141 if ($conf[$name . '.']) {
142 $target = (string)$this->contentObjectRenderer->stdWrap($target, $conf[$name . '.']);
143 }
144 return $target;
145 }
146
147 /**
148 * Loops over all configured URL modifier hooks (if available) and returns the generated URL or NULL if no URL was generated.
149 *
150 * @param string $context The context in which the method is called (e.g. typoLink).
151 * @param string $url The URL that should be processed.
152 * @param array $typolinkConfiguration The current link configuration array.
153 * @return string|null Returns NULL if URL was not processed or the processed URL as a string.
154 * @throws \RuntimeException if a hook was registered but did not fulfill the correct parameters.
155 */
156 protected function processUrl(string $context, string $url, array $typolinkConfiguration = [])
157 {
158 if (
159 empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['urlProcessing']['urlProcessors'])
160 || !is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['urlProcessing']['urlProcessors'])
161 ) {
162 return $url;
163 }
164
165 $urlProcessors = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['urlProcessing']['urlProcessors'];
166 foreach ($urlProcessors as $identifier => $configuration) {
167 if (empty($configuration) || !is_array($configuration)) {
168 throw new \RuntimeException('Missing configuration for URI processor "' . $identifier . '".', 1491130459);
169 }
170 if (!is_string($configuration['processor']) || empty($configuration['processor']) || !class_exists($configuration['processor']) || !is_subclass_of($configuration['processor'], UrlProcessorInterface::class)) {
171 throw new \RuntimeException('The URI processor "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . UrlProcessorInterface::class . '".', 1491130460);
172 }
173 }
174
175 $orderedProcessors = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($urlProcessors);
176 $keepProcessing = true;
177
178 foreach ($orderedProcessors as $configuration) {
179 /** @var UrlProcessorInterface $urlProcessor */
180 $urlProcessor = GeneralUtility::makeInstance($configuration['processor']);
181 $url = $urlProcessor->process($context, $url, $typolinkConfiguration, $this->contentObjectRenderer, $keepProcessing);
182 if (!$keepProcessing) {
183 break;
184 }
185 }
186
187 return $url;
188 }
189
190 /**
191 * @return TypoScriptFrontendController
192 */
193 public function getTypoScriptFrontendController(): TypoScriptFrontendController
194 {
195 if (!$GLOBALS['TSFE']) {
196 // This usually happens when typolink is created by the TYPO3 Backend, where no TSFE object
197 // is there. This functionality is currently completely internal, as these links cannot be
198 // created properly from the Backend.
199 // However, this is added to avoid any exceptions when trying to create a link
200 $GLOBALS['TSFE'] = GeneralUtility::makeInstance(
201 TypoScriptFrontendController::class,
202 [],
203 (int)GeneralUtility::_GP('id'),
204 (int)GeneralUtility::_GP('type')
205 );
206 $GLOBALS['TSFE']->sys_page = GeneralUtility::makeInstance(PageRepository::class);
207 $GLOBALS['TSFE']->sys_page->init(false);
208 $GLOBALS['TSFE']->tmpl = GeneralUtility::makeInstance(TemplateService::class);
209 $GLOBALS['TSFE']->tmpl->init();
210 }
211 return $GLOBALS['TSFE'];
212 }
213 }