From 194bb69bda84ee0f7b78689be134ff64f7a4b2d2 Mon Sep 17 00:00:00 2001 From: mmunos Date: Tue, 10 Feb 2026 13:24:03 -0500 Subject: [PATCH 1/4] =?UTF-8?q?-=20domaine=20par=20d=C3=A9faut=20pris=20su?= =?UTF-8?q?r=20la=20requ=C3=AAte=20en=20cas=20d'absence=20de=20host()=20as?= =?UTF-8?q?soci=C3=A9=20au=20SiteLanguage=20-=20Pas=20d'invalidation=20en?= =?UTF-8?q?=20cas=20d'absence=20de=20distributionId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Classes/Cache/CloudFrontCacheManager.php | 27 +++++++++++++++++++----- Classes/Hooks/ClearCachePostProc.php | 4 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Classes/Cache/CloudFrontCacheManager.php b/Classes/Cache/CloudFrontCacheManager.php index 7491525..d577c79 100644 --- a/Classes/Cache/CloudFrontCacheManager.php +++ b/Classes/Cache/CloudFrontCacheManager.php @@ -20,6 +20,7 @@ use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Resource\ProcessedFile; +use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Connection; @@ -103,6 +104,9 @@ public function cacheCmd(array $params, string|null $distributionIds = null): vo */ public function enqueue(string $link, string $distributionIds): void { + if (!$distributionIds) { + return; + } if ($link === '*') { $link = '/*'; } @@ -259,10 +263,10 @@ public function queueClearCache(int $pageId, bool $recursive = false, string|nul if (count($languages) > 0) { if ($this->isMultiLanguageDomains($entry)) { - $this->enqueue($this->buildLink($entry, array('_language' => 0)) . $wildcard, $this->distributionsMapping[(string)$languages[0]->getBase()->getHost()]); - foreach ($languages as $k => $lang) { - if ($lang->getLanguageId() != 0) { - $this->enqueue($this->buildLink($entry, array('_language' => $lang->getLanguageId())) . $wildcard, $this->distributionsMapping[$lang->getBase()->getHost()]); + $this->enqueue($this->buildLink($entry, array('_language' => 0)) . $wildcard, $this->distributionsMapping[$this->getLanguageHost($languages[0])]); + foreach ($languages as $k => $language) { + if ($language->getLanguageId() != 0) { + $this->enqueue($this->buildLink($entry, array('_language' => $language->getLanguageId())) . $wildcard, $this->distributionsMapping[$this->getLanguageHost($language)]); } } } else { @@ -320,12 +324,25 @@ public function getLanguagesDomains(int $uid_page): array { $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($uid_page); $domains = []; + // Récupération de l'hôte actuel via la requête si disponible foreach ($site->getAllLanguages() as $language) { - $domains[$language->getLanguageId()] = $language->getBase()->getHost(); + $domains[$language->getLanguageId()] = $this->getLanguageHost($language); } return $domains; } + public function getLanguageHost(SiteLanguage $language): string { + if ($host = $language->getBase()->getHost()) { + return $host; + } + $currentRequest = $GLOBALS['TYPO3_REQUEST'] ?? null; + if ($currentRequest + && $currentRequest instanceof \Psr\Http\Message\ServerRequestInterface) { + return $currentRequest->getUri()->getHost(); + } + return ''; + } + /** * Check if the page has multiple languages with different domains. * diff --git a/Classes/Hooks/ClearCachePostProc.php b/Classes/Hooks/ClearCachePostProc.php index 91e6838..ac34163 100644 --- a/Classes/Hooks/ClearCachePostProc.php +++ b/Classes/Hooks/ClearCachePostProc.php @@ -64,7 +64,7 @@ public function clearCachePostProc(&$params, &$pObj): void } // Do nothing if the page is a sysfolder - /* if ( (!empty($params['uid_page']) && MathUtility::canBeInterpretedAsInteger($params['uid_page'])) + /* if ( (!empty($params['uid_page']) && MathUtility::canBeInterpretedAsInteger($params['uid_page'])) || (isset($params['cacheCmd']) && MathUtility::canBeInterpretedAsInteger($params['cacheCmd'])) ) { $uid_page = (int)$params['uid_page'] ?: (int)$params['cacheCmd']; $pageRecord = BackendUtility::getRecord('pages', $uid_page, 'doktype'); @@ -197,7 +197,7 @@ protected function getDistributionIds(int $uid_page, array $params): string $sysLanguageUid = $row['sys_language_uid'] ?? 0; $language = $site->getLanguageById($sysLanguageUid); - $domain = $language->getBase()->getHost(); + $domain = $this->cacheManager->getLanguageHost($language); } $distributionIds = $this->distributionsMapping[$domain] ?? implode(',', array_values($this->distributionsMapping)); From 7e56c8aba1e334fc0610075889aafaee8d0c74be Mon Sep 17 00:00:00 2001 From: mmunos Date: Tue, 10 Feb 2026 14:09:04 -0500 Subject: [PATCH 2/4] Modification du script runTests pour ajouter l'option -p 8.4 --- Build/Scripts/runTests.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index 4c0b2ab..b26e3fc 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -166,6 +166,9 @@ getPhpImageVersion() { 8.3) echo -n "1.13" ;; + 8.4) + echo -n "latest" # Ou la version la plus récente disponible sur ghcr.io/typo3/core-testing-php84 + ;; esac } @@ -563,7 +566,7 @@ while getopts ":a:b:s:c:d:i:t:p:e:xy:o:nhug" OPT; do ;; p) PHP_VERSION=${OPTARG} - if ! [[ ${PHP_VERSION} =~ ^(8.2|8.3)$ ]]; then + if ! [[ ${PHP_VERSION} =~ ^(8.2|8.3|8.4)$ ]]; then INVALID_OPTIONS+=("${OPTARG}") fi ;; From 1fff18254bd73e598c9f97ecd8b7ec62eee99b2f Mon Sep 17 00:00:00 2001 From: mmunos Date: Tue, 10 Feb 2026 14:47:08 -0500 Subject: [PATCH 3/4] =?UTF-8?q?Ajout=20des=20cas=20de=20tests.=20-=20pour?= =?UTF-8?q?=20tester=20qu'aucune=20invalidation=20n'est=20programm=C3=A9e?= =?UTF-8?q?=20si=20le=20distributionId=20est=20vide,=20ajout=20de=20l'espa?= =?UTF-8?q?gnol,=20dont=20le=20domaine=20est=20vide.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataSet/translated_subpages.csv | 2 ++ .../Functional/Fixtures/contentPageTests.yaml | 16 +++++++--- Tests/Functional/Fixtures/languages.yaml | 22 ++++++++++++- .../Hooks/ClearCachePostProcTest.php | 32 ++++++++++++++++--- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/Tests/Functional/DataSet/translated_subpages.csv b/Tests/Functional/DataSet/translated_subpages.csv index 805ce88..80fc833 100644 --- a/Tests/Functional/DataSet/translated_subpages.csv +++ b/Tests/Functional/DataSet/translated_subpages.csv @@ -8,3 +8,5 @@ ,6,3,"Sub Subpage Dansk",1,5,"/sub/subd","clearCache_disable =",1 ,7,1,"Sys folder - English",0,0,"/sysfolder","clearCache_disable =",254 ,8,1,"Sys folder - Dansk",1,7,"/sysfolderd","clearCache_disable =",254 +,9,3,"Sub Subpage Español",2,5,"/sub/subes","clearCache_disable =",1 +,10,1,"Subpage - Español",2,3,"/subtest","clearCache_disable =",1 diff --git a/Tests/Functional/Fixtures/contentPageTests.yaml b/Tests/Functional/Fixtures/contentPageTests.yaml index 7dcc370..4a41ab9 100644 --- a/Tests/Functional/Fixtures/contentPageTests.yaml +++ b/Tests/Functional/Fixtures/contentPageTests.yaml @@ -1,15 +1,17 @@ simple: pages: - uid: 5 - modification: + modification: title: 'Testing 1' expectedArray: - pathsegment: '/en/sub*' distributionId: 'WWWWWWWWW' - pathsegment: '/dk/subtest*' distributionId: 'WWWWWWWWW' + - pathsegment: '/es/subtest*' + distributionId: 'WWWWWWWWW' - uid: 7 - modification: + modification: title: 'Renaming sysfolder' tt_content: - uid: 1 @@ -20,19 +22,23 @@ simple: distributionId: 'WWWWWWWWW' - pathsegment: '/dk/sub/subd' distributionId: 'WWWWWWWWW' + - pathsegment: '/es/sub/subes' + distributionId: 'WWWWWWWWW' - uid: 3 modification: header: 'SysFolder Content modified' -multiDomain: +multiDomain: pages: - uid: 5 - modification: + modification: title: 'Multi-domain Test' expectedArray: - pathsegment: '/sub*' distributionId: 'ENENENENENEN' - pathsegment: '/subtest*' distributionId: 'DKDKDKDKDKDK' + - pathsegment: '/' + distributionId: '' tt_content: - uid: 2 modification: @@ -41,4 +47,4 @@ multiDomain: - pathsegment: '/sub/sub' distributionId: 'ENENENENENEN' - pathsegment: '/sub/subd' - distributionId: 'DKDKDKDKDKDK' \ No newline at end of file + distributionId: 'DKDKDKDKDKDK' diff --git a/Tests/Functional/Fixtures/languages.yaml b/Tests/Functional/Fixtures/languages.yaml index e21c4ec..9d9dcf0 100644 --- a/Tests/Functional/Fixtures/languages.yaml +++ b/Tests/Functional/Fixtures/languages.yaml @@ -22,6 +22,17 @@ simple: flag: 'dk' fallbackType: 'fallback' fallbacks: 0 + 2: + title: 'Español' + enabled: true + languageId: 2 + base: '/es/' + typo3Language: 'es' + locale: 'es_ES.UTF-8' + iso-639-1: 'es' + flag: 'es' + fallbackType: 'fallback' + fallbacks: 0 multiDomain: 0: title: 'English' @@ -40,4 +51,13 @@ multiDomain: typo3Language: 'dk' locale: 'da_DK.UTF-8' iso-639-1: 'da' - flag: 'dk' \ No newline at end of file + flag: 'dk' + 2: + title: 'Español' + enabled: true + languageId: 2 + base: 'https://es.example.com/' + typo3Language: 'es' + locale: 'es_ES.UTF-8' + iso-639-1: 'es' + flag: 'es' diff --git a/Tests/Functional/Hooks/ClearCachePostProcTest.php b/Tests/Functional/Hooks/ClearCachePostProcTest.php index 47ce1c9..555e6b7 100644 --- a/Tests/Functional/Hooks/ClearCachePostProcTest.php +++ b/Tests/Functional/Hooks/ClearCachePostProcTest.php @@ -58,7 +58,7 @@ class ClearCachePostProcTest extends FunctionalTestCase * | 5 | 3 | Testing 1 | 0 | 0 | /sub/sub | * | 6 | 3 | Sub Subpage | 1 | 5 | /sub/sub | * +-----+-----+-------------------+------------------+-------------+----------+ - * + * * tt_content table structure * +-----+-----+-------------------+------------------+-------------+----------+ * | uid | pid | header | sys_language_uid | l18n_parent | colPos | @@ -82,7 +82,7 @@ protected function setUp(): void $this->setUpFrontendSite(1); $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['tm_cloudfront']['cloudfront'] = [ - 'distributionIds' => '{"www.example.com":"WWWWWWWWW","en.example.com":"ENENENENENEN","cdn.example.com":"CDNCDNCDNCDN","dk.example.com":"DKDKDKDKDKDK"}', + 'distributionIds' => '{"www.example.com":"WWWWWWWWW","en.example.com":"ENENENENENEN","cdn.example.com":"CDNCDNCDNCDN","dk.example.com":"DKDKDKDKDKDK", "es.example.com":""}', 'mode' => 'table', 'region' => 'us', 'apikey' => 'AAAAAAAAAAAAAAA', @@ -186,7 +186,17 @@ public function modifyMultiTest(): void foreach ($allRecords as $record) { var_dump($record['pathsegment'] . ' / ' . $record['distributionId']); } - $this->assertCount(count($row['expectedArray'] ?? []), $allRecords, 'Nombre d’invalidation incorrect'); + // Filtrage des éléments ayant un distributionId non vide + $expectedWithDistribution = array_filter( + $row['expectedArray'] ?? [], + fn(array $item) => !empty($item['distributionId']) + ); + + $this->assertCount( + count($expectedWithDistribution), + $allRecords, + 'Nombre d’invalidation incorrect (excluant les domaines sans CloudFront)' + ); if (isset($row['expectedArray'])) { foreach ($row['expectedArray'] as $expectedRow) { @@ -446,8 +456,22 @@ protected function checkInvalidation(array $expectedRow): void ) ); $row = $queryBuilder->executeQuery()->fetchAssociative(); + if ($expectedRow['distributionId']) { + var_dump('Checking invalidation ' . $expectedRow['pathsegment'] . ' / ' . ($expectedRow['distributionId'] ?: "(vide)")); + $this->assertNotFalse( + $expectedRow['distributionId'] + ? $row + : $row === false, + 'Aucune invalidation trouvée pour ' . $expectedRow['pathsegment'] . ' / ' . $expectedRow['distributionId']); + } + else { + var_dump('Checking no invalidation for ' . $expectedRow['pathsegment'] . ' / ' . ($expectedRow['distributionId'] ?: "(vide)")); + $this->assertFalse( + $row, + 'Invalidation existante pour ' . $expectedRow['pathsegment'] . ' alors que distributionId vide' + ); + } - $this->assertNotFalse($row, 'Aucune invalidation trouvée pour ' . $expectedRow['pathsegment'] . ' / ' . $expectedRow['distributionId']); } /** From 4a3311fa864450bfc6394376766c5b111ea4b596 Mon Sep 17 00:00:00 2001 From: mmunos Date: Tue, 10 Feb 2026 17:24:02 -0500 Subject: [PATCH 4/4] Ajustement du README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 85a8630..dfe33ef 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This extension clears the AWS CloudFront cache based on the speaking path of a p ### Using Composer -1. **Require the extension via Composer** +1. **Require the extension via Composer** In your TYPO3 project root, run: ``` composer require toumoro/tm-cloudfront @@ -24,10 +24,11 @@ This extension clears the AWS CloudFront cache based on the speaking path of a p 'apisecret' => 'YOUR_AWS_SECRET', 'region' => 'us-east-1', 'version' => 'latest', - 'distributionIds' => '{"domain1.com":"DIST_ID_1", "domain2.com":"DIST_ID_2", "cdn.domain3.com":"DIST_ID_3", "domain4.com":"DIST_ID_4, DIST_ID_5"}' + 'distributionIds' => '{"domain1.com":"DIST_ID_1", "domain2.com":"DIST_ID_2", "cdn.domain3.com":"DIST_ID_3", "domain4.com":"DIST_ID_4, DIST_ID_5", "domain5.com":""}' ] ] ``` + NB: to disable cache invalidation for a specific domain, set the distribution ID to an empty string. See domain5.com in the example above. 2. **Storage/CDN Mapping** @@ -52,5 +53,5 @@ This extension clears the AWS CloudFront cache based on the speaking path of a p ``` composer install -RUNTESTS_DIR_BIN=.Build/bin/ ./Build/Scripts/runTests.sh -p 8.2 -s functional +RUNTESTS_DIR_BIN=.Build/bin/ ./Build/Scripts/runTests.sh -p 8.4 -s functional ```