SaveHandler.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\ConfigurableProduct\Model\Product;
  7. use Magento\Catalog\Api\Data\ProductInterface;
  8. use Magento\ConfigurableProduct\Api\OptionRepositoryInterface;
  9. use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
  10. use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable as ResourceModelConfigurable;
  11. use Magento\Framework\EntityManager\Operation\ExtensionInterface;
  12. use Magento\ConfigurableProduct\Api\Data\OptionInterface;
  13. use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;
  14. /**
  15. * Class SaveHandler
  16. */
  17. class SaveHandler implements ExtensionInterface
  18. {
  19. /**
  20. * @var OptionRepositoryInterface
  21. */
  22. private $optionRepository;
  23. /**
  24. * @var ResourceModelConfigurable
  25. */
  26. private $resourceModel;
  27. /**
  28. * SaveHandler constructor
  29. *
  30. * @param ResourceModelConfigurable $resourceModel
  31. * @param OptionRepositoryInterface $optionRepository
  32. */
  33. public function __construct(
  34. ResourceModelConfigurable $resourceModel,
  35. OptionRepositoryInterface $optionRepository
  36. ) {
  37. $this->resourceModel = $resourceModel;
  38. $this->optionRepository = $optionRepository;
  39. }
  40. /**
  41. * @param ProductInterface $entity
  42. * @param array $arguments
  43. * @return ProductInterface
  44. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  45. */
  46. public function execute($entity, $arguments = [])
  47. {
  48. if ($entity->getTypeId() !== Configurable::TYPE_CODE) {
  49. return $entity;
  50. }
  51. $extensionAttributes = $entity->getExtensionAttributes();
  52. if ($extensionAttributes === null) {
  53. return $entity;
  54. }
  55. if ($extensionAttributes->getConfigurableProductOptions() !== null) {
  56. $this->deleteConfigurableProductAttributes($entity);
  57. }
  58. $configurableOptions = (array) $extensionAttributes->getConfigurableProductOptions();
  59. if (!empty($configurableOptions)) {
  60. $this->saveConfigurableProductAttributes($entity, $configurableOptions);
  61. }
  62. $configurableLinks = $extensionAttributes->getConfigurableProductLinks();
  63. if ($configurableLinks !== null) {
  64. $configurableLinks = (array)$configurableLinks;
  65. $this->resourceModel->saveProducts($entity, $configurableLinks);
  66. }
  67. return $entity;
  68. }
  69. /**
  70. * Save only newly created attributes for configurable product.
  71. *
  72. * @param ProductInterface $product
  73. * @param array $attributes
  74. * @return array
  75. */
  76. private function saveConfigurableProductAttributes(ProductInterface $product, array $attributes): array
  77. {
  78. $ids = [];
  79. $existingAttributeIds = [];
  80. foreach ($this->optionRepository->getList($product->getSku()) as $option) {
  81. $existingAttributeIds[$option->getAttributeId()] = $option;
  82. }
  83. /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute $attribute */
  84. foreach ($attributes as $attribute) {
  85. if (!in_array($attribute->getAttributeId(), array_keys($existingAttributeIds))
  86. || $this->isOptionChanged($existingAttributeIds[$attribute->getAttributeId()], $attribute)
  87. ) {
  88. $attribute->setId(null);
  89. $ids[] = $this->optionRepository->save($product->getSku(), $attribute);
  90. }
  91. }
  92. return $ids;
  93. }
  94. /**
  95. * Remove product attributes which no longer used.
  96. *
  97. * @param ProductInterface $product
  98. * @return void
  99. */
  100. private function deleteConfigurableProductAttributes(ProductInterface $product): void
  101. {
  102. $newAttributeIds = [];
  103. foreach ($product->getExtensionAttributes()->getConfigurableProductOptions() as $option) {
  104. $newAttributeIds[$option->getAttributeId()] = $option;
  105. }
  106. foreach ($this->optionRepository->getList($product->getSku()) as $option) {
  107. if (!in_array($option->getAttributeId(), array_keys($newAttributeIds))
  108. || $this->isOptionChanged($option, $newAttributeIds[$option->getAttributeId()])
  109. ) {
  110. $this->optionRepository->deleteById($product->getSku(), $option->getId());
  111. }
  112. }
  113. }
  114. /**
  115. * Check if existing option is changed.
  116. *
  117. * @param OptionInterface $option
  118. * @param Attribute $attribute
  119. * @return bool
  120. */
  121. private function isOptionChanged(OptionInterface $option, Attribute $attribute): bool
  122. {
  123. if ($option->getLabel() == $attribute->getLabel() && $option->getPosition() == $attribute->getPosition()) {
  124. return false;
  125. }
  126. return true;
  127. }
  128. }