Skip to content

Commit

Permalink
Merge pull request #20 from magento-hackathon/improve-remove-media
Browse files Browse the repository at this point in the history
enables cache cleaning with option switch
  • Loading branch information
peterjaap authored Mar 16, 2023
2 parents 6147ee4 + 53c4302 commit 447e799
Showing 1 changed file with 79 additions and 43 deletions.
122 changes: 79 additions & 43 deletions Console/Command/RemoveUnusedMediaCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Console\Cli;
use Magento\Framework\Filesystem;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
Expand All @@ -14,6 +15,11 @@

class RemoveUnusedMediaCommand extends Command
{
private const OPTION_DRY_RUN = 'dry-run';
private const OPTION_INCLUDING_CACHE = 'including-cache';
private const OPTION_FORCE = 'force';
private const COMMAND_NAME_EAV_MEDIA_REMOVE_UNUSED = 'eav:media:remove-unused';

/**
* @var ResourceConnection
*/
Expand All @@ -28,71 +34,76 @@ public function __construct(Filesystem $filesystem, ResourceConnection $resource
{
parent::__construct($name);
$this->resourceConnection = $resourceConnection;
$this->filesystem = $filesystem;
}

/**
* Init command
*/
protected function configure()
{
$this
->setName('eav:media:remove-unused')
->setDescription('Remove unused product images')
->addOption('dry-run')
->addOption('force');
$this->filesystem = $filesystem;
}

public function execute(InputInterface $input, OutputInterface $output): int
{
$fileSize = 0;
$fileSize = 0;
$countFiles = 0;
$isDryRun = $input->getOption('dry-run');
$isForce = $input->getOption('force');
$isForce = $input->getOption(self::OPTION_FORCE);
$isDryRun = $input->getOption(self::OPTION_DRY_RUN);
$deleteCacheAsWell = $input->getOption(self::OPTION_INCLUDING_CACHE);

if (!$isDryRun && !$isForce) {
if (!$input->isInteractive()) {
$output->writeln('ERROR: neither --dry-run nor --force options were supplied, and we are not running interactively.');

return 1; // error.
$output->writeln(
sprintf(
'ERROR: neither --%s nor --%s options were supplied, and we are not running interactively.', self::OPTION_DRY_RUN,
self::OPTION_FORCE
)
);

return Cli::RETURN_FAILURE;
}

$output->writeln(
'<comment>WARNING: this is not a dry run. If you want to do a dry-run, add --dry-run.</comment>'
sprintf('<comment>WARNING: this is not a dry run. If you want to do a dry-run, add --%s.</comment>', self::OPTION_DRY_RUN)
);

$question = new ConfirmationQuestion('<comment>Are you sure you want to continue? [No]</comment>', false);

if (!$this->getHelper('question')->ask($input, $output, $question)) {
return 1; // error.
return Cli::RETURN_FAILURE;
}
}

$imageDir = $this->getImageDir();
$connection = $this->resourceConnection->getConnection('core_read');
$imageDir = $this->getImageDir();
$connection = $this->resourceConnection->getConnection('core_read');
$mediaGalleryTable = $this->resourceConnection->getTableName('catalog_product_entity_media_gallery');

$directoryIterator = new RecursiveDirectoryIterator($imageDir);

$imagesToKeep = $connection->fetchCol('SELECT value FROM ' . $mediaGalleryTable);

foreach (new RecursiveIteratorIterator($directoryIterator) as $file) {
// Cached and placeholder path guard
if ($this->isInCachePath($file) || $this->isInPlaceholderPath($file)) {
// Directory guard
if (is_dir($file)) {
continue;
}

// Directory guard
if (is_dir($file)) {
// Cached guard
if ($this->isInCachePath($file) && !$deleteCacheAsWell) {
continue;
}

// Filepath guard
$filePath = str_replace($imageDir, "", $file);
// Filepath guard
if (empty($filePath)) {
continue;
}

if (in_array($filePath, $imagesToKeep)) {
$filePathWithoutCacheDir = preg_replace('#/cache_*/[a-z0-9]+(/[a-z0-9]/[a-z0-9]/.+?)#i', '$1', $filePath);
if (in_array($filePathWithoutCacheDir, $imagesToKeep, true)) {
continue;
}

// Placeholder guard
if ($this->isInPlaceholderPath($file)) {
continue;
}

if (in_array($filePath, $imagesToKeep, true)) {
continue;
}

Expand All @@ -109,20 +120,7 @@ public function execute(InputInterface $input, OutputInterface $output): int

$this->printResult($output, $isDryRun, $countFiles, $fileSize);

return 0; // success.
}

private function printResult(OutputInterface $output, $isDryRun, int $countFiles, int $filesize): void
{
$actionName = 'Deleted';

if ($isDryRun) {
$actionName = 'Would delete';
}

$fileSizeInMB = number_format($filesize / 1024 / 1024, '2');

$output->writeln("<info>{$actionName} {$countFiles} unused images. {$fileSizeInMB} MB</info>");
return Cli::RETURN_SUCCESS;
}

private function getImageDir(): string
Expand All @@ -141,4 +139,42 @@ private function isInPlaceholderPath(?string $file): bool
{
return strpos($file, '/placeholder') !== false;
}

private function printResult(OutputInterface $output, $isDryRun, int $countFiles, int $filesize): void
{
$actionName = 'Deleted';

if ($isDryRun) {
$actionName = 'Would delete';
}

$fileSizeInMB = number_format($filesize / 1024 / 1024, '2');

$output->writeln("<info>{$actionName} {$countFiles} unused images. {$fileSizeInMB} MB</info>");
}

protected function configure(): void
{
$this->setName(self::COMMAND_NAME_EAV_MEDIA_REMOVE_UNUSED);
$this->setDescription('Remove unused product images');

$this->addOption(
self::OPTION_INCLUDING_CACHE,
'c',
null,
'Also clear the ./cache/* entries for the corresponding images'
);
$this->addOption(
self::OPTION_DRY_RUN,
'd',
null,
'Only process files and output what would be deleted, but don\'t delete anything'
);
$this->addOption(
self::OPTION_FORCE,
'f',
null,
'Prevent confirmation question and force execution. Option is required for non-interactive execution.'
);
}
}

0 comments on commit 447e799

Please sign in to comment.