132 lines
4.6 KiB
PHP
132 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Core\Resource\Processing;
|
|
|
|
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
|
use TYPO3\CMS\Core\Resource\Event\AfterFileAddedEvent;
|
|
use TYPO3\CMS\Core\Resource\Event\AfterFileDeletedEvent;
|
|
use TYPO3\CMS\Core\Resource\Event\AfterFileReplacedEvent;
|
|
use TYPO3\CMS\Core\Resource\File;
|
|
use TYPO3\CMS\Core\Resource\FileInterface;
|
|
use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
|
|
use TYPO3\CMS\Core\Resource\Index\MetaDataRepository;
|
|
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
|
use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
|
|
|
|
/**
|
|
* Clean up database records, processed files and file references
|
|
*
|
|
* The aspect which deals with deleted files is a list of PSR-14
|
|
* event listeners which react on file deletion.
|
|
*
|
|
* @internal this is a list of Event Listeners, and not part of TYPO3 Core API.
|
|
*/
|
|
final readonly class FileDeletionAspect
|
|
{
|
|
public function __construct(
|
|
private ConnectionPool $connectionPool,
|
|
private MetaDataRepository $metaDataRepository,
|
|
private ProcessedFileRepository $processedFileRepository,
|
|
private FileIndexRepository $fileIndexRepository,
|
|
) {}
|
|
|
|
#[AsEventListener('delete-processed-files-after-add')]
|
|
public function cleanupProcessedFilesPostFileAdd(AfterFileAddedEvent $event): void
|
|
{
|
|
$this->cleanupProcessedFiles($event->getFile());
|
|
}
|
|
|
|
#[AsEventListener('delete-processed-files-after-replace')]
|
|
public function cleanupProcessedFilesPostFileReplace(AfterFileReplacedEvent $event): void
|
|
{
|
|
$this->cleanupProcessedFiles($event->getFile());
|
|
}
|
|
|
|
#[AsEventListener('delete-processed-files-after-delete')]
|
|
public function removeFromRepositoryAfterFileDeleted(AfterFileDeletedEvent $event): void
|
|
{
|
|
$this->removeFromRepository($event->getFile());
|
|
}
|
|
|
|
/**
|
|
* Cleanup database record for a deleted file
|
|
*/
|
|
private function removeFromRepository(FileInterface $fileObject): void
|
|
{
|
|
// remove file from repository
|
|
if ($fileObject instanceof File) {
|
|
$this->cleanupProcessedFiles($fileObject);
|
|
$this->cleanupCategoryReferences($fileObject);
|
|
$this->fileIndexRepository->remove($fileObject->getUid());
|
|
$this->metaDataRepository->removeByFileUid($fileObject->getUid());
|
|
|
|
// remove all references
|
|
$this->connectionPool->getConnectionForTable('sys_file_reference')->delete(
|
|
'sys_file_reference',
|
|
[
|
|
'uid_local' => $fileObject->getUid(),
|
|
]
|
|
);
|
|
} elseif ($fileObject instanceof ProcessedFile) {
|
|
$this->processedFileRepository->remove($fileObject);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove all category references of the deleted file.
|
|
*/
|
|
private function cleanupCategoryReferences(File $fileObject): void
|
|
{
|
|
// Retrieve the file metadata uid which is different from the file uid.
|
|
$metadataProperties = $fileObject->getMetaData()->get();
|
|
$metaDataUid = (int)($metadataProperties['_ORIG_uid'] ?? $metadataProperties['uid'] ?? 0);
|
|
|
|
if ($metaDataUid <= 0) {
|
|
// No metadata record exists for the given file. The file might not
|
|
// have been indexed or the metadata record was deleted manually.
|
|
return;
|
|
}
|
|
|
|
$this->connectionPool->getConnectionForTable('sys_category_record_mm')->delete(
|
|
'sys_category_record_mm',
|
|
[
|
|
'uid_foreign' => $metaDataUid,
|
|
'tablenames' => 'sys_file_metadata',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Remove all processed files that belong to the given File object
|
|
*/
|
|
private function cleanupProcessedFiles(FileInterface $fileObject): void
|
|
{
|
|
// only delete processed files of File objects
|
|
if (!$fileObject instanceof File) {
|
|
return;
|
|
}
|
|
foreach ($this->processedFileRepository->findAllByOriginalFile($fileObject) as $processedFile) {
|
|
if ($processedFile->exists()) {
|
|
$processedFile->delete(true);
|
|
}
|
|
$this->removeFromRepository($processedFile);
|
|
}
|
|
}
|
|
}
|