Skip to content

Commit

Permalink
fix: Caching issue
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuf committed Nov 8, 2024
1 parent f983779 commit e79e881
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 52 deletions.
29 changes: 29 additions & 0 deletions Classes/EventListener/ModifyCacheLifetime.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Sinso\Variables\EventListener;

use Sinso\Variables\Service\VariablesService;
use TYPO3\CMS\Frontend\Event\ModifyCacheLifetimeForPageEvent;

final class ModifyCacheLifetime
{
public function __construct(
protected VariablesService $variablesService,
) {}

/**
* Calculate shortest lifetime (aka duration) respecting data from
* markers
*/
public function __invoke(ModifyCacheLifetimeForPageEvent $event): void
{
$event->setCacheLifetime(
min(
$event->getCacheLifetime(),
$this->variablesService->getLifetime(),
)
);
}
}
14 changes: 0 additions & 14 deletions Classes/Hooks/ContentProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use Sinso\Variables\Service\VariablesService;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Event\AfterCacheableContentIsGeneratedEvent;

class ContentProcessor
Expand All @@ -29,23 +28,10 @@ public function __construct()
$this->variablesService = GeneralUtility::makeInstance(VariablesService::class);
}

/**
* for v12 from the Service.yaml
*/
public function __invoke(AfterCacheableContentIsGeneratedEvent $event): void
{
$extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
$this->variablesService->initialize($extensionConfiguration, $event->getController());
$this->variablesService->replaceMarkersInStructureAndAdjustCaching($event->getController()->content);
}

/**
* for the v11
*/
public function replaceContent(array &$parameters, TypoScriptFrontendController $parentObject): void
{
$extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
$this->variablesService->initialize($extensionConfiguration, $parentObject);
$this->variablesService->replaceMarkersInStructureAndAdjustCaching($parentObject->content);
}
}
50 changes: 31 additions & 19 deletions Classes/Hooks/DataHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,64 @@

namespace Sinso\Variables\Hooks;

use Sinso\Variables\Domain\Model\Marker;
use Sinso\Variables\Utility\CacheKeyUtility;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class DataHandler
{
public function __construct(
private readonly ConnectionPool $connectionPool,
private readonly CacheManager $cacheManager,
) {}

/**
* Flushes the cache if a marker record was edited.
*/
public function clearCachePostProc(array $params, \TYPO3\CMS\Core\DataHandling\DataHandler $that): void
public function clearCachePostProc(array $params, \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler): void
{
$marker = $this->getMarkerFromHook($params, $dataHandler);

if (!$marker) {
return;
}

$cacheTagToFlush = CacheKeyUtility::getCacheKey(
$marker->getMarkerWithBrackets()
);

$this->cacheManager->flushCachesInGroupByTag('pages', $cacheTagToFlush);
}

protected function getMarkerFromHook(array $params, \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler): ?Marker
{
if (
($params['table'] !== 'tx_variables_marker')
|| !isset($params['uid'])
) {
return;
return null;
}

// TODO: Prüfen, was passiert, wenn der Marker-Key nicht angepasst wird, oder ein Element gelöscht oder hidden wird
$marker = $that->datamap[$params['table']][$params['uid']]['marker'] ?? null;
$marker = $dataHandler->datamap[$params['table']][$params['uid']]['marker'] ?? null;

if ($marker === null || $marker === '') {
$marker = $this->findDeletedVariableMarkerByUid($params['uid']);
if ($marker === null || $marker === '') {
return;
}
if (!$marker) {
$marker = $this->findVariableMarkerByUidEventIfHiddenOrDeleted($params['uid']);
}

$cacheTagsToFlush = [];
$cacheTagsToFlush[] = CacheKeyUtility::getCacheKey($marker);

$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
foreach ($cacheTagsToFlush as $cacheTag) {
$cacheManager->flushCachesInGroupByTag('pages', $cacheTag);
if (!$marker) {
return null;
}

return new Marker(
uid: $params['uid'],
key: $marker,
replacement: '', // value doesn't matter here
);
}

protected function findDeletedVariableMarkerByUid(int $uid): ?string
protected function findVariableMarkerByUidEventIfHiddenOrDeleted(int $uid): ?string
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_variables_marker');
$queryBuilder->getRestrictions()->removeAll();
Expand All @@ -67,7 +80,6 @@ protected function findDeletedVariableMarkerByUid(int $uid): ?string
->from('tx_variables_marker')
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)),
$queryBuilder->expr()->eq('deleted', 1),
)
->executeQuery()
->fetchOne();
Expand Down
44 changes: 27 additions & 17 deletions Classes/Service/VariablesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function replaceMarkersInStructureAndAdjustCaching(
throw new \Exception('Markers not initialized. Please run initialize() first.', 1726241619);
}
$this->replaceMarkersInStructure($structure);
$this->setCacheTagsAndLifetimeInTsfe();
$this->setCacheTagsInTsfe();
}

/**
Expand Down Expand Up @@ -111,12 +111,18 @@ protected function replaceMarkersInText(string &$text): void
}

// Assign a cache key associated with the marker
$this->cacheTags->add(CacheKeyUtility::getCacheKey($marker->getMarkerWithBrackets()));
$this->cacheTags->add(
CacheKeyUtility::getCacheKey(
$marker->getMarkerWithBrackets()
)
);
$this->usedMarkerKeys[] = $marker->key;
$text = $newContent;
}
}

$this->usedMarkerKeys = array_unique($this->usedMarkerKeys);

// Remove all markers (avoids empty entries)
if ($this->extensionConfiguration->get('variables', 'removeUnreplacedMarkers')) {
$text = preg_replace('/{{.*?}}/', '', $text);
Expand Down Expand Up @@ -169,24 +175,30 @@ protected function getMarkers(): MarkerCollection
return $markers;
}

protected function setCacheTagsAndLifetimeInTsfe(): void
protected function setCacheTagsInTsfe(): void
{
$this->usedMarkerKeys = array_unique($this->usedMarkerKeys);

$minLifetime = min(
$this->getSmallestLifetimeForMarkers($this->usedMarkerKeys),
$this->typoScriptFrontendController->page['cache_timeout'] ?: PHP_INT_MAX
);

$this->typoScriptFrontendController->page['cache_timeout'] = $minLifetime;

if (count($this->cacheTags) > 0) {
$this->typoScriptFrontendController->addCacheTags($this->cacheTags->toArray());
}
}

public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
public function getLifetime(): int
{
return $this->getNearestTimestampForMarkers($this->usedMarkerKeys) - $GLOBALS['EXEC_TIME'];
}

/**
* Get the nearest timestamp in the future when changes for Markers should happen.
* This respects starttime and endtime.
* The result will be used to calculate the maximal caching duration
*
* @throws \Doctrine\DBAL\Exception
*/
public function getNearestTimestampForMarkers(array $usedMarkerKeys): int
{
// Max value possible to keep an int \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->realPageCacheContent ($timeOutTime = $GLOBALS['EXEC_TIME'] + $cacheTimeout;)
$result = PHP_INT_MAX;

$tableName = 'tx_variables_marker';
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName)->createQueryBuilder();
$queryBuilder->getRestrictions()->removeAll()
Expand All @@ -195,10 +207,8 @@ public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
// Code heavily inspired by:
// \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getFirstTimeValueForRecord
$now = (int)$GLOBALS['ACCESS_TIME'];
// Max value possible to keep an int \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->realPageCacheContent ($timeOutTime = $GLOBALS['EXEC_TIME'] + $cacheTimeout;)
$result = PHP_INT_MAX - $GLOBALS['EXEC_TIME'];
$timeFields = [];
$timeConditions = $queryBuilder->expr()->orX();
$timeConditions = $queryBuilder->expr()->or();
foreach (['starttime', 'endtime'] as $field) {
if (isset($GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field])) {
$timeFields[$field] = $GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field];
Expand All @@ -212,7 +222,7 @@ public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
. ' THEN NULL ELSE ' . $queryBuilder->quoteIdentifier($timeFields[$field]) . ' END'
. ') AS ' . $queryBuilder->quoteIdentifier($timeFields[$field])
);
$timeConditions->add(
$timeConditions->with(
$queryBuilder->expr()->gt(
$timeFields[$field],
$queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
Expand Down
7 changes: 5 additions & 2 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ services:
Sinso\Variables\Hooks\DataHandler:
public: true

Sinso\Variables\Hooks\ContentProcessor :
Sinso\Variables\Hooks\ContentProcessor:
tags:
- name: event.listener
identifier: 'variables/content-processor'

Sinso\Variables\Service\VariablesService:
public: true

Sinso\Variables\EventListener\ModifyCacheLifetime:
tags:
- name: event.listener

0 comments on commit e79e881

Please sign in to comment.