Skip to content

Commit

Permalink
Merge pull request #10 from derhansen/master
Browse files Browse the repository at this point in the history
Added 2 new features and a minor improvement
  • Loading branch information
borishinzer authored Oct 18, 2021
2 parents f58260d + 7aa8314 commit 3e71a22
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 6 deletions.
11 changes: 9 additions & 2 deletions Classes/Command/CleanupCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public function configure()
'Regular expression to match (preg_match) the filename against. Matching files are excluded from cleanup. Example to match only *.pdf: /^(?!.*\b.pdf\b)/',
'/index.html/i'
)
->addOption(
'path-deny-pattern',
'p',
InputOption::VALUE_OPTIONAL,
'Regular expression to match (preg_match) the filepath against. Matching files are excluded from cleanup. Example to exclude "files" and "downloads" directory: /(files|downloads)/i'
)
->addOption(
'recursive',
'r',
Expand Down Expand Up @@ -76,6 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$recursive = $input->getOption('recursive');
$dryRun = $input->getOption('dry-run');
$fileDenyPattern = $input->getOption('file-deny-pattern');
$pathDenyPattern = $input->getOption('path-deny-pattern');

if ($age === false) {
$io->error('Value of \'age\' isn\'t recognized. See http://php.net/manual/en/function.strtotime.php for possible values');
Expand Down Expand Up @@ -107,7 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
$folderObject = $storage->getFolder($folderPath);

$files = $fileRepository->findUnusedFile($folderObject, $recursive, $fileDenyPattern);
$files = $fileRepository->findUnusedFile($folderObject, $recursive, $fileDenyPattern, $pathDenyPattern);

if ($output->isVerbose()) {
$io->newLine();
Expand All @@ -119,7 +126,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
foreach ($files as $key => $file) {
$fileAge = $file->getLastReferenceTimestamp() ?: $file->getResource()->getModificationTime();
if ($output->isVerbose()) {
$io->writeln('File: ' . $file->getName() . ': ' . date('Ymd', $fileAge) . ' < ' . date('Ymd', $age));
$io->writeln('File: ' . $file->getPublicUrl() . ': ' . date('Ymd', $fileAge) . ' < ' . date('Ymd', $age));
}
// Remove all files "newer" than age from our array
if ($fileAge > $age) {
Expand Down
34 changes: 30 additions & 4 deletions Classes/Domain/Repository/FileRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
use TYPO3\CMS\Core\Resource\ProcessedFile;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
use WebVision\WvFileCleanup\FileFacade;
use WebVision\WvFileCleanup\Service\FileCollectionService;

/**
* Class FileRepository
Expand All @@ -37,46 +37,67 @@ class FileRepository implements SingletonInterface
*/
protected $fileNameDenyPattern = '';

/**
* @var string
*/
protected $pathDenyPattern = '';

/**
* @var \TYPO3\CMS\Core\Database\ConnectionPool
*/
protected $connection = null;

/**
* @var FileCollectionService
*/
protected $fileCollectionService;

/**
* FileRepository constructor
*/
public function __construct()
{
$this->connection = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class);
$this->fileCollectionService = GeneralUtility::makeInstance(FileCollectionService::class);
$this->fileNameDenyPattern = GeneralUtility::makeInstance(ExtensionConfiguration::class)
->get('wv_file_cleanup', 'fileNameDenyPattern');
$this->pathDenyPattern = GeneralUtility::makeInstance(ExtensionConfiguration::class)
->get('wv_file_cleanup', 'pathDenyPattern');
}

/**
* Find all unused files
*
* @param Folder $folder
* @param bool $recursive
* @param string $fileDenyPattern
* @param string|null $fileDenyPattern
*
* @return \WebVision\WvFileCleanup\FileFacade[]
*/
public function findUnusedFile(Folder $folder, $recursive = true, $fileDenyPattern = null)
public function findUnusedFile(Folder $folder, $recursive = true, string $fileDenyPattern = null, string $pathDenyPattern = null)
{
$this->fileCollectionService->initialize($folder->getStorage()->getUid(), $folder->getIdentifier());

$return = [];
$files = $folder->getFiles(0, 0, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive);
if ($fileDenyPattern === null) {
$fileDenyPattern = $this->fileNameDenyPattern;
}
if ($pathDenyPattern === null) {
$pathDenyPattern = $this->pathDenyPattern;
}

// filer out all files in _recycler_ and _processed_ folder + check fileDenyPattern
$files = array_filter($files, function (FileInterface $file) use ($fileDenyPattern) {
$files = array_filter($files, function (FileInterface $file) use ($fileDenyPattern, $pathDenyPattern) {
if ($file->getParentFolder()->getName() === '_recycler_' || $file instanceof ProcessedFile) {
return false;
}
if (!empty($fileDenyPattern) && preg_match($fileDenyPattern, $file->getName())) {
return false;
}
if (!empty($pathDenyPattern) && preg_match($pathDenyPattern, $file->getPublicUrl())) {
return false;
}
return true;
});

Expand All @@ -85,6 +106,11 @@ public function findUnusedFile(Folder $folder, $recursive = true, $fileDenyPatte
return $this->getReferenceCount($file) === 0;
});

// Filter out all files that are used in FileCollections of type "folder" or "category"
$files = array_filter($files, function (File $file) {
return !$this->fileCollectionService->isFileCollectionFile($file);
});

foreach ($files as $file) {
$return[] = new FileFacade($file);
}
Expand Down
132 changes: 132 additions & 0 deletions Classes/Service/FileCollectionService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php
namespace WebVision\WvFileCleanup\Service;

use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\FileCollectionRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class FileCollectionService
{
/**
* @var FileCollectionRepository
*/
protected $fileCollectionRepository;

/**
* Keeps the file uids of all files which are used in file collections of the type "folder" or "category"
*
* @var array
*/
protected $fileUids = [];

public function __construct()
{
$this->fileCollectionRepository = GeneralUtility::makeInstance(FileCollectionRepository::class);
}

/**
* Initializes the $fileUids array
*
* @param int $storage
* @param string $folder
* @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
*/
public function initialize(int $storage, string $folder)
{
$fileCollectionUids = array_unique(
array_merge(
$this->getFileCollectionUidsByStorageAndFolder($storage, $folder),
$this->getFileCollectionUidsForCategoryCollections()
)
);

foreach ($fileCollectionUids as $collectionUid) {
$fileCollection = $this->fileCollectionRepository->findByUid($collectionUid);
$fileCollection->loadContents();

$fileUids = [];
/** @var File $file */
foreach ($fileCollection->getItems() as $file) {
$fileUids[] = $file->getUid();
}

$this->fileUids = array_unique(array_merge($this->fileUids, $fileUids));
}
}

/**
* Returns, if the given file is used in a FileCollection of the type "folder" or "category"
*
* @param File $file
* @return bool
*/
public function isFileCollectionFile(File $file): bool
{
return in_array($file->getUid(), $this->fileUids, true);
}

private function getFileCollectionUidsByStorageAndFolder(int $storage, string $folder): array
{
$connection = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connection->getQueryBuilderForTable('sys_file_collection');
$queryResult = $queryBuilder
->select('uid')
->from('sys_file_collection')
->where(
$queryBuilder->expr()->eq(
'type',
$queryBuilder->createNamedParameter('folder', Connection::PARAM_STR)
),
$queryBuilder->expr()->eq(
'storage',
$queryBuilder->createNamedParameter($storage, Connection::PARAM_INT)
),
$queryBuilder->expr()->neq(
'folder',
$queryBuilder->createNamedParameter('', Connection::PARAM_STR)
),
$queryBuilder->expr()->like(
'folder',
$queryBuilder->createNamedParameter(
$queryBuilder->escapeLikeWildcards($folder) . '%',
Connection::PARAM_STR
)
)
)
->execute()
->fetchAll();

$result = [];
foreach ($queryResult as $record) {
$result[] = $record['uid'];
}

return $result;
}

private function getFileCollectionUidsForCategoryCollections(): array
{
$connection = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connection->getQueryBuilderForTable('sys_file_collection');
$queryResult = $queryBuilder
->select('uid')
->from('sys_file_collection')
->where(
$queryBuilder->expr()->eq(
'type',
$queryBuilder->createNamedParameter('category', Connection::PARAM_STR)
)
)
->execute()
->fetchAll();

$result = [];
foreach ($queryResult as $record) {
$result[] = $record['uid'];
}

return $result;
}
}
3 changes: 3 additions & 0 deletions ext_conf_template.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# cat=settings; type=string; label= LLL:EXT:wv_file_cleanup/Resources/Private/Language/locallang_mod_cleanup.xml:ext_conf.fileNameDenyPattern
fileNameDenyPattern = /index.html/i

# cat=settings; type=string; label= LLL:EXT:wv_file_cleanup/Resources/Private/Language/locallang_mod_cleanup.xml:ext_conf.pathDenyPattern
pathDenyPattern =

0 comments on commit 3e71a22

Please sign in to comment.