Skip to content

Commit bd1490b

Browse files
author
Oleksandr Iegorov
committed
Merge branch 'MAGETWO-72861' of github.com:magento-tango/magento2ce into 2.3-PR-4
2 parents 5a7c3bd + 85e0b04 commit bd1490b

File tree

13 files changed

+441
-65
lines changed

13 files changed

+441
-65
lines changed

app/code/Magento/Catalog/Model/Category.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
* @method Category setUrlPath(string $urlPath)
3333
* @method Category getSkipDeleteChildren()
3434
* @method Category setSkipDeleteChildren(boolean $value)
35+
* @method Category setChangedProductIds(array $categoryIds) Set products ids that inserted or deleted for category
36+
* @method array getChangedProductIds() Get products ids that inserted or deleted for category
3537
*
3638
* @SuppressWarnings(PHPMD.LongVariable)
3739
* @SuppressWarnings(PHPMD.ExcessivePublicCount)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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\Model\Category\Product;
9+
10+
/**
11+
* Resolver to get product positions by ids assigned to specific category
12+
*/
13+
class PositionResolver extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
14+
{
15+
/**
16+
* Initialize resource model
17+
*
18+
* @return void
19+
*/
20+
protected function _construct()
21+
{
22+
$this->_init('catalog_product_entity', 'entity_id');
23+
}
24+
25+
/**
26+
* Get category product positions
27+
*
28+
* @param int $categoryId
29+
* @return array
30+
*/
31+
public function getPositions(int $categoryId): array
32+
{
33+
$connection = $this->getConnection();
34+
35+
$select = $connection->select()->from(
36+
['cpe' => $this->getTable('catalog_product_entity')],
37+
'entity_id'
38+
)->joinLeft(
39+
['ccp' => $this->getTable('catalog_category_product')],
40+
'ccp.product_id=cpe.entity_id'
41+
)->where(
42+
'ccp.category_id = ?',
43+
$categoryId
44+
)->order(
45+
'ccp.position ' . \Magento\Framework\DB\Select::SQL_ASC
46+
);
47+
48+
return array_flip($connection->fetchCol($select));
49+
}
50+
}

app/code/Magento/Catalog/Model/ResourceModel/Category.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,18 @@ protected function _saveCategoryProducts($category)
410410
* Update product positions in category
411411
*/
412412
if (!empty($update)) {
413+
$newPositions = [];
413414
foreach ($update as $productId => $position) {
414-
$where = ['category_id = ?' => (int)$id, 'product_id = ?' => (int)$productId];
415-
$bind = ['position' => (int)$position];
415+
$delta = $position - $oldProducts[$productId];
416+
if (!isset($newPositions[$delta])) {
417+
$newPositions[$delta] = [];
418+
}
419+
$newPositions[$delta][] = $productId;
420+
}
421+
422+
foreach ($newPositions as $delta => $productIds) {
423+
$bind = ['position' => new \Zend_Db_Expr("position + ({$delta})")];
424+
$where = ['category_id = ?' => (int)$id, 'product_id IN (?)' => $productIds];
416425
$connection->update($this->getCategoryProductTable(), $bind, $where);
417426
}
418427
}
@@ -423,6 +432,8 @@ protected function _saveCategoryProducts($category)
423432
'catalog_category_change_products',
424433
['category' => $category, 'product_ids' => $productIds]
425434
);
435+
436+
$category->setChangedProductIds($productIds);
426437
}
427438

428439
if (!empty($insert) || !empty($update) || !empty($delete)) {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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\Category\Product;
9+
10+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
11+
use Magento\Catalog\Model\Category\Product\PositionResolver;
12+
use Magento\Framework\Model\ResourceModel\Db\Context;
13+
use Magento\Framework\App\ResourceConnection;
14+
use Magento\Framework\DB\Adapter\AdapterInterface;
15+
use Magento\Framework\DB\Select;
16+
17+
class PositionResolverTest extends \PHPUnit\Framework\TestCase
18+
{
19+
/**
20+
* @var Context|\PHPUnit_Framework_MockObject_MockObject
21+
*/
22+
private $context;
23+
24+
/**
25+
* @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
26+
*/
27+
private $resources;
28+
29+
/**
30+
* @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
31+
*/
32+
private $connection;
33+
34+
/**
35+
* @var Select|\PHPUnit_Framework_MockObject_MockObject
36+
*/
37+
private $select;
38+
39+
/**
40+
* @var PositionResolver
41+
*/
42+
private $model;
43+
44+
/**
45+
* @var array
46+
*/
47+
private $positions = [
48+
'3' => 100,
49+
'2' => 101,
50+
'1' => 102
51+
];
52+
53+
/**
54+
* @var array
55+
*/
56+
private $flippedPositions = [
57+
'100' => 3,
58+
'101' => 2,
59+
'102' => 1
60+
];
61+
62+
/**
63+
* @var int
64+
*/
65+
private $categoryId = 1;
66+
67+
protected function setUp()
68+
{
69+
$this->context = $this->getMockBuilder(Context::class)
70+
->disableOriginalConstructor()
71+
->getMock();
72+
73+
$this->resources = $this->getMockBuilder(ResourceConnection::class)
74+
->disableOriginalConstructor()
75+
->getMock();
76+
77+
$this->connection = $this->getMockBuilder(AdapterInterface::class)
78+
->disableOriginalConstructor()
79+
->getMockForAbstractClass();
80+
81+
$this->select = $this->getMockBuilder(Select::class)
82+
->disableOriginalConstructor()
83+
->getMock();
84+
85+
$this->model = (new ObjectManager($this))->getObject(
86+
PositionResolver::class,
87+
[
88+
'context' => $this->context,
89+
null,
90+
'_resources' => $this->resources
91+
]
92+
);
93+
}
94+
95+
public function testGetPositions()
96+
{
97+
$this->resources->expects($this->once())
98+
->method('getConnection')
99+
->willReturn($this->connection);
100+
101+
$this->connection->expects($this->once())
102+
->method('select')
103+
->willReturn($this->select);
104+
$this->select->expects($this->once())
105+
->method('from')
106+
->willReturnSelf();
107+
$this->select->expects($this->once())
108+
->method('where')
109+
->willReturnSelf();
110+
$this->select->expects($this->once())
111+
->method('order')
112+
->willReturnSelf();
113+
$this->select->expects($this->once())
114+
->method('joinLeft')
115+
->willReturnSelf();
116+
$this->connection->expects($this->once())
117+
->method('fetchCol')
118+
->willReturn($this->positions);
119+
120+
$this->assertEquals($this->flippedPositions, $this->model->getPositions($this->categoryId));
121+
}
122+
}

0 commit comments

Comments
 (0)