Skip to content

Commit

Permalink
wip: Add first TYPO3 12 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
sirdiego committed Apr 23, 2024
1 parent 5b5a237 commit b14c989
Show file tree
Hide file tree
Showing 15 changed files with 1,844 additions and 1,858 deletions.
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
<?php

/**
* Clear Cache hook for the Backend.
*/
declare(strict_types=1);

namespace HDNET\CdnFastly\Hooks;
namespace HDNET\CdnFastly\EventListener;

use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Backend\Backend\Event\ModifyClearCacheActionsEvent;
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Toolbar\ClearCacheActionsHookInterface;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheGroupException;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* Clear Cache hook for the Backend.
*/
class FastlyClearCache implements ClearCacheActionsHookInterface
final class FastlyClearCacheListener
{
/**
* Modifies CacheMenuItems array.
*
* @param array<mixed> $cacheActions Array of CacheMenuItems
* @param array<mixed> $optionValues Array of AccessConfigurations-identifiers (typically used by userTS with options.clearCache.identifier)
*/
public function manipulateCacheActions(&$cacheActions, &$optionValues): void
public function __invoke(ModifyClearCacheActionsEvent $event): void
{
$isAdmin = $GLOBALS['BE_USER']->isAdmin();
$userTsConfig = $GLOBALS['BE_USER']->getTSConfig();
if (!($isAdmin || ( ($userTsConfig['options.']['clearCache.'] ?? false) && ($userTsConfig['options.']['clearCache.']['fastly'] ?? false)))) {
if (!($isAdmin || (($userTsConfig['options.']['clearCache.'] ?? false) && ($userTsConfig['options.']['clearCache.']['fastly'] ?? false)))) {
return;
}

Expand All @@ -39,33 +27,15 @@ public function manipulateCacheActions(&$cacheActions, &$optionValues): void
return;
}

$cacheActions[] = [
$event->addCacheAction([
'id' => 'cdn_fastly',
'title' => 'LLL:EXT:cdn_fastly/Resources/Private/Language/locallang.xlf:cache.title',
'description' => 'LLL:EXT:cdn_fastly/Resources/Private/Language/locallang.xlf:cache.description',
'href' => $route,
'iconIdentifier' => 'extension-cdn_fastly-clearcache',
];

$optionValues[] = 'fastly';
}

/**
* @throws NoSuchCacheGroupException
*
* @return HtmlResponse|void
*/
public function clear()
{
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
$cacheManager->flushCachesInGroup('fastly');

return new HtmlResponse('');
]);
}

/**
* Get Ajax URI.
*/
protected function getAjaxUri(): string
{
/** @var UriBuilder $uriBuilder */
Expand All @@ -79,4 +49,12 @@ protected function getAjaxUri(): string

return (string)$uri;
}

public function clear(): ResponseInterface
{
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
$cacheManager->flushCachesInGroup('fastly');

return new HtmlResponse('');
}
}
24 changes: 9 additions & 15 deletions Classes/Middleware/FastlyMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Http\ApplicationType;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\EnvironmentService;

class FastlyMiddleware implements MiddlewareInterface
{
Expand All @@ -32,7 +31,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
{
$response = $handler->handle($request);

if (!$this->isEnvironmentInFrontendMode()) {
if (!$this->isEnvironmentInFrontendMode($request)) {
return $response;
}

Expand All @@ -44,17 +43,12 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface

$response = $this->appendSurrogateKeys($response);
$response = $this->appendSurrogateControl($response);
$response = $response->withHeader('X-CDN', 'enabled');

return $response;
return $response->withHeader('X-CDN', 'enabled');
}

protected function isEnvironmentInFrontendMode(): bool
protected function isEnvironmentInFrontendMode(ServerRequestInterface $request): bool
{
// We don't need extbase here, so no ObjectManager, yet.
GeneralUtility::makeInstance(EnvironmentService::class);

return ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend();
return ApplicationType::fromRequest($request)->isFrontend();
}

protected function isFastlyDisabledOrNotConfigured(): bool
Expand All @@ -73,18 +67,18 @@ protected function appendSurrogateKeys(ResponseInterface $response): ResponseInt

protected function appendSurrogateControl(ResponseInterface $response): ResponseInterface
{
$cacheControlHeaderValue = $response->getHeader('Cache-Control')[0] ?? '';
if (\mb_strpos($cacheControlHeaderValue, 'private') !== false) {
return $response;
}

$staleTimeout = 14400; // 4 hours
$staleIfErrorTimeout = 604800; // 168 hours
$additions = [
'stale-while-revalidate' => $staleTimeout,
'stale-if-error' => $staleIfErrorTimeout,
];

$cacheControlHeaderValue = $response->getHeader('Cache-Control')[0];
if (\mb_strpos($cacheControlHeaderValue, 'private') !== false) {
return $response;
}

$cacheControlHeaderValue = 'max-age='.$GLOBALS['TSFE']->get_cache_timeout().', public';
foreach ($additions as $key => $value) {
$cacheControlHeaderValue .= ',' . $key . '=' . $value;
Expand Down
5 changes: 2 additions & 3 deletions Configuration/Backend/AjaxRoutes.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

declare(strict_types=1);

use HDNET\CdnFastly\Hooks\FastlyClearCache;
use HDNET\CdnFastly\EventListener\FastlyClearCacheListener;

return [
'fastly' => [
'path' => '/backend/fastly',
// Use BE route direclty as Request-response call
'target' => FastlyClearCache::class . '::clear',
'target' => FastlyClearCacheListener::class . '::clear',
],
];
12 changes: 12 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

HDNET\CdnFastly\:
resource: '../Classes/*'

HDNET\CdnFastly\EventListener\FastlyClearCacheListener:
tags:
- name: event.listener
4 changes: 2 additions & 2 deletions Resources/Private/Build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM php:7.4.23-cli-alpine as base
FROM php:8.1.28-cli-alpine as base

COPY --from=composer:1.10.24 /usr/bin/composer /usr/bin/composer
COPY --from=composer:2.7.4 /usr/bin/composer /usr/bin/composer

FROM base

Expand Down
11 changes: 0 additions & 11 deletions Tests/Unit/AbstractTest.php

This file was deleted.

16 changes: 16 additions & 0 deletions Tests/Unit/AbstractTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace HDNET\CdnFastly\Tests\Unit;

use TYPO3\TestingFramework\Core\Unit\UnitTestCase;

abstract class AbstractTestCase extends UnitTestCase
{
public function tearDown(): void
{
$this->resetSingletonInstances = true;
parent::tearDown();
}
}
6 changes: 3 additions & 3 deletions Tests/Unit/Cache/FastlyBackendTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
namespace HDNET\CdnFastly\Tests\Unit\Cache;

use HDNET\CdnFastly\Cache\FastlyBackend;
use HDNET\CdnFastly\Tests\Unit\AbstractTest;
use HDNET\CdnFastly\Tests\Unit\AbstractTestCase;

class FastlyBackendTest extends AbstractTest
class FastlyBackendTest extends AbstractTestCase
{
public function testIsLoadable()
{
$object = new FastlyBackend(null);
self::assertTrue(is_object($object), 'Object should be creatable');
self::assertInstanceOf(FastlyBackend::class, $object, 'Object should be creatable');
}
}
15 changes: 15 additions & 0 deletions Tests/Unit/EventListener/FastlyClearCacheListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace HDNET\CdnFastly\Tests\Unit\EventListener;

use HDNET\CdnFastly\EventListener\FastlyClearCacheListener;
use HDNET\CdnFastly\Tests\Unit\AbstractTestCase;

class FastlyClearCacheListenerTest extends AbstractTestCase
{
public function testIsLoadable()
{
$object = new FastlyClearCacheListener();
self::assertInstanceOf(FastlyClearCacheListener::class, $object, 'Object should be creatable');
}
}
15 changes: 0 additions & 15 deletions Tests/Unit/Hooks/FastlyClearCacheTest.php

This file was deleted.

26 changes: 9 additions & 17 deletions Tests/Unit/Middleware/FastlyMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,27 @@
namespace HDNET\CdnFastly\Tests\Unit\Middleware;

use HDNET\CdnFastly\Middleware\FastlyMiddleware;
use HDNET\CdnFastly\Tests\Unit\AbstractTest;
use HDNET\CdnFastly\Tests\Unit\AbstractTestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
use TYPO3\CMS\Core\Http\Response;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\EnvironmentService;
use TYPO3\CMS\Core\Http\ServerRequest;

class FastlyMiddlewareTest extends AbstractTest
class FastlyMiddlewareTest extends AbstractTestCase
{
public function testIsLoadable()
{
$object = new FastlyMiddleware();
self::assertTrue(is_object($object), 'Object should be creatable');
}

public function test_is_response_a_ResponseInterface()
{
$middleware = new FastlyMiddleware();
$request = $this->getMockBuilder(ServerRequestInterface::class)->getMock();
$request = (new ServerRequest())->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
$handler = $this->getMockBuilder(RequestHandlerInterface::class)->getMock();
$handler->method('handle')->willReturn(new Response());
$response = $middleware->process($request, $handler);

self::assertInstanceOf(ResponseInterface::class, $response);
Expand All @@ -33,11 +34,9 @@ public function test_is_response_a_ResponseInterface()
public function test_get_XCDN_Header_if_Fastly_is_disabled()
{
$middleware = new FastlyMiddleware();
$request = $this->getMockBuilder(ServerRequestInterface::class)->getMock();
$request = (new ServerRequest())->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
$handler = $this->getMockBuilder(RequestHandlerInterface::class)->getMock();
$handler->method('handle')->willReturn(new Response());
$environmentServiceMock = $this->getMockBuilder(EnvironmentService::class)->setMethods(['isEnvironmentInFrontendMode'])->getMock();
$environmentServiceMock->method('isEnvironmentInFrontendMode')->willReturn(true);

$GLOBALS['TSFE'] = new class() {
public $page = [
Expand All @@ -55,8 +54,6 @@ public function get_cache_timeout()
}
};

GeneralUtility::setSingletonInstance(EnvironmentService::class, $environmentServiceMock);

$response = $middleware->process($request, $handler);

self::assertTrue($response->hasHeader('X-CDN'));
Expand All @@ -66,14 +63,11 @@ public function get_cache_timeout()
public function test_PageCacheKey()
{
$middleware = new FastlyMiddleware();
$request = $this->getMockBuilder(ServerRequestInterface::class)->getMock();
$request = (new ServerRequest())->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);

$handler = $this->getMockBuilder(RequestHandlerInterface::class)->getMock();
$handler->method('handle')->willReturn(new Response());

$environmentServiceMock = $this->getMockBuilder(EnvironmentService::class)->setMethods(['isEnvironmentInFrontendMode'])->getMock();
$environmentServiceMock->method('isEnvironmentInFrontendMode')->willReturn(true);

$GLOBALS['TSFE'] = new class() {
public $page = [
'fastly' => true,
Expand All @@ -92,8 +86,6 @@ public function get_cache_timeout()
}
};

GeneralUtility::setSingletonInstance(EnvironmentService::class, $environmentServiceMock);

$response = $middleware->process($request, $handler);

self::assertTrue($response->hasHeader('X-CDN'), 'Expected Header "X-CDN"');
Expand Down
25 changes: 3 additions & 22 deletions Tests/Unit/Service/FastlyServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,13 @@
namespace HDNET\CdnFastly\Tests\Unit\Service;

use HDNET\CdnFastly\Service\FastlyService;
use HDNET\CdnFastly\Tests\Unit\AbstractTest;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Object\Container\Container;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use HDNET\CdnFastly\Tests\Unit\AbstractTestCase;

class FastlyServiceTest extends AbstractTest
class FastlyServiceTest extends AbstractTestCase
{
public function testIsLoadable()
{
$object = new FastlyService();
self::assertTrue(is_object($object), 'Object should be creatable');
}

public function test_purgeAll()
{
//if(...) {
// $this->markTestSkipped(....);
//} ggf. umgebngsvariablen

$objectManager = new ObjectManager();
$container = $objectManager->get(Container::class);

$service = $objectManager->get(FastlyService::class);

$response = $service->purgeAll();

self::assertInstanceOf(ResponseInterface::class, $response);
self::assertInstanceOf(FastlyService::class, $object, 'Object should be creatable');
}
}
Loading

0 comments on commit b14c989

Please sign in to comment.