From 34ad5a06f3ccdbe8833ff0a2d76efd0860c72771 Mon Sep 17 00:00:00 2001
From: Matt Glaman <nmd.matt@gmail.com>
Date: Thu, 25 Feb 2016 15:48:07 -0600
Subject: [PATCH] Issue #2675836: Variation is not properly factoring attribute
 dependencies when selecting from user input

---
 modules/product/src/Form/AddToCartForm.php | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/modules/product/src/Form/AddToCartForm.php b/modules/product/src/Form/AddToCartForm.php
index 365c8e4..1fc89f4 100644
--- a/modules/product/src/Form/AddToCartForm.php
+++ b/modules/product/src/Form/AddToCartForm.php
@@ -241,7 +241,7 @@ public function ajaxRefresh(array $form, FormStateInterface $form_state) {
   }
 
   /**
-   * Selects a product variation based on user input containing attribute values.
+   * Selects a product variation based on user input and attribute values.
    *
    * If there's no user input (form viewed for the first time), the default
    * variation is returned.
@@ -258,22 +258,26 @@ protected function selectVariationFromUserInput(array $variations, FormStateInte
     $user_input = $form_state->getUserInput();
     $current_variation = reset($variations);
     if (!empty($user_input)) {
+      // We cascade through the attributes and find the variations through
+      // attribute dependency. That means the last possible attribute helps
+      // define the actual variation, so we do not use it as a qualifying
+      // attribute, because it defines our final available variations.
       $attributes = $user_input['attributes'];
-      foreach ($variations as $variation) {
-        $match = TRUE;
-        foreach ($attributes as $field_name => $value) {
+      array_pop($attributes);
+
+      // Loop the through attributes to find qualifying variations.
+      foreach ($attributes as $field_name => $value) {
+        foreach ($variations as $key => &$variation) {
+          // Check if this variation is invalid or not.
           if ($variation->get($field_name)->target_id != $value) {
-            $match = FALSE;
+            // Remove it so it is not considered on next attribute.
+            unset($variations[$key]);
           }
         }
-
-        if ($match) {
-          $current_variation = $variation;
-          break;
-        }
       }
+      // Use the first remaining variation as our selected option.
+      $current_variation = reset($variations);
     }
-
     return $current_variation;
   }
 
