11<?php
22/**
3- * Copyright © Magento, Inc. All rights reserved.
4- * See COPYING.txt for license details .
3+ * Copyright 2013 Adobe
4+ * All Rights Reserved .
55 */
66namespace Magento \ConfigurableProduct \Block \Adminhtml \Product \Edit \Tab \Variations \Config ;
77
88use Magento \Catalog \Api \ProductRepositoryInterface ;
99use Magento \Catalog \Model \Locator \LocatorInterface ;
1010use Magento \Catalog \Model \Product ;
11+ use Magento \Eav \Model \Entity \Attribute \AbstractAttribute ;
1112use Magento \Framework \Exception \NoSuchEntityException ;
1213
1314/**
@@ -88,7 +89,7 @@ public function __construct(
8889 LocatorInterface $ locator ,
8990 array $ data = []
9091 ) {
91- parent ::__construct ($ context , $ data );
92+ parent ::__construct ($ context , $ data, $ data [ ' jsonHelper ' ] ?? null , $ data [ ' directoryHelper ' ] ?? null );
9293 $ this ->_configurableType = $ configurableType ;
9394 $ this ->stockRegistry = $ stockRegistry ;
9495 $ this ->variationMatrix = $ variationMatrix ;
@@ -242,6 +243,32 @@ protected function getAssociatedProducts()
242243 return $ productByUsedAttributes ;
243244 }
244245
246+ /**
247+ * Retrieves attributes that are used for configurable product variations
248+ *
249+ * @return array
250+ */
251+ private function getVariantAttributeComposition (): array
252+ {
253+ $ variants = [];
254+ foreach ($ this ->_getAssociatedProducts () as $ product ) {
255+ /* @var $attribute AbstractAttribute */
256+ foreach ($ this ->getUsedAttributes () as $ attribute ) {
257+ $ variants [$ product ->getId ()][$ attribute ->getAttributeCode ()] =
258+ [
259+ 'value_id ' => $ product ->getData ($ attribute ->getAttributeCode ()),
260+ 'label ' => $ this ->extractAttributeValueLabel (
261+ $ attribute ,
262+ $ product ->getData ($ attribute ->getAttributeCode ())
263+ ),
264+ 'attribute ' => $ attribute
265+ ];
266+ }
267+ }
268+
269+ return $ variants ;
270+ }
271+
245272 /**
246273 * Retrieve actual list of associated products (i.e. if product contains variations matrix form data
247274 * - previously saved in database relations are not considered)
@@ -251,7 +278,7 @@ protected function getAssociatedProducts()
251278 protected function _getAssociatedProducts ()
252279 {
253280 $ product = $ this ->getProduct ();
254- $ ids = $ this -> getProduct () ->getAssociatedProductIds ();
281+ $ ids = $ product ->getAssociatedProductIds ();
255282 if ($ ids === null ) {
256283 // form data overrides any relations stored in database
257284 return $ this ->_configurableType ->getUsedProducts ($ product );
@@ -332,6 +359,76 @@ public function getProductAttributes()
332359 return $ this ->productAttributes ;
333360 }
334361
362+ /**
363+ * Prepare attribute details for child product configuration
364+ *
365+ * @param AbstractAttribute $attribute
366+ * @return array
367+ */
368+ private function buildAttributeDetails (AbstractAttribute $ attribute ): array
369+ {
370+ $ configurableAttributes = $ this ->getAttributes ();
371+ $ details = [
372+ 'code ' => $ attribute ->getAttributeCode (),
373+ 'label ' => $ attribute ->getStoreLabel (),
374+ 'id ' => $ attribute ->getAttributeId (),
375+ 'position ' => $ configurableAttributes [$ attribute ->getAttributeId ()]['position ' ],
376+ 'chosen ' => [],
377+ '__disableTmpl ' => true
378+ ];
379+
380+ foreach ($ attribute ->getOptions () as $ option ) {
381+ if ($ option ->getValue ()) {
382+ $ details ['options ' ][] = [
383+ 'attribute_code ' => $ attribute ->getAttributeCode (),
384+ 'attribute_label ' => $ attribute ->getStoreLabel (0 ),
385+ 'id ' => $ option ->getValue (),
386+ 'label ' => $ option ->getLabel (),
387+ 'value ' => $ option ->getValue (),
388+ '__disableTmpl ' => true ,
389+ ];
390+ }
391+ }
392+
393+ return $ details ;
394+ }
395+
396+ /**
397+ * Generate configurable product child option
398+ *
399+ * @param array $attributeDetails
400+ * @return array
401+ */
402+ private function buildChildProductOption (array $ attributeDetails ): array
403+ {
404+ return [
405+ 'attribute_code ' => $ attributeDetails ['attribute ' ]->getAttributeCode (),
406+ 'attribute_label ' => $ attributeDetails ['attribute ' ]->getStoreLabel (0 ),
407+ 'id ' => $ attributeDetails ['value_id ' ],
408+ 'label ' => $ attributeDetails ['label ' ],
409+ 'value ' => $ attributeDetails ['value_id ' ],
410+ '__disableTmpl ' => true ,
411+ ];
412+ }
413+
414+ /**
415+ * Get label for a specific value of an attribute.
416+ *
417+ * @param AbstractAttribute $attribute
418+ * @param mixed $valueId
419+ * @return string
420+ */
421+ private function extractAttributeValueLabel (AbstractAttribute $ attribute , mixed $ valueId ): string
422+ {
423+ foreach ($ attribute ->getOptions () as $ attributeOption ) {
424+ if ($ attributeOption ->getValue () == $ valueId ) {
425+ return $ attributeOption ->getLabel ();
426+ }
427+ }
428+
429+ return '' ;
430+ }
431+
335432 /**
336433 * Prepare product variations.
337434 *
@@ -341,106 +438,57 @@ public function getProductAttributes()
341438 */
342439 protected function prepareVariations ()
343440 {
344- $ variations = $ this ->getVariations ();
345- $ productMatrix = [];
346- $ attributes = [];
347- if ($ variations ) {
348- $ usedProductAttributes = $ this ->getUsedAttributes ();
349- $ productByUsedAttributes = $ this ->getAssociatedProducts ();
350- $ configurableAttributes = $ this ->getAttributes ();
351- foreach ($ variations as $ variation ) {
352- $ attributeValues = [];
353- foreach ($ usedProductAttributes as $ attribute ) {
354- $ attributeValues [$ attribute ->getAttributeCode ()] = $ variation [$ attribute ->getId ()]['value ' ];
355- }
356- $ key = implode ('- ' , $ attributeValues );
357- if (isset ($ productByUsedAttributes [$ key ])) {
358- $ product = $ productByUsedAttributes [$ key ];
359- $ price = $ product ->getPrice ();
360- $ variationOptions = [];
361- foreach ($ usedProductAttributes as $ attribute ) {
362- list ($ attributes , $ variationOptions ) = $ this ->prepareAttributes (
363- $ attributes ,
364- $ attribute ,
365- $ configurableAttributes ,
366- $ variation ,
367- $ variationOptions
368- );
369- }
370-
371- $ productMatrix [] = [
372- 'productId ' => $ product ->getId (),
373- 'images ' => [
374- 'preview ' => $ this ->image ->init ($ product , 'product_thumbnail_image ' )->getUrl ()
375- ],
376- 'sku ' => $ product ->getSku (),
377- 'name ' => $ product ->getName (),
378- 'quantity ' => $ this ->getProductStockQty ($ product ),
379- 'price ' => $ price ,
380- 'options ' => $ variationOptions ,
381- 'weight ' => $ product ->getWeight (),
382- 'status ' => $ product ->getStatus (),
383- '__disableTmpl ' => true ,
384- ];
441+ $ productMatrix = $ attributes = [];
442+ $ variants = $ this ->getVariantAttributeComposition ();
443+ foreach (array_reverse ($ this ->getAssociatedProducts ()) as $ product ) {
444+ $ childProductOptions = [];
445+ foreach ($ variants [$ product ->getId ()] as $ attributeComposition ) {
446+ $ childProductOptions [] = $ this ->buildChildProductOption ($ attributeComposition );
447+
448+ /** @var AbstractAttribute $attribute */
449+ $ attribute = $ attributeComposition ['attribute ' ];
450+ if (!isset ($ attributes [$ attribute ->getAttributeId ()])) {
451+ $ attributes [$ attribute ->getAttributeId ()] = $ this ->buildAttributeDetails ($ attribute );
385452 }
453+ $ variationOption = [
454+ 'attribute_code ' => $ attribute ->getAttributeCode (),
455+ 'attribute_label ' => $ attribute ->getStoreLabel (0 ),
456+ 'id ' => $ attributeComposition ['value_id ' ],
457+ 'label ' => $ attributeComposition ['label ' ],
458+ 'value ' => $ attributeComposition ['value_id ' ],
459+ '__disableTmpl ' => true ,
460+ ];
461+ $ attributes [$ attribute ->getAttributeId ()]['chosen ' ][] = $ variationOption ;
386462 }
463+ $ productMatrix [] = $ this ->buildChildProductDetails ($ product , $ childProductOptions );
387464 }
465+
388466 $ this ->productMatrix = $ productMatrix ;
389467 $ this ->productAttributes = array_values ($ attributes );
390468 }
391469
392470 /**
393- * Prepare attributes.
471+ * Create child product details
394472 *
395- * @param array $attributes
396- * @param object $attribute
397- * @param array $configurableAttributes
398- * @param array $variation
399- * @param array $variationOptions
473+ * @param Product $product
474+ * @param array $childProductOptions
400475 * @return array
401476 */
402- private function prepareAttributes (
403- array $ attributes ,
404- $ attribute ,
405- array $ configurableAttributes ,
406- array $ variation ,
407- array $ variationOptions
408- ): array {
409- if (!isset ($ attributes [$ attribute ->getAttributeId ()])) {
410- $ attributes [$ attribute ->getAttributeId ()] = [
411- 'code ' => $ attribute ->getAttributeCode (),
412- 'label ' => $ attribute ->getStoreLabel (),
413- 'id ' => $ attribute ->getAttributeId (),
414- 'position ' => $ configurableAttributes [$ attribute ->getAttributeId ()]['position ' ],
415- 'chosen ' => [],
416- '__disableTmpl ' => true
417- ];
418- $ options = $ attribute ->usesSource () ? $ attribute ->getSource ()->getAllOptions () : [];
419- foreach ($ options as $ option ) {
420- if (!empty ($ option ['value ' ])) {
421- $ attributes [$ attribute ->getAttributeId ()]['options ' ][] = [
422- 'attribute_code ' => $ attribute ->getAttributeCode (),
423- 'attribute_label ' => $ attribute ->getStoreLabel (0 ),
424- 'id ' => $ option ['value ' ],
425- 'label ' => $ option ['label ' ],
426- 'value ' => $ option ['value ' ],
427- '__disableTmpl ' => true ,
428- ];
429- }
430- }
431- }
432- $ optionId = $ variation [$ attribute ->getId ()]['value ' ];
433- $ variationOption = [
434- 'attribute_code ' => $ attribute ->getAttributeCode (),
435- 'attribute_label ' => $ attribute ->getStoreLabel (0 ),
436- 'id ' => $ optionId ,
437- 'label ' => $ variation [$ attribute ->getId ()]['label ' ],
438- 'value ' => $ optionId ,
477+ private function buildChildProductDetails (Product $ product , array $ childProductOptions ): array
478+ {
479+ return [
480+ 'productId ' => $ product ->getId (),
481+ 'images ' => [
482+ 'preview ' => $ this ->image ->init ($ product , 'product_thumbnail_image ' )->getUrl ()
483+ ],
484+ 'sku ' => $ product ->getSku (),
485+ 'name ' => $ product ->getName (),
486+ 'quantity ' => $ this ->getProductStockQty ($ product ),
487+ 'price ' => $ product ->getPrice (),
488+ 'options ' => $ childProductOptions ,
489+ 'weight ' => $ product ->getWeight (),
490+ 'status ' => $ product ->getStatus (),
439491 '__disableTmpl ' => true ,
440492 ];
441- $ variationOptions [] = $ variationOption ;
442- $ attributes [$ attribute ->getAttributeId ()]['chosen ' ][] = $ variationOption ;
443-
444- return [$ attributes , $ variationOptions ];
445493 }
446494}
0 commit comments