mirror of
https://github.com/werkraum-media/events.git
synced 2024-11-25 13:56:10 +01:00
Respect new upcoming feature when calculating TTL of page cache (#17)
Relates: #10506
This commit is contained in:
parent
99ef32a37b
commit
76c1e79ea3
6 changed files with 141 additions and 23 deletions
|
@ -25,10 +25,12 @@ namespace Wrm\Events\Caching;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
|
use InvalidArgumentException;
|
||||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||||
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
|
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
|
||||||
use TYPO3\CMS\Core\Context\Context;
|
use TYPO3\CMS\Core\Context\Context;
|
||||||
use TYPO3\CMS\Core\SingletonInterface;
|
use TYPO3\CMS\Core\SingletonInterface;
|
||||||
|
use Wrm\Events\Domain\Model\Date;
|
||||||
use Wrm\Events\Events\Controller\DateListVariables;
|
use Wrm\Events\Events\Controller\DateListVariables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +44,7 @@ class PageCacheTimeout implements SingletonInterface
|
||||||
/**
|
/**
|
||||||
* @var null|DateTimeImmutable
|
* @var null|DateTimeImmutable
|
||||||
*/
|
*/
|
||||||
private $endOfEvent = null;
|
private $timeout = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var FrontendInterface
|
* @var FrontendInterface
|
||||||
|
@ -78,46 +80,74 @@ class PageCacheTimeout implements SingletonInterface
|
||||||
public function trackDates(DateListVariables $event): void
|
public function trackDates(DateListVariables $event): void
|
||||||
{
|
{
|
||||||
if ($event->getDemand()->shouldShowFromMidnight()) {
|
if ($event->getDemand()->shouldShowFromMidnight()) {
|
||||||
$this->updateTimeout((new DateTimeImmutable('tomorrow midnight')));
|
$this->updateTimeout(new DateTimeImmutable('tomorrow midnight'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($event->getDemand()->shouldShowUpcoming()) {
|
||||||
|
$this->trackTimeoutByDate($event, static function (Date $date) {
|
||||||
|
return $date->getStart();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->trackTimeoutByDate($event, static function (Date $date) {
|
||||||
|
return $date->getEnd();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable $callback Receives Date as argument and should return DateTime to use as potential timeout.
|
||||||
|
*/
|
||||||
|
private function trackTimeoutByDate(
|
||||||
|
DateListVariables $event,
|
||||||
|
callable $callback
|
||||||
|
): void {
|
||||||
foreach ($event->getDates() as $date) {
|
foreach ($event->getDates() as $date) {
|
||||||
$endDate = $date->getEnd();
|
$date = $callback($date);
|
||||||
if (!$endDate instanceof DateTime) {
|
if (!$date instanceof DateTime) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->updateTimeout(DateTimeImmutable::createFromMutable($endDate));
|
$this->updateTimeout(DateTimeImmutable::createFromMutable($date));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updateTimeout(DateTimeImmutable $end): void
|
private function updateTimeout(DateTimeImmutable $newTimeout): void
|
||||||
{
|
{
|
||||||
$now = new DateTimeImmutable();
|
$now = $this->getExecution();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$end <= $now
|
$newTimeout <= $now
|
||||||
|| (
|
|| (
|
||||||
$this->endOfEvent instanceof DateTimeImmutable
|
$this->timeout instanceof DateTimeImmutable
|
||||||
&& $this->endOfEvent >= $end
|
&& $this->timeout >= $newTimeout
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->runtimeCache->remove('core-tslib_fe-get_cache_timeout');
|
$this->runtimeCache->remove('core-tslib_fe-get_cache_timeout');
|
||||||
$this->endOfEvent = $end;
|
$this->timeout = $newTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTimeout(): ?int
|
private function getTimeout(): ?int
|
||||||
{
|
{
|
||||||
if (!$this->endOfEvent instanceof DateTimeImmutable) {
|
if (!$this->timeout instanceof DateTimeImmutable) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$executionTime = $this->context->getPropertyFromAspect('date', 'timestamp');
|
return ((int) $this->timeout->format('U')) - ((int) $this->getExecution()->format('U'));
|
||||||
return ((int) $this->endOfEvent->format('U')) - $executionTime;
|
}
|
||||||
|
|
||||||
|
private function getExecution(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
$execution = $this->context->getPropertyFromAspect('date', 'full');
|
||||||
|
|
||||||
|
if (!$execution instanceof DateTimeImmutable) {
|
||||||
|
throw new InvalidArgumentException('Could not fetch DateTimeImmutable from context.', 1684740576);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $execution;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function register(): void
|
public static function register(): void
|
||||||
|
|
|
@ -10,8 +10,15 @@ Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
* Adjust TYPO3 page cache timeout based on rendered dates.
|
* Adjust TYPO3 page cache timeout based on rendered dates.
|
||||||
The end time of each rendered date will be used.
|
Will use one of the following:
|
||||||
The lowest end date will be used to calculate the maximum time to life for the page cache.
|
|
||||||
|
- end time of each rendered date
|
||||||
|
|
||||||
|
- start time of each rendered date (if upcoming is enabled)
|
||||||
|
|
||||||
|
- midnight (if midnight is configured)
|
||||||
|
|
||||||
|
The lowest date will be used to calculate the maximum time to life for the page cache.
|
||||||
This is compared to the already calculated time to life.
|
This is compared to the already calculated time to life.
|
||||||
The lower value is then used by TYPO3.
|
The lower value is then used by TYPO3.
|
||||||
|
|
||||||
|
|
13
Documentation/Features.rst
Normal file
13
Documentation/Features.rst
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.. _features:
|
||||||
|
|
||||||
|
Features
|
||||||
|
=========
|
||||||
|
|
||||||
|
The extension provides a couple of features.
|
||||||
|
The following is an incomplete list of the feature set with further info per feature.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
Features/*
|
28
Documentation/Features/Caching.rst
Normal file
28
Documentation/Features/Caching.rst
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
.. _caching:
|
||||||
|
|
||||||
|
.. index:: single: caching
|
||||||
|
|
||||||
|
Caching
|
||||||
|
=======
|
||||||
|
|
||||||
|
The extension provides out of the box support for proper TYPO3 page caching.
|
||||||
|
|
||||||
|
Page Cache
|
||||||
|
----------
|
||||||
|
|
||||||
|
TYPO3 can cache the full page with a TTL (=time to live).
|
||||||
|
The TTL can be adjusted via configuration and code.
|
||||||
|
The extension uses the code to lower TTL if necessary.
|
||||||
|
|
||||||
|
The TTL of the extension is determined in the following way:
|
||||||
|
|
||||||
|
#. Upcoming midnight if midnight should be used.
|
||||||
|
|
||||||
|
#. Start of each shown date if upcoming should be used.
|
||||||
|
|
||||||
|
#. End of each shown date as fallback.
|
||||||
|
|
||||||
|
The corresponding code is ``Wrm\Events\Caching\PageCacheTimeout``.
|
||||||
|
|
||||||
|
That way the TTL of each page is not longer than the valid period for shown events,
|
||||||
|
leading to re-rendering of the page once an event might change.
|
|
@ -42,6 +42,7 @@ Table of Contents
|
||||||
:maxdepth: 3
|
:maxdepth: 3
|
||||||
:titlesonly:
|
:titlesonly:
|
||||||
|
|
||||||
|
Features
|
||||||
Commands
|
Commands
|
||||||
Settings
|
Settings
|
||||||
Changelog
|
Changelog
|
||||||
|
|
|
@ -67,7 +67,7 @@ class CacheTest extends AbstractTestCase
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function setupReturnsSystemDefaults(): void
|
public function returnsSystemDefaults(): void
|
||||||
{
|
{
|
||||||
$response = $this->executeFrontendRequest($this->getRequestWithSleep());
|
$response = $this->executeFrontendRequest($this->getRequestWithSleep());
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class CacheTest extends AbstractTestCase
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function setupReturnsDefaultsIfEventsEndLater(): void
|
public function returnsDefaultsIfEventsEndLater(): void
|
||||||
{
|
{
|
||||||
(new PhpDataSet())->import([
|
(new PhpDataSet())->import([
|
||||||
'tx_events_domain_model_event' => [
|
'tx_events_domain_model_event' => [
|
||||||
|
@ -107,7 +107,7 @@ class CacheTest extends AbstractTestCase
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function setupReturnsEarlierIfEventsChangeBeforeSystemDefault(): void
|
public function returnsEarlierIfEventsEndEarlier(): void
|
||||||
{
|
{
|
||||||
$end = (new DateTimeImmutable('tomorrow midnight', new DateTimeZone('UTC')))->modify('+2 hours');
|
$end = (new DateTimeImmutable('tomorrow midnight', new DateTimeZone('UTC')))->modify('+2 hours');
|
||||||
|
|
||||||
|
@ -138,7 +138,46 @@ class CacheTest extends AbstractTestCase
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function setupReturnsMidnightIfConfigured(): void
|
public function returnsEarlierIfStartEndEalierAndIsUpcoming(): void
|
||||||
|
{
|
||||||
|
$end = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->modify('+2 hours');
|
||||||
|
|
||||||
|
(new PhpDataSet())->import([
|
||||||
|
'tx_events_domain_model_event' => [
|
||||||
|
[
|
||||||
|
'uid' => '1',
|
||||||
|
'pid' => '2',
|
||||||
|
'title' => 'Test Event 1',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'tx_events_domain_model_date' => [
|
||||||
|
[
|
||||||
|
'pid' => '2',
|
||||||
|
'event' => '1',
|
||||||
|
'start' => $end->format('U'),
|
||||||
|
'end' => '0',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->executeFrontendRequest($this->getRequestWithSleep([
|
||||||
|
'plugin.' => [
|
||||||
|
'tx_events.' => [
|
||||||
|
'settings.' => [
|
||||||
|
'upcoming' => 1,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]));
|
||||||
|
|
||||||
|
self::assertSame(200, $response->getStatusCode());
|
||||||
|
self::assertCacheHeaders($end, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsMidnightIfConfigured(): void
|
||||||
{
|
{
|
||||||
$midnight = (new DateTimeImmutable('tomorrow midnight', new DateTimeZone('UTC')));
|
$midnight = (new DateTimeImmutable('tomorrow midnight', new DateTimeZone('UTC')));
|
||||||
|
|
||||||
|
@ -207,13 +246,13 @@ class CacheTest extends AbstractTestCase
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getRequestWithSleep(): InternalRequest
|
private function getRequestWithSleep(array $typoScript = []): InternalRequest
|
||||||
{
|
{
|
||||||
$request = new InternalRequest();
|
$request = new InternalRequest();
|
||||||
$request = $request->withPageId(1);
|
$request = $request->withPageId(1);
|
||||||
$request = $request->withInstructions([
|
$request = $request->withInstructions([
|
||||||
$this->getTypoScriptInstruction()
|
$this->getTypoScriptInstruction()
|
||||||
->withTypoScript([
|
->withTypoScript(array_merge_recursive($typoScript, [
|
||||||
'page.' => [
|
'page.' => [
|
||||||
'30.' => [
|
'30.' => [
|
||||||
'userFunc.' => [
|
'userFunc.' => [
|
||||||
|
@ -221,7 +260,7 @@ class CacheTest extends AbstractTestCase
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
])
|
]))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $request;
|
return $request;
|
||||||
|
|
Loading…
Reference in a new issue