Skip to content

Commit 048a2ee

Browse files
author
Timon de Groot
committed
Improve command catalog:images:resize
- Only resize images that are actually in use. - Improve code on several places
1 parent 7120c6e commit 048a2ee

File tree

4 files changed

+193
-18
lines changed

4 files changed

+193
-18
lines changed

app/code/Magento/Catalog/Model/ResourceModel/Product/Image.php

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function __construct(
5454
}
5555

5656
/**
57-
* Returns product images
57+
* Get all product images.
5858
*
5959
* @return \Generator
6060
*/
@@ -75,7 +75,28 @@ public function getAllProductImages(): \Generator
7575
}
7676

7777
/**
78-
* Get the number of unique pictures of products
78+
* Get used product images.
79+
*
80+
* @return \Generator
81+
*/
82+
public function getUsedProductImages(): \Generator
83+
{
84+
$batchSelectIterator = $this->batchQueryGenerator->generate(
85+
'value_id',
86+
$this->getUsedImagesSelect(),
87+
$this->batchSize,
88+
\Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR
89+
);
90+
91+
foreach ($batchSelectIterator as $select) {
92+
foreach ($this->connection->fetchAll($select) as $key => $value) {
93+
yield $key => $value;
94+
}
95+
}
96+
}
97+
98+
/**
99+
* Get the number of unique images of products.
79100
*
80101
* @return int
81102
*/
@@ -92,7 +113,24 @@ public function getCountAllProductImages(): int
92113
}
93114

94115
/**
95-
* Return Select to fetch all products images
116+
* Get the number of unique and used images of products.
117+
*
118+
* @return int
119+
*/
120+
public function getCountUsedProductImages(): int
121+
{
122+
$select = $this->getUsedImagesSelect()
123+
->reset('columns')
124+
->reset('distinct')
125+
->columns(
126+
new \Zend_Db_Expr('count(distinct value)')
127+
);
128+
129+
return (int) $this->connection->fetchOne($select);
130+
}
131+
132+
/**
133+
* Return select to fetch all products images.
96134
*
97135
* @return Select
98136
*/
@@ -106,4 +144,23 @@ private function getVisibleImagesSelect(): Select
106144
'disabled = 0'
107145
);
108146
}
147+
148+
/**
149+
* Return select to fetch all used product images.
150+
*
151+
* @return Select
152+
*/
153+
private function getUsedImagesSelect(): Select
154+
{
155+
return $this->connection->select()->distinct()
156+
->from(
157+
['images' => $this->resourceConnection->getTableName(Gallery::GALLERY_TABLE)],
158+
'value as filepath'
159+
)->joinInner(
160+
['image_value' => $this->resourceConnection->getTableName(Gallery::GALLERY_VALUE_TABLE)],
161+
'images.value_id = image_value.value_id'
162+
)->where(
163+
'images.disabled = 0 AND image_value.disabled = 0'
164+
);
165+
}
109166
}

app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/ImageTest.php

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,37 @@ protected function getVisibleImagesSelectMock(): MockObject
7676
return $selectMock;
7777
}
7878

79+
/**
80+
* @return MockObject
81+
*/
82+
protected function getUsedImagesSelectMock(): MockObject
83+
{
84+
$selectMock = $this->getMockBuilder(Select::class)
85+
->disableOriginalConstructor()
86+
->getMock();
87+
$selectMock->expects($this->once())
88+
->method('distinct')
89+
->willReturnSelf();
90+
$selectMock->expects($this->once())
91+
->method('from')
92+
->with(
93+
['images' => Gallery::GALLERY_TABLE],
94+
'value as filepath'
95+
)->willReturnSelf();
96+
$selectMock->expects($this->once())
97+
->method('joinInner')
98+
->with(
99+
['image_value' => Gallery::GALLERY_VALUE_TABLE],
100+
'images.value_id = image_value.value_id'
101+
)->willReturnSelf();
102+
$selectMock->expects($this->once())
103+
->method('where')
104+
->with('images.disabled = 0 AND image_value.disabled = 0')
105+
->willReturnSelf();
106+
107+
return $selectMock;
108+
}
109+
79110
/**
80111
* @param int $imagesCount
81112
* @dataProvider dataProvider
@@ -116,15 +147,53 @@ public function testGetCountAllProductImages(int $imagesCount): void
116147
);
117148
}
118149

150+
/**
151+
* @param int $imagesCount
152+
* @dataProvider dataProvider
153+
*/
154+
public function testGetCountUsedProductImages(int $imagesCount): void
155+
{
156+
$selectMock = $this->getUsedImagesSelectMock();
157+
$selectMock->expects($this->exactly(2))
158+
->method('reset')
159+
->withConsecutive(
160+
['columns'],
161+
['distinct']
162+
)->willReturnSelf();
163+
$selectMock->expects($this->once())
164+
->method('columns')
165+
->with(new \Zend_Db_Expr('count(distinct value)'))
166+
->willReturnSelf();
167+
168+
$this->connectionMock->expects($this->once())
169+
->method('select')
170+
->willReturn($selectMock);
171+
$this->connectionMock->expects($this->once())
172+
->method('fetchOne')
173+
->with($selectMock)
174+
->willReturn($imagesCount);
175+
176+
$imageModel = $this->objectManager->getObject(
177+
Image::class,
178+
[
179+
'generator' => $this->generatorMock,
180+
'resourceConnection' => $this->resourceMock
181+
]
182+
);
183+
184+
$this->assertSame(
185+
$imagesCount,
186+
$imageModel->getCountUsedProductImages()
187+
);
188+
}
189+
119190
/**
120191
* @param int $imagesCount
121192
* @param int $batchSize
122193
* @dataProvider dataProvider
123194
*/
124-
public function testGetAllProductImages(
125-
int $imagesCount,
126-
int $batchSize
127-
): void {
195+
public function testGetAllProductImages(int $imagesCount, int $batchSize): void
196+
{
128197
$this->connectionMock->expects($this->once())
129198
->method('select')
130199
->willReturn($this->getVisibleImagesSelectMock());
@@ -165,6 +234,54 @@ public function testGetAllProductImages(
165234
$this->assertCount($imagesCount, $imageModel->getAllProductImages());
166235
}
167236

237+
/**
238+
* @param int $imagesCount
239+
* @param int $batchSize
240+
* @dataProvider dataProvider
241+
*/
242+
public function testGetUsedProductImages(int $imagesCount, int $batchSize): void
243+
{
244+
$this->connectionMock->expects($this->once())
245+
->method('select')
246+
->willReturn($this->getUsedImagesSelectMock());
247+
248+
$batchCount = (int)ceil($imagesCount / $batchSize);
249+
$fetchResultsCallback = $this->getFetchResultCallbackForBatches($imagesCount, $batchSize);
250+
$this->connectionMock->expects($this->exactly($batchCount))
251+
->method('fetchAll')
252+
->will($this->returnCallback($fetchResultsCallback));
253+
254+
/** @var Select | MockObject $selectMock */
255+
$selectMock = $this->getMockBuilder(Select::class)
256+
->disableOriginalConstructor()
257+
->getMock();
258+
259+
$this->generatorMock->expects($this->once())
260+
->method('generate')
261+
->with(
262+
'value_id',
263+
$selectMock,
264+
$batchSize,
265+
BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR
266+
)->will(
267+
$this->returnCallback(
268+
$this->getBatchIteratorCallback($selectMock, $batchCount)
269+
)
270+
);
271+
272+
/** @var Image $imageModel */
273+
$imageModel = $this->objectManager->getObject(
274+
Image::class,
275+
[
276+
'generator' => $this->generatorMock,
277+
'resourceConnection' => $this->resourceMock,
278+
'batchSize' => $batchSize
279+
]
280+
);
281+
282+
$this->assertCount($imagesCount, $imageModel->getUsedProductImages());
283+
}
284+
168285
/**
169286
* @param int $imagesCount
170287
* @param int $batchSize

app/code/Magento/MediaStorage/Console/Command/ImagesResizeCommand.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
use Magento\Framework\App\Area;
1111
use Magento\Framework\App\State;
1212
use Magento\MediaStorage\Service\ImageResize;
13+
use Symfony\Component\Console\Helper\ProgressBar;
14+
use Symfony\Component\Console\Helper\ProgressBarFactory;
1315
use Symfony\Component\Console\Input\InputInterface;
1416
use Symfony\Component\Console\Output\OutputInterface;
15-
use Symfony\Component\Console\Helper\ProgressBar;
16-
use Magento\Framework\ObjectManagerInterface;
1717

1818
class ImagesResizeCommand extends \Symfony\Component\Console\Command\Command
1919
{
@@ -28,24 +28,24 @@ class ImagesResizeCommand extends \Symfony\Component\Console\Command\Command
2828
private $appState;
2929

3030
/**
31-
* @var ObjectManagerInterface
31+
* @var ProgressBarFactory
3232
*/
33-
private $objectManager;
33+
private $progressBarFactory;
3434

3535
/**
3636
* @param State $appState
3737
* @param ImageResize $resize
38-
* @param ObjectManagerInterface $objectManager
38+
* @param ProgressBarFactory $progressBarFactory
3939
*/
4040
public function __construct(
4141
State $appState,
4242
ImageResize $resize,
43-
ObjectManagerInterface $objectManager
43+
ProgressBarFactory $progressBarFactory
4444
) {
4545
parent::__construct();
4646
$this->resize = $resize;
4747
$this->appState = $appState;
48-
$this->objectManager = $objectManager;
48+
$this->progressBarFactory = $progressBarFactory;
4949
}
5050

5151
/**
@@ -67,7 +67,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
6767
$generator = $this->resize->resizeFromThemes();
6868

6969
/** @var ProgressBar $progress */
70-
$progress = $this->objectManager->create(ProgressBar::class, [
70+
$progress = $this->progressBarFactory->create([
7171
'output' => $output,
7272
'max' => $generator->current()
7373
]);
@@ -79,9 +79,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
7979
$progress->setOverwrite(false);
8080
}
8181

82-
for (; $generator->valid(); $generator->next()) {
82+
while ($generator->valid()) {
8383
$progress->setMessage($generator->key());
8484
$progress->advance();
85+
$generator->next();
8586
}
8687
} catch (\Exception $e) {
8788
$output->writeln("<error>{$e->getMessage()}</error>");

app/code/Magento/MediaStorage/Service/ImageResize.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ public function resizeFromImageName(string $originalImageName)
152152
*/
153153
public function resizeFromThemes(array $themes = null): \Generator
154154
{
155-
$count = $this->productImage->getCountAllProductImages();
155+
$count = $this->productImage->getCountUsedProductImages();
156156
if (!$count) {
157157
throw new NotFoundException(__('Cannot resize images - product images not found'));
158158
}
159159

160-
$productImages = $this->productImage->getAllProductImages();
160+
$productImages = $this->productImage->getUsedProductImages();
161161
$viewImages = $this->getViewImages($themes ?? $this->getThemesInUse());
162162

163163
foreach ($productImages as $image) {

0 commit comments

Comments
 (0)