astehlik/typo3-extension-tinyurls

View on GitHub
Classes/Controller/EidController.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php

declare(strict_types=1);

namespace Tx\Tinyurls\Controller;

/*                                                                        *
 * This script belongs to the TYPO3 extension "tinyurls".                 *
 *                                                                        *
 * It is free software; you can redistribute it and/or modify it under    *
 * the terms of the GNU General Public License, either version 3 of the   *
 * License, or (at your option) any later version.                        *
 *                                                                        *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Tx\Tinyurls\Configuration\ExtensionConfiguration;
use Tx\Tinyurls\Domain\Model\TinyUrl;
use Tx\Tinyurls\Domain\Repository\TinyUrlRepository;
use Tx\Tinyurls\Exception\NoTinyUrlKeySubmittedException;
use Tx\Tinyurls\Exception\TinyUrlNotFoundException;
use TYPO3\CMS\Core\Http\Response;
use TYPO3\CMS\Core\Routing\SiteMatcher;
use TYPO3\CMS\Core\Routing\SiteRouteResult;
use TYPO3\CMS\Core\Site\Entity\SiteInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\ErrorController;

/**
 * Handles tiny URLs with the TYPO3 eID mechanism.
 *
 * @author Alexander Stehlik <alexander.stehlik.deleteme@gmail.com>
 * @author Sebastian Lemke <s.lemke.deleteme@infoworxx.de>
 */
class EidController
{
    private ?ErrorController $errorController = null;

    public function __construct(
        protected readonly ExtensionConfiguration $extensionConfiguration,
        protected readonly SiteMatcher $siteMatcher,
        protected readonly TinyUrlRepository $tinyUrlRepository,
    ) {}

    public function setErrorController(ErrorController $errorController): void
    {
        $this->errorController = $errorController;
    }

    public function tinyUrlRedirect(ServerRequestInterface $request): ResponseInterface
    {
        $this->extensionConfiguration->setSite($this->getSiteFromRequest($request));

        $this->tinyUrlRepository->purgeInvalidUrls();

        try {
            $tinyUrl = $this->getTinyUrl($request);
        } catch (TinyUrlNotFoundException $e) {
            return $this->handleTinyUrlNotFoundError($request, $e);
        }

        $this->processUrlHit($tinyUrl);

        $this->extensionConfiguration->reset();

        $response = new Response();
        $noCacheResponse = $this->addNoCacheHeaders($response);

        $redirectResponse = $noCacheResponse->withStatus(301);
        return $redirectResponse->withAddedHeader('Location', $tinyUrl->getTargetUrl());
    }

    protected function addNoCacheHeaders(ResponseInterface $response): ResponseInterface
    {
        $noCacheResponse = $response->withAddedHeader('Expires', '0');
        $noCacheResponse = $noCacheResponse->withAddedHeader(
            'Last-Modified',
            gmdate('D, d M Y H:i:s', $GLOBALS['EXEC_TIME']) . ' GMT',
        );
        $noCacheResponse = $noCacheResponse->withAddedHeader('Cache-Control', 'no-cache, must-revalidate');
        return $noCacheResponse->withAddedHeader('Pragma', 'no-cache');
    }

    protected function getErrorController(): ErrorController
    {
        if ($this->errorController) {
            return $this->errorController;
        }

        return GeneralUtility::makeInstance(ErrorController::class); // @codeCoverageIgnore
    }

    /**
     * Returns the data of the tiny URL record that was found by the submitted tinyurl key.
     *
     * @throws TinyUrlNotFoundException
     */
    protected function getTinyUrl(ServerRequestInterface $request): TinyUrl
    {
        $queryParams = $request->getQueryParams();
        if (empty($queryParams['tx_tinyurls']['key'])) {
            throw new NoTinyUrlKeySubmittedException();
        }

        $tinyUrlKey = (string)$queryParams['tx_tinyurls']['key'];

        return $this->tinyUrlRepository->findTinyUrlByKey($tinyUrlKey);
    }

    protected function handleTinyUrlNotFoundError(
        ServerRequestInterface $request,
        TinyUrlNotFoundException $e,
    ): ResponseInterface {
        $errorController = $this->getErrorController();
        return $errorController->pageNotFoundAction($request, $e->getMessage());
    }

    protected function processUrlHit(TinyUrl $tinyUrl): void
    {
        if ($tinyUrl->getDeleteOnUse()) {
            $this->tinyUrlRepository->deleteTinyUrlByKey($tinyUrl->getUrlkey());
            return;
        }

        $this->tinyUrlRepository->countTinyUrlHit($tinyUrl);
    }

    private function getSiteFromRequest(ServerRequestInterface $request): ?SiteInterface
    {
        $result =  $this->siteMatcher->matchRequest($request);

        if (!$result instanceof SiteRouteResult) {
            return null;
        }

        // @extensionScannerIgnoreLine
        return $result->getSite();
    }
}