| Conditions | 63 |
| Paths | > 20000 |
| Total Lines | 226 |
| Code Lines | 130 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php |
||
| 50 | public function build(array &$linkDetails, string $linkText, string $target, array $conf): array |
||
| 51 | { |
||
| 52 | $tsfe = $this->getTypoScriptFrontendController(); |
||
| 53 | if (empty($linkDetails['pageuid']) || $linkDetails['pageuid'] === 'current') { |
||
| 54 | // If no id is given |
||
| 55 | $linkDetails['pageuid'] = $tsfe->id; |
||
| 56 | } |
||
| 57 | |||
| 58 | // Link to page even if access is missing? |
||
| 59 | if (isset($conf['linkAccessRestrictedPages'])) { |
||
| 60 | $disableGroupAccessCheck = (bool)$conf['linkAccessRestrictedPages']; |
||
| 61 | } else { |
||
| 62 | $disableGroupAccessCheck = (bool)$tsfe->config['config']['typolinkLinkAccessRestrictedPages']; |
||
| 63 | } |
||
| 64 | |||
| 65 | // Looking up the page record to verify its existence: |
||
| 66 | $page = $this->resolvePage($linkDetails, $conf, $disableGroupAccessCheck); |
||
| 67 | |||
| 68 | if (empty($page)) { |
||
| 69 | throw new UnableToLinkException('Page id "' . $linkDetails['typoLinkParameter'] . '" was not found, so "' . $linkText . '" was not linked.', 1490987336, null, $linkText); |
||
| 70 | } |
||
| 71 | |||
| 72 | foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typolinkProcessing']['typolinkModifyParameterForPageLinks'] ?? [] as $classData) { |
||
| 73 | $hookObject = GeneralUtility::makeInstance($classData); |
||
| 74 | if (!$hookObject instanceof TypolinkModifyLinkConfigForPageLinksHookInterface) { |
||
| 75 | throw new \UnexpectedValueException('$hookObject must implement interface ' . TypolinkModifyLinkConfigForPageLinksHookInterface::class, 1483114905); |
||
| 76 | } |
||
| 77 | /** @var TypolinkModifyLinkConfigForPageLinksHookInterface $hookObject */ |
||
| 78 | $conf = $hookObject->modifyPageLinkConfiguration($conf, $linkDetails, $page); |
||
| 79 | } |
||
| 80 | if ($conf['no_cache.']) { |
||
| 81 | $conf['no_cache'] = (string)$this->contentObjectRenderer->stdWrap($conf['no_cache'], $conf['no_cache.']); |
||
| 82 | } |
||
| 83 | |||
| 84 | $sectionMark = trim(isset($conf['section.']) ? (string)$this->contentObjectRenderer->stdWrap($conf['section'], $conf['section.']) : (string)$conf['section']); |
||
| 85 | if ($sectionMark === '' && isset($linkDetails['fragment'])) { |
||
| 86 | $sectionMark = $linkDetails['fragment']; |
||
| 87 | } |
||
| 88 | if ($sectionMark !== '') { |
||
| 89 | $sectionMark = '#' . (MathUtility::canBeInterpretedAsInteger($sectionMark) ? 'c' : '') . $sectionMark; |
||
| 90 | } |
||
| 91 | // Overruling 'type' |
||
| 92 | $pageType = $linkDetails['pagetype'] ?? ''; |
||
| 93 | |||
| 94 | if (isset($linkDetails['parameters'])) { |
||
| 95 | $conf['additionalParams'] .= '&' . ltrim($linkDetails['parameters'], '&'); |
||
| 96 | } |
||
| 97 | // MountPoints, look for closest MPvar: |
||
| 98 | $MPvarAcc = []; |
||
| 99 | if (!$tsfe->config['config']['MP_disableTypolinkClosestMPvalue']) { |
||
| 100 | $temp_MP = $this->getClosestMountPointValueForPage($page['uid']); |
||
| 101 | if ($temp_MP) { |
||
| 102 | $MPvarAcc['closest'] = $temp_MP; |
||
| 103 | } |
||
| 104 | } |
||
| 105 | // Look for overlay Mount Point: |
||
| 106 | $mount_info = $tsfe->sys_page->getMountPointInfo($page['uid'], $page); |
||
| 107 | if (is_array($mount_info) && $mount_info['overlay']) { |
||
| 108 | $page = $tsfe->sys_page->getPage($mount_info['mount_pid'], $disableGroupAccessCheck); |
||
| 109 | if (empty($page)) { |
||
| 110 | throw new UnableToLinkException('Mount point "' . $mount_info['mount_pid'] . '" was not available, so "' . $linkText . '" was not linked.', 1490987337, null, $linkText); |
||
| 111 | } |
||
| 112 | $MPvarAcc['re-map'] = $mount_info['MPvar']; |
||
| 113 | } |
||
| 114 | // Query Params: |
||
| 115 | $addQueryParams = $conf['addQueryString'] ? $this->contentObjectRenderer->getQueryArguments($conf['addQueryString.']) : ''; |
||
| 116 | $addQueryParams .= isset($conf['additionalParams.']) ? trim((string)$this->contentObjectRenderer->stdWrap($conf['additionalParams'], $conf['additionalParams.'])) : trim((string)$conf['additionalParams']); |
||
| 117 | if ($addQueryParams === '&' || $addQueryParams[0] !== '&') { |
||
| 118 | $addQueryParams = ''; |
||
| 119 | } |
||
| 120 | // Mount pages are always local and never link to another domain |
||
| 121 | if (!empty($MPvarAcc)) { |
||
| 122 | // Add "&MP" var: |
||
| 123 | $addQueryParams .= '&MP=' . rawurlencode(implode(',', $MPvarAcc)); |
||
| 124 | } elseif (strpos($addQueryParams, '&MP=') === false) { |
||
| 125 | // We do not come here if additionalParams had '&MP='. This happens when typoLink is called from |
||
| 126 | // menu. Mount points always work in the content of the current domain and we must not change |
||
| 127 | // domain if MP variables exist. |
||
| 128 | // If we link across domains and page is free type shortcut, we must resolve the shortcut first! |
||
| 129 | if ((int)$page['doktype'] === PageRepository::DOKTYPE_SHORTCUT |
||
| 130 | && (int)$page['shortcut_mode'] === PageRepository::SHORTCUT_MODE_NONE |
||
| 131 | ) { |
||
| 132 | // Save in case of broken destination or endless loop |
||
| 133 | $page2 = $page; |
||
| 134 | // Same as in RealURL, seems enough |
||
| 135 | $maxLoopCount = 20; |
||
| 136 | while ($maxLoopCount |
||
| 137 | && is_array($page) |
||
| 138 | && (int)$page['doktype'] === PageRepository::DOKTYPE_SHORTCUT |
||
| 139 | && (int)$page['shortcut_mode'] === PageRepository::SHORTCUT_MODE_NONE |
||
| 140 | ) { |
||
| 141 | $page = $tsfe->sys_page->getPage($page['shortcut'], $disableGroupAccessCheck); |
||
| 142 | $maxLoopCount--; |
||
| 143 | } |
||
| 144 | if (empty($page) || $maxLoopCount === 0) { |
||
| 145 | // We revert if shortcut is broken or maximum number of loops is exceeded (indicates endless loop) |
||
| 146 | $page = $page2; |
||
| 147 | } |
||
| 148 | } |
||
| 149 | } |
||
| 150 | |||
| 151 | if (isset($conf['useCacheHash'])) { |
||
| 152 | // This option will be removed in TYPO3 v11.0. |
||
| 153 | trigger_error('Setting typolink.useCacheHash has no effect anymore. Remove the option in all your TypoScript code and Fluid templates.', E_USER_DEPRECATED); |
||
| 154 | } |
||
| 155 | |||
| 156 | // get config.linkVars and prepend them before the actual GET parameters |
||
| 157 | $queryParameters = []; |
||
| 158 | parse_str($addQueryParams, $queryParameters); |
||
| 159 | if ($tsfe->linkVars) { |
||
| 160 | $globalQueryParameters = []; |
||
| 161 | parse_str($tsfe->linkVars, $globalQueryParameters); |
||
| 162 | $queryParameters = array_replace_recursive($globalQueryParameters, $queryParameters); |
||
| 163 | } |
||
| 164 | // Disable "?id=", for pages with no site configuration, this is added later-on anyway |
||
| 165 | unset($queryParameters['id']); |
||
| 166 | |||
| 167 | // Override language property if not being set already |
||
| 168 | if (isset($queryParameters['L']) && !isset($conf['language'])) { |
||
| 169 | $conf['language'] = (int)$queryParameters['L']; |
||
| 170 | unset($queryParameters['L']); |
||
| 171 | } |
||
| 172 | |||
| 173 | // Check if the target page has a site configuration |
||
| 174 | try { |
||
| 175 | $siteOfTargetPage = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId((int)$page['uid'], null, $queryParameters['MP'] ?? ''); |
||
| 176 | $currentSite = $this->getCurrentSite(); |
||
| 177 | } catch (SiteNotFoundException $e) { |
||
| 178 | // Usually happens in tests, as sites with configuration should be available everywhere. |
||
| 179 | $siteOfTargetPage = null; |
||
| 180 | $currentSite = null; |
||
| 181 | } |
||
| 182 | |||
| 183 | // Link to a page that has a site configuration |
||
| 184 | if ($siteOfTargetPage !== null) { |
||
| 185 | $siteLanguageOfTargetPage = $this->getSiteLanguageOfTargetPage($siteOfTargetPage, (string)($conf['language'] ?? 'current')); |
||
| 186 | $languageAspect = LanguageAspectFactory::createFromSiteLanguage($siteLanguageOfTargetPage); |
||
| 187 | |||
| 188 | // Now overlay the page in the target language, in order to have valid title attributes etc. |
||
| 189 | if ($siteLanguageOfTargetPage->getLanguageId() > 0) { |
||
| 190 | $context = clone GeneralUtility::makeInstance(Context::class); |
||
| 191 | $context->setAspect('language', $languageAspect); |
||
| 192 | $pageRepository = GeneralUtility::makeInstance(PageRepository::class, $context); |
||
| 193 | $page = $pageRepository->getPageOverlay($page); |
||
| 194 | } |
||
| 195 | // Check if the target page can be access depending on l18n_cfg |
||
| 196 | if (!$tsfe->sys_page->isPageSuitableForLanguage($page, $languageAspect)) { |
||
| 197 | $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField'] ?? null; |
||
| 198 | $languageOfPageRecord = (int)($page[$languageField] ?? 0); |
||
| 199 | if ($languageOfPageRecord === 0 && GeneralUtility::hideIfDefaultLanguage($page['l18n_cfg'])) { |
||
| 200 | throw new UnableToLinkException('Default language of page "' . $linkDetails['typoLinkParameter'] . '" is hidden, so "' . $linkText . '" was not linked.', 1551621985, null, $linkText); |
||
| 201 | } |
||
| 202 | if ($languageOfPageRecord > 0 && !isset($page['_PAGES_OVERLAY']) && GeneralUtility::hideIfNotTranslated($page['l18n_cfg'])) { |
||
| 203 | throw new UnableToLinkException('Fallback to default language of page "' . $linkDetails['typoLinkParameter'] . '" is disabled, so "' . $linkText . '" was not linked.', 1551621996, null, $linkText); |
||
| 204 | } |
||
| 205 | } |
||
| 206 | |||
| 207 | if ($pageType) { |
||
| 208 | $queryParameters['type'] = (int)$pageType; |
||
| 209 | } |
||
| 210 | |||
| 211 | $treatAsExternalLink = true; |
||
| 212 | // External links are resolved via calling Typolink again (could be anything, really) |
||
| 213 | if ((int)$page['doktype'] === PageRepository::DOKTYPE_LINK) { |
||
| 214 | $conf['parameter'] = $page['url']; |
||
| 215 | unset($conf['parameter.']); |
||
| 216 | $this->contentObjectRenderer->typoLink($linkText, $conf); |
||
| 217 | $target = $this->contentObjectRenderer->lastTypoLinkTarget; |
||
| 218 | $url = $this->contentObjectRenderer->lastTypoLinkUrl; |
||
| 219 | if (empty($url)) { |
||
| 220 | throw new UnableToLinkException('Link to external page "' . $page['uid'] . '" does not have a proper target URL, so "' . $linkText . '" was not linked.', 1551621999, null, $linkText); |
||
| 221 | } |
||
| 222 | } else { |
||
| 223 | // Generate the URL |
||
| 224 | $url = $this->generateUrlForPageWithSiteConfiguration($page, $siteOfTargetPage, $queryParameters, $sectionMark, $conf); |
||
| 225 | // no scheme => always not external |
||
| 226 | if (!$url->getScheme() || !$url->getHost()) { |
||
| 227 | $treatAsExternalLink = false; |
||
| 228 | } else { |
||
| 229 | // URL has a scheme, possibly because someone requested a full URL. So now lets check if the URL |
||
| 230 | // is on the same site pagetree. If this is the case, we'll treat it as internal |
||
| 231 | // @todo: currently this does not check if the target page is a mounted page in a different site, |
||
| 232 | // so it is treating this as an absolute URL, which is wrong |
||
| 233 | if ($currentSite instanceof Site && $currentSite->getRootPageId() === $siteOfTargetPage->getRootPageId()) { |
||
| 234 | $treatAsExternalLink = false; |
||
| 235 | } |
||
| 236 | } |
||
| 237 | $url = (string)$url; |
||
| 238 | } |
||
| 239 | if ($treatAsExternalLink) { |
||
| 240 | $target = $target ?: $this->resolveTargetAttribute($conf, 'extTarget', false, $tsfe->extTarget); |
||
| 241 | } else { |
||
| 242 | $target = (isset($page['target']) && trim($page['target'])) ? $page['target'] : $target; |
||
| 243 | if (empty($target)) { |
||
| 244 | $target = $this->resolveTargetAttribute($conf, 'target', true, $tsfe->intTarget); |
||
| 245 | } |
||
| 246 | } |
||
| 247 | } else { |
||
| 248 | throw new UnableToLinkException('Could not link to page with ID: ' . $page['uid'], 1546887172, null, $linkText); |
||
| 249 | } |
||
| 250 | |||
| 251 | // If link is to an access restricted page which should be redirected, then find new URL: |
||
| 252 | if (empty($conf['linkAccessRestrictedPages']) |
||
| 253 | && $tsfe->config['config']['typolinkLinkAccessRestrictedPages'] |
||
| 254 | && $tsfe->config['config']['typolinkLinkAccessRestrictedPages'] !== 'NONE' |
||
| 255 | && !$tsfe->checkPageGroupAccess($page) |
||
| 256 | ) { |
||
| 257 | $thePage = $tsfe->sys_page->getPage($tsfe->config['config']['typolinkLinkAccessRestrictedPages']); |
||
| 258 | $addParams = str_replace( |
||
| 259 | [ |
||
| 260 | '###RETURN_URL###', |
||
| 261 | '###PAGE_ID###' |
||
| 262 | ], |
||
| 263 | [ |
||
| 264 | rawurlencode($url), |
||
| 265 | $page['uid'] |
||
| 266 | ], |
||
| 267 | $tsfe->config['config']['typolinkLinkAccessRestrictedPages_addParams'] |
||
| 268 | ); |
||
| 269 | $url = $this->contentObjectRenderer->getTypoLink_URL($thePage['uid'] . ($pageType ? ',' . $pageType : ''), $addParams, $target); |
||
| 270 | $url = $this->forceAbsoluteUrl($url, $conf); |
||
| 271 | } |
||
| 272 | |||
| 273 | // Setting title if blank value to link |
||
| 274 | $linkText = $this->parseFallbackLinkTextIfLinkTextIsEmpty($linkText, $page['title']); |
||
| 275 | return [$url, $linkText, $target]; |
||
| 276 | } |
||
| 690 |