Skip to content

Commit 91f2943

Browse files
ENGCOM-3292: catalog:images:resize total images count calculates incorrectly #18387: #18807
- Merge Pull Request #18807 from vpodorozh/magento2:2.3-develop-18387-catalog-images-resize - Merged commits: 1. 6a6079d 2. 466daaa 3. e1a1c7b 4. f6b0a2a 5. 9e9715b 6. 546e7ce 7. f38a4fc 8. 12f8396 9. c95ce3c 10. c1aa5bc
2 parents da1a96c + c1aa5bc commit 91f2943

File tree

2 files changed

+250
-1
lines changed
  • app/code/Magento/Catalog

2 files changed

+250
-1
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
use Magento\Framework\DB\Select;
1313
use Magento\Framework\App\ResourceConnection;
1414

15+
/**
16+
* Class for retrieval of all product images
17+
*/
1518
class Image
1619
{
1720
/**
@@ -73,15 +76,24 @@ public function getAllProductImages(): \Generator
7376

7477
/**
7578
* Get the number of unique pictures of products
79+
*
7680
* @return int
7781
*/
7882
public function getCountAllProductImages(): int
7983
{
80-
$select = $this->getVisibleImagesSelect()->reset('columns')->columns('count(*)');
84+
$select = $this->getVisibleImagesSelect()
85+
->reset('columns')
86+
->reset('distinct')
87+
->columns(
88+
new \Zend_Db_Expr('count(distinct value)')
89+
);
90+
8191
return (int) $this->connection->fetchOne($select);
8292
}
8393

8494
/**
95+
* Return Select to fetch all products images
96+
*
8597
* @return Select
8698
*/
8799
private function getVisibleImagesSelect(): Select
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product;
9+
10+
use Magento\Catalog\Model\ResourceModel\Product\Image;
11+
use Magento\Framework\DB\Adapter\AdapterInterface;
12+
use Magento\Framework\DB\Query\Generator;
13+
use Magento\Framework\DB\Select;
14+
use Magento\Framework\App\ResourceConnection;
15+
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
16+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
17+
use Magento\Framework\DB\Query\BatchIteratorInterface;
18+
19+
class ImageTest extends \PHPUnit\Framework\TestCase
20+
{
21+
/**
22+
* @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
23+
*/
24+
protected $objectManager;
25+
26+
/**
27+
* @var AdapterInterface | MockObject
28+
*/
29+
protected $connectionMock;
30+
31+
/**
32+
* @var Generator | MockObject
33+
*/
34+
protected $generatorMock;
35+
36+
/**
37+
* @var ResourceConnection | MockObject
38+
*/
39+
protected $resourceMock;
40+
41+
protected function setUp(): void
42+
{
43+
$this->objectManager =
44+
new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
45+
$this->connectionMock = $this->createMock(AdapterInterface::class);
46+
$this->resourceMock = $this->createMock(ResourceConnection::class);
47+
$this->resourceMock->method('getConnection')
48+
->willReturn($this->connectionMock);
49+
$this->resourceMock->method('getTableName')
50+
->willReturnArgument(0);
51+
$this->generatorMock = $this->createMock(Generator::class);
52+
}
53+
54+
/**
55+
* @return MockObject
56+
*/
57+
protected function getVisibleImagesSelectMock(): MockObject
58+
{
59+
$selectMock = $this->getMockBuilder(Select::class)
60+
->disableOriginalConstructor()
61+
->getMock();
62+
$selectMock->expects($this->once())
63+
->method('distinct')
64+
->willReturnSelf();
65+
$selectMock->expects($this->once())
66+
->method('from')
67+
->with(
68+
['images' => Gallery::GALLERY_TABLE],
69+
'value as filepath'
70+
)->willReturnSelf();
71+
$selectMock->expects($this->once())
72+
->method('where')
73+
->with('disabled = 0')
74+
->willReturnSelf();
75+
76+
return $selectMock;
77+
}
78+
79+
/**
80+
* @param int $imagesCount
81+
* @dataProvider dataProvider
82+
*/
83+
public function testGetCountAllProductImages(int $imagesCount): void
84+
{
85+
$selectMock = $this->getVisibleImagesSelectMock();
86+
$selectMock->expects($this->exactly(2))
87+
->method('reset')
88+
->withConsecutive(
89+
['columns'],
90+
['distinct']
91+
)->willReturnSelf();
92+
$selectMock->expects($this->once())
93+
->method('columns')
94+
->with(new \Zend_Db_Expr('count(distinct value)'))
95+
->willReturnSelf();
96+
97+
$this->connectionMock->expects($this->once())
98+
->method('select')
99+
->willReturn($selectMock);
100+
$this->connectionMock->expects($this->once())
101+
->method('fetchOne')
102+
->with($selectMock)
103+
->willReturn($imagesCount);
104+
105+
$imageModel = $this->objectManager->getObject(
106+
Image::class,
107+
[
108+
'generator' => $this->generatorMock,
109+
'resourceConnection' => $this->resourceMock
110+
]
111+
);
112+
113+
$this->assertSame(
114+
$imagesCount,
115+
$imageModel->getCountAllProductImages()
116+
);
117+
}
118+
119+
/**
120+
* @param int $imagesCount
121+
* @param int $batchSize
122+
* @dataProvider dataProvider
123+
*/
124+
public function testGetAllProductImages(
125+
int $imagesCount,
126+
int $batchSize
127+
): void {
128+
$this->connectionMock->expects($this->once())
129+
->method('select')
130+
->willReturn($this->getVisibleImagesSelectMock());
131+
132+
$batchCount = (int)ceil($imagesCount / $batchSize);
133+
$fetchResultsCallback = $this->getFetchResultCallbackForBatches($imagesCount, $batchSize);
134+
$this->connectionMock->expects($this->exactly($batchCount))
135+
->method('fetchAll')
136+
->will($this->returnCallback($fetchResultsCallback));
137+
138+
/** @var Select | MockObject $selectMock */
139+
$selectMock = $this->getMockBuilder(Select::class)
140+
->disableOriginalConstructor()
141+
->getMock();
142+
143+
$this->generatorMock->expects($this->once())
144+
->method('generate')
145+
->with(
146+
'value_id',
147+
$selectMock,
148+
$batchSize,
149+
BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR
150+
)->will(
151+
$this->returnCallback(
152+
$this->getBatchIteratorCallback($selectMock, $batchCount)
153+
)
154+
);
155+
156+
$imageModel = $this->objectManager->getObject(
157+
Image::class,
158+
[
159+
'generator' => $this->generatorMock,
160+
'resourceConnection' => $this->resourceMock,
161+
'batchSize' => $batchSize
162+
]
163+
);
164+
165+
$this->assertCount($imagesCount, $imageModel->getAllProductImages());
166+
}
167+
168+
/**
169+
* @param int $imagesCount
170+
* @param int $batchSize
171+
* @return \Closure
172+
*/
173+
protected function getFetchResultCallbackForBatches(
174+
int $imagesCount,
175+
int $batchSize
176+
): \Closure {
177+
$fetchResultsCallback = function () use (&$imagesCount, $batchSize) {
178+
$batchSize =
179+
($imagesCount >= $batchSize) ? $batchSize : $imagesCount;
180+
$imagesCount -= $batchSize;
181+
182+
$getFetchResults = function ($batchSize): array {
183+
$result = [];
184+
$count = $batchSize;
185+
while ($count) {
186+
$count--;
187+
$result[$count] = $count;
188+
}
189+
190+
return $result;
191+
};
192+
193+
return $getFetchResults($batchSize);
194+
};
195+
196+
return $fetchResultsCallback;
197+
}
198+
199+
/**
200+
* @param Select | MockObject $selectMock
201+
* @param int $batchCount
202+
* @return \Closure
203+
*/
204+
protected function getBatchIteratorCallback(
205+
MockObject $selectMock,
206+
int $batchCount
207+
): \Closure {
208+
$iteratorCallback = function () use ($batchCount, $selectMock): array {
209+
$result = [];
210+
$count = $batchCount;
211+
while ($count) {
212+
$count--;
213+
$result[$count] = $selectMock;
214+
}
215+
216+
return $result;
217+
};
218+
219+
return $iteratorCallback;
220+
}
221+
222+
/**
223+
* Data Provider
224+
* @return array
225+
*/
226+
public function dataProvider(): array
227+
{
228+
return [
229+
[300, 300],
230+
[300, 100],
231+
[139, 100],
232+
[67, 10],
233+
[154, 47],
234+
[0, 100]
235+
];
236+
}
237+
}

0 commit comments

Comments
 (0)