Skip to content

Commit 447e799

Browse files
authored
Merge pull request #20 from magento-hackathon/improve-remove-media
enables cache cleaning with option switch
2 parents 6147ee4 + 53c4302 commit 447e799

File tree

1 file changed

+79
-43
lines changed

1 file changed

+79
-43
lines changed

Console/Command/RemoveUnusedMediaCommand.php

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Magento\Framework\App\Filesystem\DirectoryList;
66
use Magento\Framework\App\ResourceConnection;
7+
use Magento\Framework\Console\Cli;
78
use Magento\Framework\Filesystem;
89
use RecursiveDirectoryIterator;
910
use RecursiveIteratorIterator;
@@ -14,6 +15,11 @@
1415

1516
class RemoveUnusedMediaCommand extends Command
1617
{
18+
private const OPTION_DRY_RUN = 'dry-run';
19+
private const OPTION_INCLUDING_CACHE = 'including-cache';
20+
private const OPTION_FORCE = 'force';
21+
private const COMMAND_NAME_EAV_MEDIA_REMOVE_UNUSED = 'eav:media:remove-unused';
22+
1723
/**
1824
* @var ResourceConnection
1925
*/
@@ -28,71 +34,76 @@ public function __construct(Filesystem $filesystem, ResourceConnection $resource
2834
{
2935
parent::__construct($name);
3036
$this->resourceConnection = $resourceConnection;
31-
$this->filesystem = $filesystem;
32-
}
33-
34-
/**
35-
* Init command
36-
*/
37-
protected function configure()
38-
{
39-
$this
40-
->setName('eav:media:remove-unused')
41-
->setDescription('Remove unused product images')
42-
->addOption('dry-run')
43-
->addOption('force');
37+
$this->filesystem = $filesystem;
4438
}
4539

4640
public function execute(InputInterface $input, OutputInterface $output): int
4741
{
48-
$fileSize = 0;
42+
$fileSize = 0;
4943
$countFiles = 0;
50-
$isDryRun = $input->getOption('dry-run');
51-
$isForce = $input->getOption('force');
44+
$isForce = $input->getOption(self::OPTION_FORCE);
45+
$isDryRun = $input->getOption(self::OPTION_DRY_RUN);
46+
$deleteCacheAsWell = $input->getOption(self::OPTION_INCLUDING_CACHE);
5247

5348
if (!$isDryRun && !$isForce) {
5449
if (!$input->isInteractive()) {
55-
$output->writeln('ERROR: neither --dry-run nor --force options were supplied, and we are not running interactively.');
56-
57-
return 1; // error.
50+
$output->writeln(
51+
sprintf(
52+
'ERROR: neither --%s nor --%s options were supplied, and we are not running interactively.', self::OPTION_DRY_RUN,
53+
self::OPTION_FORCE
54+
)
55+
);
56+
57+
return Cli::RETURN_FAILURE;
5858
}
5959

6060
$output->writeln(
61-
'<comment>WARNING: this is not a dry run. If you want to do a dry-run, add --dry-run.</comment>'
61+
sprintf('<comment>WARNING: this is not a dry run. If you want to do a dry-run, add --%s.</comment>', self::OPTION_DRY_RUN)
6262
);
63+
6364
$question = new ConfirmationQuestion('<comment>Are you sure you want to continue? [No]</comment>', false);
6465

6566
if (!$this->getHelper('question')->ask($input, $output, $question)) {
66-
return 1; // error.
67+
return Cli::RETURN_FAILURE;
6768
}
6869
}
6970

70-
$imageDir = $this->getImageDir();
71-
$connection = $this->resourceConnection->getConnection('core_read');
71+
$imageDir = $this->getImageDir();
72+
$connection = $this->resourceConnection->getConnection('core_read');
7273
$mediaGalleryTable = $this->resourceConnection->getTableName('catalog_product_entity_media_gallery');
7374

7475
$directoryIterator = new RecursiveDirectoryIterator($imageDir);
7576

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

7879
foreach (new RecursiveIteratorIterator($directoryIterator) as $file) {
79-
// Cached and placeholder path guard
80-
if ($this->isInCachePath($file) || $this->isInPlaceholderPath($file)) {
80+
// Directory guard
81+
if (is_dir($file)) {
8182
continue;
8283
}
8384

84-
// Directory guard
85-
if (is_dir($file)) {
85+
// Cached guard
86+
if ($this->isInCachePath($file) && !$deleteCacheAsWell) {
8687
continue;
8788
}
8889

89-
// Filepath guard
9090
$filePath = str_replace($imageDir, "", $file);
91+
// Filepath guard
9192
if (empty($filePath)) {
9293
continue;
9394
}
9495

95-
if (in_array($filePath, $imagesToKeep)) {
96+
$filePathWithoutCacheDir = preg_replace('#/cache_*/[a-z0-9]+(/[a-z0-9]/[a-z0-9]/.+?)#i', '$1', $filePath);
97+
if (in_array($filePathWithoutCacheDir, $imagesToKeep, true)) {
98+
continue;
99+
}
100+
101+
// Placeholder guard
102+
if ($this->isInPlaceholderPath($file)) {
103+
continue;
104+
}
105+
106+
if (in_array($filePath, $imagesToKeep, true)) {
96107
continue;
97108
}
98109

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

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

112-
return 0; // success.
113-
}
114-
115-
private function printResult(OutputInterface $output, $isDryRun, int $countFiles, int $filesize): void
116-
{
117-
$actionName = 'Deleted';
118-
119-
if ($isDryRun) {
120-
$actionName = 'Would delete';
121-
}
122-
123-
$fileSizeInMB = number_format($filesize / 1024 / 1024, '2');
124-
125-
$output->writeln("<info>{$actionName} {$countFiles} unused images. {$fileSizeInMB} MB</info>");
123+
return Cli::RETURN_SUCCESS;
126124
}
127125

128126
private function getImageDir(): string
@@ -141,4 +139,42 @@ private function isInPlaceholderPath(?string $file): bool
141139
{
142140
return strpos($file, '/placeholder') !== false;
143141
}
142+
143+
private function printResult(OutputInterface $output, $isDryRun, int $countFiles, int $filesize): void
144+
{
145+
$actionName = 'Deleted';
146+
147+
if ($isDryRun) {
148+
$actionName = 'Would delete';
149+
}
150+
151+
$fileSizeInMB = number_format($filesize / 1024 / 1024, '2');
152+
153+
$output->writeln("<info>{$actionName} {$countFiles} unused images. {$fileSizeInMB} MB</info>");
154+
}
155+
156+
protected function configure(): void
157+
{
158+
$this->setName(self::COMMAND_NAME_EAV_MEDIA_REMOVE_UNUSED);
159+
$this->setDescription('Remove unused product images');
160+
161+
$this->addOption(
162+
self::OPTION_INCLUDING_CACHE,
163+
'c',
164+
null,
165+
'Also clear the ./cache/* entries for the corresponding images'
166+
);
167+
$this->addOption(
168+
self::OPTION_DRY_RUN,
169+
'd',
170+
null,
171+
'Only process files and output what would be deleted, but don\'t delete anything'
172+
);
173+
$this->addOption(
174+
self::OPTION_FORCE,
175+
'f',
176+
null,
177+
'Prevent confirmation question and force execution. Option is required for non-interactive execution.'
178+
);
179+
}
144180
}

0 commit comments

Comments
 (0)