Skip to content

Commit 97fba92

Browse files
authored
feat: Update v12 (#30)
1 parent 4a94ef7 commit 97fba92

23 files changed

Lines changed: 227 additions & 122 deletions

.github/workflows/ci.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
php-version:
3232
- 8.1
3333
- 8.2
34+
- 8.3
3435
steps:
3536
- name: Checkout
3637
uses: actions/checkout@v3
@@ -106,9 +107,11 @@ jobs:
106107
matrix:
107108
include:
108109
- php-version: '8.1'
109-
typo3-version: '^11.5'
110+
typo3-version: '^12.4'
110111
- php-version: '8.2'
111-
typo3-version: '^11.5'
112+
typo3-version: '^12.4'
113+
- php-version: '8.3'
114+
typo3-version: '^12.4'
112115
steps:
113116
- uses: actions/checkout@v3
114117

Classes/Domain/Model/Marker.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/*
34
* This file is part of the TYPO3 CMS project.
45
*

Classes/Domain/Model/MarkerCollection.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/*
34
* This file is part of the TYPO3 CMS project.
45
*
@@ -34,7 +35,7 @@ public function add(Marker $marker): void
3435
public function get(string $markerKey): Marker
3536
{
3637
if (!isset($this[$markerKey])) {
37-
throw new \RuntimeException('Marker not found');
38+
throw new \RuntimeException('Marker not found', 6494338102);
3839
}
3940

4041
return $this[$markerKey];
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sinso\Variables\EventListener;
6+
7+
use Sinso\Variables\Service\VariablesService;
8+
use TYPO3\CMS\Frontend\Event\ModifyCacheLifetimeForPageEvent;
9+
10+
final class ModifyCacheLifetime
11+
{
12+
public function __construct(
13+
private VariablesService $variablesService,
14+
) {
15+
}
16+
17+
/**
18+
* Calculate shortest lifetime (aka duration) respecting data from
19+
* markers
20+
*/
21+
public function __invoke(ModifyCacheLifetimeForPageEvent $event): void
22+
{
23+
$event->setCacheLifetime(
24+
min(
25+
$event->getCacheLifetime(),
26+
$this->variablesService->getLifetime(),
27+
)
28+
);
29+
}
30+
}

Classes/Hooks/ContentProcessor.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/*
34
* This file is part of the TYPO3 CMS project.
45
*
@@ -17,7 +18,7 @@
1718
use Sinso\Variables\Service\VariablesService;
1819
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
1920
use TYPO3\CMS\Core\Utility\GeneralUtility;
20-
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
21+
use TYPO3\CMS\Frontend\Event\AfterCacheableContentIsGeneratedEvent;
2122

2223
class ContentProcessor
2324
{
@@ -28,13 +29,10 @@ public function __construct()
2829
$this->variablesService = GeneralUtility::makeInstance(VariablesService::class);
2930
}
3031

31-
/**
32-
* Dynamically replaces variables by user content.
33-
*/
34-
public function replaceContent(array &$parameters, TypoScriptFrontendController $parentObject): void
32+
public function __invoke(AfterCacheableContentIsGeneratedEvent $event): void
3533
{
3634
$extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
37-
$this->variablesService->initialize($extensionConfiguration, $parentObject);
38-
$this->variablesService->replaceMarkersInStructureAndAdjustCaching($parentObject->content);
35+
$this->variablesService->initialize($extensionConfiguration, $event->getController());
36+
$this->variablesService->replaceMarkersInStructureAndAdjustCaching($event->getController()->content);
3937
}
4038
}

Classes/Hooks/DataHandler.php

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/*
34
* This file is part of the TYPO3 CMS project.
45
*
@@ -14,29 +15,75 @@
1415

1516
namespace Sinso\Variables\Hooks;
1617

18+
use Sinso\Variables\Domain\Model\Marker;
1719
use Sinso\Variables\Utility\CacheKeyUtility;
1820
use TYPO3\CMS\Core\Cache\CacheManager;
19-
use TYPO3\CMS\Core\Utility\GeneralUtility;
21+
use TYPO3\CMS\Core\Database\Connection;
22+
use TYPO3\CMS\Core\Database\ConnectionPool;
2023

2124
class DataHandler
2225
{
26+
public function __construct(
27+
private readonly ConnectionPool $connectionPool,
28+
private readonly CacheManager $cacheManager,
29+
) {
30+
}
31+
2332
/**
2433
* Flushes the cache if a marker record was edited.
2534
*/
26-
public function clearCachePostProc(array $params): void
35+
public function clearCachePostProc(array $params, \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler): void
36+
{
37+
$marker = $this->getMarkerFromHook($params, $dataHandler);
38+
39+
if (!$marker instanceof \Sinso\Variables\Domain\Model\Marker) {
40+
return;
41+
}
42+
43+
$cacheTagToFlush = CacheKeyUtility::getCacheKey(
44+
$marker->getMarkerWithBrackets()
45+
);
46+
47+
$this->cacheManager->flushCachesInGroupByTag('pages', $cacheTagToFlush);
48+
}
49+
50+
protected function getMarkerFromHook(array $params, \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler): ?Marker
2751
{
2852
if (
29-
isset($params['table'], $params['uid']) && $params['table'] === 'tx_variables_marker'
53+
($params['table'] !== 'tx_variables_marker')
54+
|| !isset($params['uid'])
3055
) {
31-
$cacheTagsToFlush = [];
32-
if (isset($params['marker'])) {
33-
$cacheTagsToFlush[] = CacheKeyUtility::getCacheKey($params['marker']);
34-
}
35-
36-
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
37-
foreach ($cacheTagsToFlush as $cacheTag) {
38-
$cacheManager->flushCachesInGroupByTag('pages', $cacheTag);
39-
}
56+
return null;
4057
}
58+
59+
$marker = $dataHandler->datamap[$params['table']][$params['uid']]['marker'] ?? null;
60+
61+
if (!$marker) {
62+
$marker = $this->findVariableMarkerByUidEventIfHiddenOrDeleted($params['uid']);
63+
}
64+
65+
if (!$marker) {
66+
return null;
67+
}
68+
69+
return new Marker(
70+
uid: $params['uid'],
71+
key: $marker,
72+
replacement: '', // value doesn't matter here
73+
);
74+
}
75+
76+
protected function findVariableMarkerByUidEventIfHiddenOrDeleted(int $uid): ?string
77+
{
78+
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_variables_marker');
79+
$queryBuilder->getRestrictions()->removeAll();
80+
return $queryBuilder
81+
->select('marker')
82+
->from('tx_variables_marker')
83+
->where(
84+
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)),
85+
)
86+
->executeQuery()
87+
->fetchOne();
4188
}
4289
}

Classes/Hooks/MarkersProcessorInterface.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/*
34
* This file is part of the TYPO3 CMS project.
45
*

Classes/Service/VariablesService.php

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ public function initialize(
3636
ExtensionConfiguration $extensionConfiguration = null,
3737
TypoScriptFrontendController $typoScriptFrontendController = null,
3838
): void {
39-
if (!$typoScriptFrontendController) {
39+
if (!$typoScriptFrontendController instanceof \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController) {
4040
$typoScriptFrontendController = $this->getTypoScriptFrontendController();
4141
}
4242

43-
if (!$extensionConfiguration) {
43+
if (!$extensionConfiguration instanceof \TYPO3\CMS\Core\Configuration\ExtensionConfiguration) {
4444
$extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
4545
}
4646

@@ -54,19 +54,17 @@ public function initialize(
5454
/**
5555
* Iterates over a structure (array, object) and replaces markers in every string found.
5656
*
57-
* @param mixed $structure
5857
*
59-
* @return void
6058
* @throws \Exception
6159
*/
6260
public function replaceMarkersInStructureAndAdjustCaching(
6361
mixed &$structure
6462
): void {
65-
if ($this->markerCollection === null) {
63+
if (!$this->markerCollection instanceof \Sinso\Variables\Domain\Model\MarkerCollection) {
6664
throw new \Exception('Markers not initialized. Please run initialize() first.', 1726241619);
6765
}
6866
$this->replaceMarkersInStructure($structure);
69-
$this->setCacheTagsAndLifetimeInTsfe();
67+
$this->setCacheTagsInTsfe();
7068
}
7169

7270
/**
@@ -111,12 +109,18 @@ protected function replaceMarkersInText(string &$text): void
111109
}
112110

113111
// Assign a cache key associated with the marker
114-
$this->cacheTags->add(CacheKeyUtility::getCacheKey($marker->getMarkerWithBrackets()));
112+
$this->cacheTags->add(
113+
CacheKeyUtility::getCacheKey(
114+
$marker->getMarkerWithBrackets()
115+
)
116+
);
115117
$this->usedMarkerKeys[] = $marker->key;
116118
$text = $newContent;
117119
}
118120
}
119121

122+
$this->usedMarkerKeys = array_unique($this->usedMarkerKeys);
123+
120124
// Remove all markers (avoids empty entries)
121125
if ($this->extensionConfiguration->get('variables', 'removeUnreplacedMarkers')) {
122126
$text = preg_replace('/{{.*?}}/', '', $text);
@@ -132,8 +136,8 @@ protected function getMarkers(): MarkerCollection
132136
return $page['uid'];
133137
}, $this->typoScriptFrontendController->rootLine);
134138

135-
if (!empty($this->typoScriptFrontendController->tmpl->setup['plugin.']['tx_variables.']['persistence.']['storagePid'])) {
136-
$pids[] = (int)$this->typoScriptFrontendController->tmpl->setup['plugin.']['tx_variables.']['persistence.']['storagePid'];
139+
if (!empty($GLOBALS['TYPO3_REQUEST']->getAttribute('frontend.typoscript')->getSetupArray()['plugin.']['tx_variables.']['persistence.']['storagePid'])) {
140+
$pids[] = (int)$GLOBALS['TYPO3_REQUEST']->getAttribute('frontend.typoscript')->getSetupArray()['plugin.']['tx_variables.']['persistence.']['storagePid'];
137141
}
138142

139143
$table = 'tx_variables_marker';
@@ -169,36 +173,40 @@ protected function getMarkers(): MarkerCollection
169173
return $markers;
170174
}
171175

172-
protected function setCacheTagsAndLifetimeInTsfe(): void
176+
protected function setCacheTagsInTsfe(): void
173177
{
174-
$this->usedMarkerKeys = array_unique($this->usedMarkerKeys);
175-
176-
$minLifetime = min(
177-
$this->getSmallestLifetimeForMarkers($this->usedMarkerKeys),
178-
$this->typoScriptFrontendController->page['cache_timeout'] ?: PHP_INT_MAX
179-
);
180-
181-
$this->typoScriptFrontendController->page['cache_timeout'] = $minLifetime;
182-
183178
if (count($this->cacheTags) > 0) {
184179
$this->typoScriptFrontendController->addCacheTags($this->cacheTags->toArray());
185180
}
186181
}
187182

188-
public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
183+
public function getLifetime(): int
189184
{
185+
return $this->getNearestTimestampForMarkers($this->usedMarkerKeys) - \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\Context::class)->getPropertyFromAspect('date', 'timestamp');
186+
}
187+
188+
/**
189+
* Get the nearest timestamp in the future when changes for Markers should happen.
190+
* This respects starttime and endtime.
191+
* The result will be used to calculate the maximal caching duration
192+
*
193+
* @throws \Doctrine\DBAL\Exception
194+
*/
195+
public function getNearestTimestampForMarkers(array $usedMarkerKeys): int
196+
{
197+
// Max value possible to keep an int \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->realPageCacheContent ($timeOutTime = $GLOBALS['EXEC_TIME'] + $cacheTimeout;)
198+
$result = PHP_INT_MAX;
199+
190200
$tableName = 'tx_variables_marker';
191201
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName)->createQueryBuilder();
192202
$queryBuilder->getRestrictions()->removeAll()
193203
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
194204

195205
// Code heavily inspired by:
196206
// \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getFirstTimeValueForRecord
197-
$now = (int)$GLOBALS['ACCESS_TIME'];
198-
// Max value possible to keep an int \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->realPageCacheContent ($timeOutTime = $GLOBALS['EXEC_TIME'] + $cacheTimeout;)
199-
$result = PHP_INT_MAX - $GLOBALS['EXEC_TIME'];
207+
$now = (int)\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\Context::class)->getPropertyFromAspect('date', 'timestamp');
200208
$timeFields = [];
201-
$timeConditions = $queryBuilder->expr()->orX();
209+
$timeConditions = $queryBuilder->expr()->or();
202210
foreach (['starttime', 'endtime'] as $field) {
203211
if (isset($GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field])) {
204212
$timeFields[$field] = $GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field];
@@ -212,7 +220,7 @@ public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
212220
. ' THEN NULL ELSE ' . $queryBuilder->quoteIdentifier($timeFields[$field]) . ' END'
213221
. ') AS ' . $queryBuilder->quoteIdentifier($timeFields[$field])
214222
);
215-
$timeConditions->add(
223+
$timeConditions->with(
216224
$queryBuilder->expr()->gt(
217225
$timeFields[$field],
218226
$queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
@@ -222,7 +230,7 @@ public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
222230
}
223231

224232
// if starttime or endtime are defined, evaluate them
225-
if (!empty($timeFields)) {
233+
if ($timeFields !== []) {
226234
// find the timestamp, when the current page's content changes the next time
227235
$queryBuilder
228236
->from($tableName)
@@ -235,7 +243,7 @@ public function getSmallestLifetimeForMarkers(array $usedMarkerKeys): int
235243
->fetch();
236244

237245
if ($row) {
238-
foreach ($timeFields as $timeField => $_) {
246+
foreach (array_keys($timeFields) as $timeField) {
239247
// if a MIN value is found, take it into account for the
240248
// cache lifetime we have to filter out start/endtimes < $now,
241249
// as the SQL query also returns rows with starttime < $now

Configuration/Services.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,16 @@ services:
77
Sinso\Variables\:
88
resource: '../Classes/*'
99

10+
Sinso\Variables\Hooks\DataHandler:
11+
public: true
12+
13+
Sinso\Variables\Hooks\ContentProcessor:
14+
tags:
15+
- name: event.listener
16+
1017
Sinso\Variables\Service\VariablesService:
1118
public: true
19+
20+
Sinso\Variables\EventListener\ModifyCacheLifetime:
21+
tags:
22+
- name: event.listener
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('variables', 'Configuration/TypoScript', 'Content Variables');

0 commit comments

Comments
 (0)