Skip to content

Instantly share code, notes, and snippets.

@georgringer
Created October 28, 2019 10:21
Show Gist options
  • Select an option

  • Save georgringer/557b40b40d69d59db4bc52dbcd5ae584 to your computer and use it in GitHub Desktop.

Select an option

Save georgringer/557b40b40d69d59db4bc52dbcd5ae584 to your computer and use it in GitHub Desktop.

Revisions

  1. georgringer created this gist Oct 28, 2019.
    161 changes: 161 additions & 0 deletions XclassedRedirectService.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,161 @@
    <?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;
    }
    }