|
8 | 8 | use Magento\Catalog\Api\ProductRepositoryInterface;
|
9 | 9 | use Magento\Catalog\Model\Locator\LocatorInterface;
|
10 | 10 | use Magento\Catalog\Model\Product;
|
| 11 | +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; |
11 | 12 | use Magento\Framework\Exception\NoSuchEntityException;
|
12 | 13 |
|
13 | 14 | /**
|
@@ -242,6 +243,28 @@ protected function getAssociatedProducts()
|
242 | 243 | return $productByUsedAttributes;
|
243 | 244 | }
|
244 | 245 |
|
| 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 | + 'attribute' => $attribute |
| 261 | + ]; |
| 262 | + } |
| 263 | + } |
| 264 | + |
| 265 | + return $variants; |
| 266 | + } |
| 267 | + |
245 | 268 | /**
|
246 | 269 | * Retrieve actual list of associated products (i.e. if product contains variations matrix form data
|
247 | 270 | * - previously saved in database relations are not considered)
|
@@ -332,6 +355,121 @@ public function getProductAttributes()
|
332 | 355 | return $this->productAttributes;
|
333 | 356 | }
|
334 | 357 |
|
| 358 | + /** |
| 359 | + * Get configurable product existing setup |
| 360 | + * |
| 361 | + * @return array |
| 362 | + */ |
| 363 | + public function getExistingVariantConfiguration(): array |
| 364 | + { |
| 365 | + $productMatrix = $attributes = []; |
| 366 | + $variants = $this->getVariantAttributeComposition(); |
| 367 | + foreach ($this->getAssociatedProducts() as $product) { |
| 368 | + $childProductOptions = []; |
| 369 | + foreach ($variants[$product->getId()] as $attributeComposition) { |
| 370 | + $childProductOptions[] = $this->buildChildProductOption($attributeComposition); |
| 371 | + |
| 372 | + /** @var AbstractAttribute $attribute */ |
| 373 | + $attribute = $attributeComposition['attribute']; |
| 374 | + if (!isset($attributes[$attribute->getAttributeId()])) { |
| 375 | + $attributes[$attribute->getAttributeId()] = $this->buildAttributeDetails($attribute); |
| 376 | + } |
| 377 | + $variationOption = [ |
| 378 | + 'attribute_code' => $attribute->getAttributeCode(), |
| 379 | + 'attribute_label' => $attribute->getStoreLabel(0), |
| 380 | + 'id' => $attributeComposition['value_id'], |
| 381 | + 'label' => $this->extractAttributeValueLabel( |
| 382 | + $attribute, |
| 383 | + $attributeComposition['value_id'] |
| 384 | + ), |
| 385 | + 'value' => $attributeComposition['value_id'], |
| 386 | + '__disableTmpl' => true, |
| 387 | + ]; |
| 388 | + $attributes[$attribute->getAttributeId()]['chosen'][] = $variationOption; |
| 389 | + } |
| 390 | + $productMatrix[] = $this->buildChildProductDetails($product, $childProductOptions); |
| 391 | + } |
| 392 | + return [ |
| 393 | + 'product_matrix' => $productMatrix, |
| 394 | + 'attributes' => array_values($attributes) |
| 395 | + ]; |
| 396 | + } |
| 397 | + |
| 398 | + /** |
| 399 | + * Prepare attribute details for child product configuration |
| 400 | + * |
| 401 | + * @param AbstractAttribute $attribute |
| 402 | + * @return array |
| 403 | + */ |
| 404 | + private function buildAttributeDetails(AbstractAttribute $attribute): array |
| 405 | + { |
| 406 | + $configurableAttributes = $this->getAttributes(); |
| 407 | + $details = [ |
| 408 | + 'code' => $attribute->getAttributeCode(), |
| 409 | + 'label' => $attribute->getStoreLabel(), |
| 410 | + 'id' => $attribute->getAttributeId(), |
| 411 | + 'position' => $configurableAttributes[$attribute->getAttributeId()]['position'], |
| 412 | + 'chosen' => [], |
| 413 | + '__disableTmpl' => true |
| 414 | + ]; |
| 415 | + |
| 416 | + foreach ($attribute->getOptions() as $option) { |
| 417 | + if (!empty($option['value'])) { |
| 418 | + $details['options'][] = [ |
| 419 | + 'attribute_code' => $attribute->getAttributeCode(), |
| 420 | + 'attribute_label' => $attribute->getStoreLabel(0), |
| 421 | + 'id' => $option['value'], |
| 422 | + 'label' => $option['label'], |
| 423 | + 'value' => $option['value'], |
| 424 | + '__disableTmpl' => true, |
| 425 | + ]; |
| 426 | + } |
| 427 | + } |
| 428 | + |
| 429 | + return $details; |
| 430 | + } |
| 431 | + |
| 432 | + /** |
| 433 | + * Generate configurable product child option |
| 434 | + * |
| 435 | + * @param array $attributeDetails |
| 436 | + * @return array |
| 437 | + */ |
| 438 | + private function buildChildProductOption(array $attributeDetails): array |
| 439 | + { |
| 440 | + $label = $this->extractAttributeValueLabel( |
| 441 | + $attributeDetails['attribute'], |
| 442 | + $attributeDetails['value_id'] |
| 443 | + ); |
| 444 | + |
| 445 | + return [ |
| 446 | + 'attribute_code' => $attributeDetails['attribute']->getAttributeCode(), |
| 447 | + 'attribute_label' => $attributeDetails['attribute']->getStoreLabel(0), |
| 448 | + 'id' => $attributeDetails['value_id'], |
| 449 | + 'label' => $label, |
| 450 | + 'value' => $attributeDetails['value_id'], |
| 451 | + '__disableTmpl' => true, |
| 452 | + ]; |
| 453 | + } |
| 454 | + |
| 455 | + /** |
| 456 | + * Get label for a specific value of an attribute. |
| 457 | + * |
| 458 | + * @param $attribute |
| 459 | + * @param int $valueId |
| 460 | + * @return string |
| 461 | + */ |
| 462 | + private function extractAttributeValueLabel($attribute, int $valueId): string |
| 463 | + { |
| 464 | + foreach ($attribute->getOptions() as $attributeOption) { |
| 465 | + if ($attributeOption->getValue() == $valueId) { |
| 466 | + return $attributeOption->getLabel(); |
| 467 | + } |
| 468 | + } |
| 469 | + |
| 470 | + return ''; |
| 471 | + } |
| 472 | + |
335 | 473 | /**
|
336 | 474 | * Prepare product variations.
|
337 | 475 | *
|
@@ -443,4 +581,29 @@ private function prepareAttributes(
|
443 | 581 |
|
444 | 582 | return [$attributes, $variationOptions];
|
445 | 583 | }
|
| 584 | + |
| 585 | + /** |
| 586 | + * Create child product details |
| 587 | + * |
| 588 | + * @param Product $product |
| 589 | + * @param array $childProductOptions |
| 590 | + * @return array |
| 591 | + */ |
| 592 | + private function buildChildProductDetails(Product $product, array $childProductOptions): array |
| 593 | + { |
| 594 | + return [ |
| 595 | + 'productId' => $product->getId(), |
| 596 | + 'images' => [ |
| 597 | + 'preview' => $this->image->init($product, 'product_thumbnail_image')->getUrl() |
| 598 | + ], |
| 599 | + 'sku' => $product->getSku(), |
| 600 | + 'name' => $product->getName(), |
| 601 | + 'quantity' => $this->getProductStockQty($product), |
| 602 | + 'price' => $product->getPrice(), |
| 603 | + 'options' => $childProductOptions, |
| 604 | + 'weight' => $product->getWeight(), |
| 605 | + 'status' => $product->getStatus(), |
| 606 | + '__disableTmpl' => true, |
| 607 | + ]; |
| 608 | + } |
446 | 609 | }
|
0 commit comments