diff --git a/Classes/Cache/CloudFrontCacheManager.php b/Classes/Cache/CloudFrontCacheManager.php index d577c79..b7349d2 100644 --- a/Classes/Cache/CloudFrontCacheManager.php +++ b/Classes/Cache/CloudFrontCacheManager.php @@ -56,8 +56,8 @@ public function __construct() public function fileMod(Folder|File|ProcessedFile $resource): void { // Skip processed files that are already processed - if($resource instanceof ProcessedFile) { - if($resource->isProcessed()) return; + if ($resource instanceof ProcessedFile) { + if ($resource->isProcessed()) return; } $storage = $resource->getStorage(); @@ -72,7 +72,7 @@ public function fileMod(Folder|File|ProcessedFile $resource): void $this->enqueue($resource->getIdentifier() . $wildcard, $distributionIds); $this->clearCache(); - if(isset($GLOBALS['BE_USER'])) { + if (isset($GLOBALS['BE_USER'])) { $errorMessage = 'fileMod distributionsIds : ' . $distributionIds . ' resource identifier : ' . $resource->getIdentifier() . ' wildcard : ' . $wildcard; $GLOBALS['BE_USER']->writelog(4, 0, 0, 0, $errorMessage, ["ext" => "tm_cloudfront"]); } @@ -331,13 +331,16 @@ public function getLanguagesDomains(int $uid_page): array return $domains; } - public function getLanguageHost(SiteLanguage $language): string { + 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) { + if ( + $currentRequest + && $currentRequest instanceof \Psr\Http\Message\ServerRequestInterface + ) { return $currentRequest->getUri()->getHost(); } return ''; diff --git a/Classes/EventListener/FileAndFolderEventListener.php b/Classes/EventListener/FileAndFolderEventListener.php index 9aa08ca..a37a300 100644 --- a/Classes/EventListener/FileAndFolderEventListener.php +++ b/Classes/EventListener/FileAndFolderEventListener.php @@ -18,8 +18,16 @@ namespace Toumoro\TmCloudfront\EventListener; use Toumoro\TmCloudfront\Cache\CloudFrontCacheManager; -use TYPO3\CMS\Core\Resource\Event\{AfterFileMovedEvent, AfterFileRenamedEvent, AfterFileReplacedEvent, - AfterFileDeletedEvent, AfterFileContentsSetEvent, AfterFolderMovedEvent, AfterFolderRenamedEvent, AfterFolderDeletedEvent}; +use TYPO3\CMS\Core\Resource\Event\{ + AfterFileMovedEvent, + AfterFileRenamedEvent, + AfterFileReplacedEvent, + AfterFileDeletedEvent, + AfterFileContentsSetEvent, + AfterFolderMovedEvent, + AfterFolderRenamedEvent, + AfterFolderDeletedEvent +}; class FileAndFolderEventListener { @@ -49,7 +57,8 @@ public function afterFileDeleted(AfterFileDeletedEvent $event): void { try { $this->cacheManager->fileMod($event->getFile()); - } catch (\Exception $e) {} + } catch (\Exception $e) { + } } public function afterFileContentsSet(AfterFileContentsSetEvent $event): void diff --git a/Classes/Hooks/ClearCachePostProc.php b/Classes/Hooks/ClearCachePostProc.php index ac34163..1019a10 100644 --- a/Classes/Hooks/ClearCachePostProc.php +++ b/Classes/Hooks/ClearCachePostProc.php @@ -36,8 +36,7 @@ class ClearCachePostProc public function __construct( protected SiteFinder $siteFinder - ) - { + ) { $this->cloudFrontConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class) ->get('tm_cloudfront')['cloudfront']; $this->cacheManager = GeneralUtility::makeInstance(CloudFrontCacheManager::class); @@ -55,6 +54,11 @@ public function __construct( */ public function clearCachePostProc(&$params, &$pObj): void { + // looks if the table array key is set and in [content,pages] if not returns. This to avoid running hook on unwanted table like sys_file_metadata + if (!empty($params['table']) && !in_array($params['table'], ['tt_content', 'pages'])) { + return; + } + // Reset the queue after processing for testing purposes $this->cacheManager->resetQueue(); @@ -109,7 +113,7 @@ public function clearCachePostProc(&$params, &$pObj): void // Priority to TsConfig settings if (!empty($tsConfig['TCEMAIN.'])) { - if(!empty($tsConfig['TCEMAIN.']['distributionIds'])) { + if (!empty($tsConfig['TCEMAIN.']['distributionIds'])) { $distributionIds = $tsConfig['TCEMAIN.']['distributionIds']; } } @@ -221,7 +225,7 @@ private function isPageDeleted($uid): int $queryBuilder->getRestrictions()->removeAll(); - return (int)$queryBuilder + return (int)$queryBuilder ->select('deleted') ->from('pages') ->where( diff --git a/Classes/Task/ClearTask.php b/Classes/Task/ClearTask.php index c834451..090d6f1 100644 --- a/Classes/Task/ClearTask.php +++ b/Classes/Task/ClearTask.php @@ -2,6 +2,8 @@ namespace Toumoro\TmCloudfront\Task; + + use Aws\CloudFront\CloudFrontClient; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Database\Connection; diff --git a/Tests/Functional/Hooks/FileMetadataTest.php b/Tests/Functional/Hooks/FileMetadataTest.php new file mode 100644 index 0000000..a4231aa --- /dev/null +++ b/Tests/Functional/Hooks/FileMetadataTest.php @@ -0,0 +1,66 @@ +importCSVDataSet(__DIR__ . '/../DataSet/be_users.csv'); + $this->importCSVDataSet(__DIR__ . '/../DataSet/sys_file_storage.csv'); + + $this->setUpBackendUser(1); + + $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['tm_cloudfront']['cloudfront'] = [ + 'distributionIds' => '{"www.example.com":"WWWWWWWWW","cdn.example.com":"CDNCDNCDNCDN"}', + 'mode' => 'table', + 'region' => 'us', + 'apikey' => 'AAAAAAAAAAAAAAA', + 'apisecret' => 'AAAAAAAAAAAAAAA', + 'version' => 'AAAAAAAAAAAAAAA', + ]; + } + + /** + * test metadadata invalidation + */ + #[\PHPUnit\Framework\Attributes\Test] + public function editingFileMetadataDoesNotCreateRootInvalidation(): void + { + $storage = GeneralUtility::makeInstance(ResourceFactory::class)->getStorageObject(1); + + // Create a test file outside of the storage path + $tempFileName = tempnam(sys_get_temp_dir(), 'test-file'); + file_put_contents($tempFileName, 'test content'); + $file = $storage->addFile($tempFileName, $storage->getRootLevelFolder(), 'test-file.txt'); + + // Clear any invalidations created during file upload + GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable('tx_tmcloudfront_domain_model_invalidation') + ->truncate('tx_tmcloudfront_domain_model_invalidation'); + + $subject = $this->get(MetaDataRepository::class); + $result = $subject->update(1, [ + 'title' => 'test2', + ]); + + // Assert that no "/" invalidation was created + $rows = $this->getAllRecords('tx_tmcloudfront_domain_model_invalidation'); + + $pathSegments = array_column($rows, 'pathsegment'); + $this->assertNotContains('/', $pathSegments, 'Root invalidation "/" should not be created when editing file metadata.'); + $this->assertNotContains('/test-file.txt', $pathSegments, 'The file path should not be invalidated when editing its metadata.'); + } +}