diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php index bc212adae2c32..5a00bad30875f 100644 --- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php +++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php @@ -47,22 +47,26 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type) $products = $this->providers[$type]->getLinkedProducts($product); $converter = $this->converterPool->getConverter($type); - $output = []; $sorterItems = []; foreach ($products as $item) { - $output[$item->getId()] = $converter->convert($item); + $sorterItems[$item->getId()] = $converter->convert($item); } - foreach ($output as $item) { - $itemPosition = $item['position']; - if (!isset($sorterItems[$itemPosition])) { - $sorterItems[$itemPosition] = $item; - } else { - $newPosition = $itemPosition + 1; - $sorterItems[$newPosition] = $item; - } - } - ksort($sorterItems); + usort($sorterItems, [$this, 'comparePosition']); + return $sorterItems; } + + /** + * Compare item by key 'position'. + * + * @param array $itemA + * @param array $itemB + * @return int Return -1, 0 or 1 when $itemA['position'] is + * respectively less than, equal to, or greater than $itemB['position'] + */ + public function comparePosition(array $itemA, array $itemB): int + { + return (int)$itemA['position'] <=> (int)$itemB['position']; + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php index d8931cbbfcf73..b92af3367297d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CollectionProviderTest.php @@ -57,10 +57,12 @@ public function testGetCollection() $linkedProductOneMock = $this->createMock(Product::class); $linkedProductTwoMock = $this->createMock(Product::class); $linkedProductThreeMock = $this->createMock(Product::class); + $linkedProductFourMock = $this->createMock(Product::class); $linkedProductOneMock->expects($this->once())->method('getId')->willReturn(1); $linkedProductTwoMock->expects($this->once())->method('getId')->willReturn(2); $linkedProductThreeMock->expects($this->once())->method('getId')->willReturn(3); + $linkedProductFourMock->expects($this->once())->method('getId')->willReturn(4); $this->converterPoolMock->expects($this->once()) ->method('getConverter') @@ -71,9 +73,10 @@ public function testGetCollection() [$linkedProductOneMock, ['name' => 'Product One', 'position' => 10]], [$linkedProductTwoMock, ['name' => 'Product Two', 'position' => 2]], [$linkedProductThreeMock, ['name' => 'Product Three', 'position' => 2]], + [$linkedProductFourMock, ['name' => 'Product Four', 'position' => 5]], ]; - $this->converterMock->expects($this->exactly(3))->method('convert')->willReturnMap($map); + $this->converterMock->expects($this->exactly(4))->method('convert')->willReturnMap($map); $this->providerMock->expects($this->once()) ->method('getLinkedProducts') @@ -82,14 +85,16 @@ public function testGetCollection() [ $linkedProductOneMock, $linkedProductTwoMock, - $linkedProductThreeMock + $linkedProductThreeMock, + $linkedProductFourMock, ] ); $expectedResult = [ - 2 => ['name' => 'Product Two', 'position' => 2], - 3 => ['name' => 'Product Three', 'position' => 2], - 10 => ['name' => 'Product One', 'position' => 10], + 0 => ['name' => 'Product Three', 'position' => 2], + 1 => ['name' => 'Product Two', 'position' => 2], + 2 => ['name' => 'Product Four', 'position' => 5], + 3 => ['name' => 'Product One', 'position' => 10], ]; $actualResult = $this->model->getCollection($this->productMock, 'crosssell');