From 412b59d77f746cf3583bb5353e666a5892d8bf9b Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 19 Sep 2019 10:47:37 +0200 Subject: [PATCH] WIP Remove files Remove files from sys_file db table and filesystem. Add this to delete all, in order to delete all matching files. But also add to past cleanup, to only remove files which do no longer have relations. This last part was not tested, due to missing testing environment. --- Classes/Service/CleanupService.php | 82 +++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/Classes/Service/CleanupService.php b/Classes/Service/CleanupService.php index 39f7f89..1cfa9fe 100644 --- a/Classes/Service/CleanupService.php +++ b/Classes/Service/CleanupService.php @@ -6,6 +6,8 @@ use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\QueryBuilder; +use TYPO3\CMS\Core\Resource\ResourceStorage; +use TYPO3\CMS\Core\Resource\StorageRepository; use TYPO3\CMS\Core\Utility\GeneralUtility; class CleanupService @@ -23,6 +25,8 @@ class CleanupService 'tx_events_domain_model_event', ])); $dataHandler->process_cmdmap(); + + $this->deleteAllFiles(); } public function deletePastData() @@ -33,6 +37,8 @@ class CleanupService /* @var DataHandler $dataHandler */ $dataHandler->start([], $this->getDeletionStructureForEventsWithoutDates()); $dataHandler->process_cmdmap(); + + $this->deleteDanglingFiles(); } private function truncateTables(string ...$tableNames): void @@ -68,11 +74,11 @@ class CleanupService private function getRecordsToDelete(string $tableName): array { + /* @var QueryBuilder $queryBuilder */ $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getConnectionForTable($tableName) ->createQueryBuilder(); - /* @var QueryBuilder $queryBuilder */ $records = $queryBuilder->select('uid') ->from($tableName) ->execute() @@ -142,4 +148,78 @@ class CleanupService } return $dataStructure; } + + private function deleteAllFiles() + { + $this->deleteFiles($this->getRelatedFileInformation()); + } + + private function deleteDanglingFiles() + { + $this->deleteFiles($this->getRelatedFileInformation(function (QueryBuilder $queryBuilder) { + $queryBuilder->leftJoin( + 'file', + 'sys_file_reference', + 'reference', + $queryBuilder->expr()->eq('file.uid', 'reference.local_uid') + ); + $queryBuilder->addWhere($queryBuilder->expr()->isNull('reference.uid')); + })); + } + + private function deleteFiles(array $files) + { + $uidsToRemove = []; + foreach ($filesToDelete as $fileToDelete) { + $this->deleteFileFromFilesystem($fileToDelete['storage'], $fileToDelete['identifier']); + $uidsToRemove[] = $fileToDelete['uid']; + } + + $this->deleteFileRecords(... $uidsToRemove); + } + + private function getRelatedFileInformation(callable $whereGenerator = null): array + { + /* @var QueryBuilder $queryBuilder */ + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable('sys_file'); + + $queryBuilder->select('file.identifier', 'file.storage', 'file.uid') + ->from('sys_file', 'file') + ->where($queryBuilder->expr()->like( + 'file.identifier', + $queryBuilder->createNamedParameter('/staedte/%/events/%') + )); + + if ($whereGenerator !== null) { + $whereGenerator($queryBuilder); + } + + return $queryBuilder->execute()->fetchAll(); + } + + private function deleteFileFromFilesystem(int $storageUid, string $filePath) + { + /* @var ResourceStorage $storage */ + $storage = GeneralUtility::makeInstance(StorageRepository::class) + ->findByUid($storageUid); + + if ($storage->hasFile($filePath) === false) { + return; + } + + $storage->deleteFile($storage->getFile($filePath)); + } + + private function deleteFileRecords(int ...$uids) + { + /* @var QueryBuilder $queryBuilder */ + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable('sys_file'); + + $queryBuilder->delete('sys_file') + ->where('uid in (:uids)') + ->setParameter(':uids', $uids, Connection::PARAM_INT_ARRAY) + ->execute(); + } }