Commit bf3c79af authored by Kevin von Spiczak's avatar Kevin von Spiczak
Browse files

[TASK] add DeleteOldMailsCommand

parent 9d5e95f9
......@@ -34,6 +34,8 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
use TYPO3\CMS\Extbase\Object\Exception;
......@@ -45,7 +47,11 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
* @package SGalinski\SgMail\Command
*/
class DeleteOldMailsCommand extends Command {
private const TABLE_NAME = 'tx_sgmail_domain_model_mail';
private const TABLE_NAME_MAIL = 'tx_sgmail_domain_model_mail';
private const TABLE_NAME_FILE_REFERENCE = 'sys_file_reference';
private const TABLE_NAME_FILE = 'sys_file';
private const TABLE_NAME_REFINDEX = 'sys_refindex';
/**
* @var int
*/
......@@ -79,7 +85,7 @@ class DeleteOldMailsCommand extends Command {
if ($maxAgeInDays <= 0) {
$io->error('Please enter a maximum age (in days) for the mail\'s to be deleted.');
return;
return 0;
}
if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '10.4.0', '<')) {
......@@ -93,11 +99,11 @@ class DeleteOldMailsCommand extends Command {
$mailUidsForDeletion = $mailRepository->findMailsForDeletion($maxAgeInDays);
if (!$mailUidsForDeletion) {
$io->success("No matching mails found for deletion criteria: older than $maxAgeInDays days");
return;
return 0;
}
$this->markRelatedAttachmentsAsDeleted($mailUidsForDeletion);
$this->markOldMailsAsDeleted($mailUidsForDeletion);
$this->deleteAttachments($mailUidsForDeletion);
$this->deleteOldMails($mailUidsForDeletion);
if ($this->amountOfDeletedRecords > 0) {
$io->success('Successfully deleted ' . $this->amountOfDeletedRecords . ' records.');
......@@ -109,43 +115,128 @@ class DeleteOldMailsCommand extends Command {
}
/**
* Deletes all tx_sgmail_domain_model_mail records, where the uid matches one of the uids in $mailUidsForDeletion
*
* @param array $mailUidsForDeletion
*/
private function markOldMailsAsDeleted(array $mailUidsForDeletion): void {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE_NAME);
$queryBuilder
->update(self::TABLE_NAME)
->set('deleted', 1)
private function deleteOldMails(array $mailUidsForDeletion): void {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::TABLE_NAME_MAIL
);
$this->amountOfDeletedRecords += $queryBuilder
->delete(self::TABLE_NAME_MAIL)
->where(
$queryBuilder->expr()->in(
'uid',
$queryBuilder->createNamedParameter($mailUidsForDeletion, Connection::PARAM_INT_ARRAY)
)
);
$result = $queryBuilder->execute();
$this->amountOfDeletedRecords += $result;
)->execute();
}
private function markRelatedAttachmentsAsDeleted(array $mailUidsForDeletion): void {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE_NAME);
$queryBuilder
->update('sys_file_reference')
->set('deleted', 1)
/**
* Deletes the attachments (sys_file_reference / sys_file records), referenced in the mails to be deleted.
* For every file reference found in a mail record, we check if it is the only reference,
* or if we can find more records, referencing the same sys_file.
*
* The sys_file_reference found in the mail record is always deleted.
* If the referenced file has no more references, besides the one we just deleted, both the sys_file record and
* the actual file in the file system is deleted as well.
*
* @param array $mailUidsForDeletion
*/
private function deleteAttachments(array $mailUidsForDeletion): void {
$fileReferenceQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::TABLE_NAME_FILE_REFERENCE
);
// Fetch all sys_file_reference records, with a relation to the mails we want to delete.
$sysFileReferencesToDelete = $fileReferenceQueryBuilder
->select('uid', 'uid_local')
->from(self::TABLE_NAME_FILE_REFERENCE)
->where(
$queryBuilder->expr()->in(
$fileReferenceQueryBuilder->expr()->in(
'uid_foreign',
$queryBuilder->createNamedParameter($mailUidsForDeletion, Connection::PARAM_INT_ARRAY)
$fileReferenceQueryBuilder->createNamedParameter(
$mailUidsForDeletion, Connection::PARAM_INT_ARRAY
)
),
$queryBuilder->expr()->eq(
'tablenames', $queryBuilder->createNamedParameter(self::TABLE_NAME, Connection::PARAM_STR)
$fileReferenceQueryBuilder->expr()->eq(
'tablenames',
$fileReferenceQueryBuilder->createNamedParameter(self::TABLE_NAME_MAIL, Connection::PARAM_STR)
),
$queryBuilder->expr()->eq(
'fieldname', $queryBuilder->createNamedParameter('attachments', Connection::PARAM_STR)
$fileReferenceQueryBuilder->expr()->eq(
'fieldname',
$fileReferenceQueryBuilder->createNamedParameter('attachments', Connection::PARAM_STR)
),
);
$result = $queryBuilder->execute();
$this->amountOfDeletedRecords += $result;
)->execute()->fetchAllAssociative();
foreach ($sysFileReferencesToDelete as $sysFileReferenceToDelete) {
$sysFileReferenceUid = (int) $sysFileReferenceToDelete['uid'];
$sysFileUid = (int) $sysFileReferenceToDelete['uid_local'];
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
try {
$sysFileReference = $resourceFactory->getFileReferenceObject($sysFileReferenceUid);
} catch (ResourceDoesNotExistException $e) {
$sysFileReference = NULL;
}
if ($sysFileReference === NULL) {
return;
}
$referencedSysFile = $sysFileReference->getOriginalFile();
$refIndexQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(
self::TABLE_NAME_REFINDEX
)->createQueryBuilder();
// Check if there are more rows in sys_refindex,
// referencing the same file as the current $sysFileReferenceToDelete.
// If we do not find any rows here, we delete
// * the sys_file_reference record,
// * the sys_file record,
// * the actual file in the filesystem
// If we find more rows here, only the sys_file_reference record is deleted.
$countRefIndexEntries = $refIndexQueryBuilder
->count('*')
->from(self::TABLE_NAME_REFINDEX)
->where(
$refIndexQueryBuilder->expr()->eq(
'ref_table',
$refIndexQueryBuilder->createNamedParameter(self::TABLE_NAME_FILE, Connection::PARAM_STR)
),
$refIndexQueryBuilder->expr()->eq(
'ref_uid',
$refIndexQueryBuilder->createNamedParameter($sysFileUid, Connection::PARAM_INT)
),
// exclude current sys_file_reference record
$refIndexQueryBuilder->expr()->neq(
'recuid',
$refIndexQueryBuilder->createNamedParameter($sysFileReferenceUid, Connection::PARAM_INT)
)
)->execute()->fetchOne();
if ($countRefIndexEntries <= 0) {
$referencedSysFile->delete();
}
$deleteFileReferenceQueryBuilder = GeneralUtility::makeInstance(
ConnectionPool::class
)->getConnectionForTable(
self::TABLE_NAME_FILE_REFERENCE
)->createQueryBuilder();
// delete the sys_file_reference
$this->amountOfDeletedRecords += $deleteFileReferenceQueryBuilder
->delete(self::TABLE_NAME_FILE_REFERENCE)
->where(
$deleteFileReferenceQueryBuilder->expr()->eq(
'uid',
$deleteFileReferenceQueryBuilder->createNamedParameter(
$sysFileReferenceUid, Connection::PARAM_INT
)
)
)->execute();
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment