Skip to content

Instantly share code, notes, and snippets.

@georgringer
Created October 28, 2019 10:21
Show Gist options
  • Save georgringer/557b40b40d69d59db4bc52dbcd5ae584 to your computer and use it in GitHub Desktop.
Save georgringer/557b40b40d69d59db4bc52dbcd5ae584 to your computer and use it in GitHub Desktop.
Redirects to records XCLASS
<?php
declare(strict_types = 1);
namespace Vendor\Theme\Xclass;
use Psr\Http\Message\UriInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\LinkHandling\LinkService;
use TYPO3\CMS\Core\Resource\Exception\InvalidPathException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Site\Entity\SiteInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\HttpUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
use TYPO3\CMS\Frontend\Typolink\AbstractTypolinkBuilder;
use TYPO3\CMS\Frontend\Typolink\UnableToLinkException;
use TYPO3\CMS\Redirects\Service\RedirectService;
/**
* Creates a proper URL to redirect from a matched redirect of a request
*
* @internal due to some possible refactorings in TYPO3 v9
*/
class XclassedRedirectService extends RedirectService implements LoggerAwareInterface
{
use LoggerAwareTrait;
/**
* @param array $matchedRedirect
* @param array $queryParams
* @param SiteInterface|null $site
* @return UriInterface|null
*/
public function getTargetUrl(array $matchedRedirect, array $queryParams, ?SiteInterface $site = null): ?UriInterface
{
$this->logger->debug('Found a redirect to process', $matchedRedirect);
$linkParameterParts = GeneralUtility::makeInstance(TypoLinkCodecService::class)->decode((string)$matchedRedirect['target']);
$redirectTarget = $linkParameterParts['url'];
$linkDetails = $this->resolveLinkDetailsFromLinkTargetXclass($redirectTarget, $site, $queryParams);
$this->logger->debug('Resolved link details for redirect', $linkDetails);
// Do this for files, folders, external URLs
if (!empty($linkDetails['url'])) {
$url = new Uri($linkDetails['url']);
if ($matchedRedirect['force_https']) {
$url = $url->withScheme('https');
}
if ($matchedRedirect['keep_query_parameters']) {
$url = $this->addQueryParams($queryParams, $url);
}
return $url;
}
// If it's a record or page, then boot up TSFE and use typolink
return $this->getUriFromCustomLinkDetails($matchedRedirect, $site, $linkDetails, $queryParams);
}
/**
* Check if the current request is actually a redirect, and then process the redirect.
*
* @param string $redirectTarget
*
* @param SiteInterface|null $site
* @param array $queryParams
* @return array the link details from the linkService
* @throws \TYPO3\CMS\Core\LinkHandling\Exception\UnknownLinkHandlerException
*/
protected function resolveLinkDetailsFromLinkTargetXclass(string $redirectTarget, ?SiteInterface $site, array $queryParams): array
{
// build the target URL, take force SSL into account etc.
$linkService = GeneralUtility::makeInstance(LinkService::class);
try {
$linkDetails = $linkService->resolve($redirectTarget);
switch ($linkDetails['type']) {
case LinkService::TYPE_URL:
// all set up, nothing to do
break;
case LinkService::TYPE_FILE:
/** @var File $file */
$file = $linkDetails['file'];
if ($file instanceof File) {
$linkDetails['url'] = $file->getPublicUrl();
}
break;
case LinkService::TYPE_FOLDER:
/** @var Folder $folder */
$folder = $linkDetails['folder'];
if ($folder instanceof Folder) {
$linkDetails['url'] = $folder->getPublicUrl();
}
break;
case LinkService::TYPE_RECORD:
$this->bootFrontendController($site, $queryParams);
$contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$url = $contentObject->typoLink_URL([
'parameter' => $linkService->asString($linkDetails),
'forceAbsoluteUrl' => true
]);
if ($url) {
$linkDetails['url'] =$url;
}
break;
default:
// we have to return the link details without having a "URL" parameter
}
} catch (InvalidPathException $e) {
return [];
}
return $linkDetails;
}
/**
* Finishing booting up TSFE, after that the following properties are available.
*
* Instantiating is done by the middleware stack (see Configuration/RequestMiddlewares.php)
*
* - TSFE->fe_user
* - TSFE->sys_page
* - TSFE->tmpl
* - TSFE->config
* - TSFE->cObj
*
* So a link to a page can be generated.
*
* @param SiteInterface|null $site
* @param array $queryParams
* @return TypoScriptFrontendController
*/
protected function bootFrontendController(?SiteInterface $site, array $queryParams): TypoScriptFrontendController
{
// disable page errors
$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'] = false;
$controller = GeneralUtility::makeInstance(
TypoScriptFrontendController::class,
null,
$site ? $site->getRootPageId() : $GLOBALS['TSFE']->id,
0
);
$controller->fe_user = $GLOBALS['TSFE']->fe_user ?? null;
$controller->fetch_the_id();
$controller->calculateLinkVars($queryParams);
$controller->getConfigArray();
$controller->settingLanguage();
$controller->settingLocale();
$controller->newCObj();
$GLOBALS['TSFE'] = $controller;
return $controller;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment