diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php index edd654a739312..a4218e92b3486 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php @@ -278,15 +278,19 @@ public function testInitialize() ->method('getOptionsReadOnly') ->willReturn(false); + $firstExpectedCustomOption = clone $this->customOptionMock; + $firstExpectedCustomOption->setData($optionsData['option2']); + $secondExpectedCustomOption = clone $this->customOptionMock; + $secondExpectedCustomOption->setData($optionsData['option3']); $this->customOptionFactoryMock->expects($this->any()) ->method('create') ->willReturnMap([ [ ['data' => $optionsData['option2']], - (clone $this->customOptionMock)->setData($optionsData['option2']) + $firstExpectedCustomOption ], [ ['data' => $optionsData['option3']], - (clone $this->customOptionMock)->setData($optionsData['option3']) + $secondExpectedCustomOption ] ]); diff --git a/lib/internal/Magento/Framework/Data/Argument/Interpreter/ArrayType.php b/lib/internal/Magento/Framework/Data/Argument/Interpreter/ArrayType.php index 74a6cc7d2cd92..d714caa1724f0 100644 --- a/lib/internal/Magento/Framework/Data/Argument/Interpreter/ArrayType.php +++ b/lib/internal/Magento/Framework/Data/Argument/Interpreter/ArrayType.php @@ -54,25 +54,70 @@ public function evaluate(array $data) */ private function sortItems($items) { - uasort( - $items, - function ($firstItem, $secondItem) { - $firstValue = 0; - $secondValue = 0; - if (isset($firstItem['sortOrder'])) { - $firstValue = intval($firstItem['sortOrder']); + $sortOrderDefined = $this->isSortOrderDefined($items); + if ($sortOrderDefined) { + $indexedItems = []; + foreach ($items as $key => $item) { + $indexedItems[] = ['key' => $key, 'item' => $item]; + } + uksort( + $indexedItems, + function ($firstItemKey, $secondItemKey) use ($indexedItems) { + return $this->compareItems($firstItemKey, $secondItemKey, $indexedItems); } + ); + // Convert array of sorted items back to initial format + $items = []; + foreach ($indexedItems as $indexedItem) { + $items[$indexedItem['key']] = $indexedItem['item']; + } + } + return $items; + } - if (isset($secondItem['sortOrder'])) { - $secondValue = intval($secondItem['sortOrder']); - } + /** + * Compare sortOrder of item + * + * @param mixed $firstItemKey + * @param mixed $secondItemKey + * @param array $indexedItems + * @return int + */ + private function compareItems($firstItemKey, $secondItemKey, $indexedItems) + { + $firstItem = $indexedItems[$firstItemKey]['item']; + $secondItem = $indexedItems[$secondItemKey]['item']; + $firstValue = 0; + $secondValue = 0; + if (isset($firstItem['sortOrder'])) { + $firstValue = intval($firstItem['sortOrder']); + } - if ($firstValue == $secondValue) { - return 0; - } - return $firstValue < $secondValue ? -1 : 1; + if (isset($secondItem['sortOrder'])) { + $secondValue = intval($secondItem['sortOrder']); + } + + if ($firstValue == $secondValue) { + // These keys reflect initial relative position of items. + // Allows stable sort for items with equal 'sortOrder' + return $firstItemKey < $secondItemKey ? -1 : 1; + } + return $firstValue < $secondValue ? -1 : 1; + } + + /** + * Determine if a sort order exists for any of the items. + * + * @param array $items + * @return bool + */ + private function isSortOrderDefined($items) + { + foreach ($items as $itemData) { + if (isset($itemData['sortOrder'])) { + return true; } - ); - return $items; + } + return false; } } diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/ArrayTypeTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/ArrayTypeTest.php index 7d3c21ba271ce..e1bc7528cbe1a 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/ArrayTypeTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/ArrayTypeTest.php @@ -103,6 +103,40 @@ public function evaluateDataProvider() 'key1' => '-value 1-', ], ], + 'pre-sorted array items' => [ + [ + 'item' => [ + 'key1' => ['value' => 'value 1'], + 'key4' => ['value' => 'value 4'], + 'key2' => ['value' => 'value 2', 'sortOrder' => 10], + 'key3' => ['value' => 'value 3'], + ], + ], + [ + 'key1' => '-value 1-', + 'key4' => '-value 4-', + 'key3' => '-value 3-', + 'key2' => '-value 2-', + ], + ], + 'sort order edge case values' => [ + [ + 'item' => [ + 'key1' => ['value' => 'value 1', 'sortOrder' => 101], + 'key4' => ['value' => 'value 4'], + 'key2' => ['value' => 'value 2', 'sortOrder' => -10], + 'key3' => ['value' => 'value 3'], + 'key5' => ['value' => 'value 5', 'sortOrder' => 20], + ], + ], + [ + 'key2' => '-value 2-', + 'key4' => '-value 4-', + 'key3' => '-value 3-', + 'key5' => '-value 5-', + 'key1' => '-value 1-', + ], + ], ]; } }