From 9794d38f266db3dc36f640b6a38615253f7eea3c Mon Sep 17 00:00:00 2001
From: Ward Cappelle <ward.cappelle@studioemma.com>
Date: Tue, 2 Jan 2018 23:34:35 +0100
Subject: [PATCH] Sort configurable attribute options by sort_order

When fetching configurable options using the configurable product
option select builder, the sort_order of each option should be taken
into account as well, making sure the desired sorting is passed to the
frontend.

See github issue #7441, internal ticket MAGETWO-61484 and PR#12420 for more on this.
---
 .../Attribute/OptionSelectBuilder.php         |  6 +++
 .../Attribute/OptionSelectBuilderTest.php     | 41 +++++++++++++++++--
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Attribute/OptionSelectBuilder.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Attribute/OptionSelectBuilder.php
index 958d802682d..5d9eed0a188 100644
--- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Attribute/OptionSelectBuilder.php
+++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Attribute/OptionSelectBuilder.php
@@ -91,6 +91,12 @@ class OptionSelectBuilder implements OptionSelectBuilderInterface
                 ]
             ),
             []
+        )->joinInner(
+            ['attribute_option' => $this->attributeResource->getTable('eav_attribute_option')],
+            'attribute_option.option_id = entity_value.value',
+            []
+        )->order(
+            'attribute_option.sort_order ASC'
         )->where(
             'super_attribute.product_id = ?',
             $productId
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Attribute/OptionSelectBuilderTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Attribute/OptionSelectBuilderTest.php
index 235c16c9b55..9802c97372b 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Attribute/OptionSelectBuilderTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Attribute/OptionSelectBuilderTest.php
@@ -66,7 +66,7 @@ class OptionSelectBuilderTest extends \PHPUnit\Framework\TestCase
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
         $this->select = $this->getMockBuilder(Select::class)
-            ->setMethods(['from', 'joinInner', 'joinLeft', 'where', 'columns'])
+            ->setMethods(['from', 'joinInner', 'joinLeft', 'where', 'columns', 'order'])
             ->disableOriginalConstructor()
             ->getMock();
         $this->connectionMock->expects($this->atLeastOnce())
@@ -112,10 +112,28 @@ class OptionSelectBuilderTest extends \PHPUnit\Framework\TestCase
     {
         $this->select->expects($this->exactly(1))->method('from')->willReturnSelf();
         $this->select->expects($this->exactly(1))->method('columns')->willReturnSelf();
-        $this->select->expects($this->exactly(5))->method('joinInner')->willReturnSelf();
+        $this->select->expects($this->exactly(6))->method('joinInner')->willReturnSelf();
         $this->select->expects($this->exactly(3))->method('joinLeft')->willReturnSelf();
+        $this->select->expects($this->exactly(1))->method('order')->willReturnSelf();
         $this->select->expects($this->exactly(2))->method('where')->willReturnSelf();
 
+        $this->attributeResourceMock->expects($this->exactly(9))
+            ->method('getTable')
+            ->will(
+                $this->returnValueMap(
+                    [
+                        ['catalog_product_super_attribute', 'catalog_product_super_attribute value'],
+                        ['catalog_product_entity', 'catalog_product_entity value'],
+                        ['catalog_product_super_link', 'catalog_product_super_link value'],
+                        ['eav_attribute', 'eav_attribute value'],
+                        ['catalog_product_entity', 'catalog_product_entity value'],
+                        ['catalog_product_super_attribute_label', 'catalog_product_super_attribute_label value'],
+                        ['eav_attribute_option', 'eav_attribute_option value'],
+                        ['eav_attribute_option_value', 'eav_attribute_option_value value']
+                    ]
+                )
+            );
+
         $this->abstractAttributeMock->expects($this->atLeastOnce())
             ->method('getAttributeId')
             ->willReturn('getAttributeId value');
@@ -138,10 +156,27 @@ class OptionSelectBuilderTest extends \PHPUnit\Framework\TestCase
     {
         $this->select->expects($this->exactly(1))->method('from')->willReturnSelf();
         $this->select->expects($this->exactly(0))->method('columns')->willReturnSelf();
-        $this->select->expects($this->exactly(5))->method('joinInner')->willReturnSelf();
+        $this->select->expects($this->exactly(6))->method('joinInner')->willReturnSelf();
         $this->select->expects($this->exactly(1))->method('joinLeft')->willReturnSelf();
+        $this->select->expects($this->exactly(1))->method('order')->willReturnSelf();
         $this->select->expects($this->exactly(2))->method('where')->willReturnSelf();
 
+        $this->attributeResourceMock->expects($this->exactly(7))
+            ->method('getTable')
+            ->will(
+                $this->returnValueMap(
+                    [
+                        ['catalog_product_super_attribute', 'catalog_product_super_attribute value'],
+                        ['catalog_product_entity', 'catalog_product_entity value'],
+                        ['catalog_product_super_link', 'catalog_product_super_link value'],
+                        ['eav_attribute', 'eav_attribute value'],
+                        ['catalog_product_entity', 'catalog_product_entity value'],
+                        ['catalog_product_super_attribute_label', 'catalog_product_super_attribute_label value'],
+                        ['eav_attribute_option', 'eav_attribute_option value']
+                    ]
+                )
+            );
+
         $this->abstractAttributeMock->expects($this->atLeastOnce())
             ->method('getAttributeId')
             ->willReturn('getAttributeId value');
-- 
GitLab