Collection.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\ConfigurableProductGraphQl\Model\Variant;
  8. use Magento\Catalog\Api\Data\ProductInterface;
  9. use Magento\Catalog\Model\Product;
  10. use Magento\Catalog\Model\ProductFactory;
  11. use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection as ChildCollection;
  12. use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory;
  13. use Magento\Framework\EntityManager\MetadataPool;
  14. use Magento\Framework\Api\SearchCriteriaBuilder;
  15. use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product as DataProvider;
  16. /**
  17. * Collection for fetching configurable child product data.
  18. */
  19. class Collection
  20. {
  21. /**
  22. * @var CollectionFactory
  23. */
  24. private $childCollectionFactory;
  25. /**
  26. * @var ProductFactory
  27. */
  28. private $productFactory;
  29. /**
  30. * @var SearchCriteriaBuilder
  31. */
  32. private $searchCriteriaBuilder;
  33. /**
  34. * @var DataProvider
  35. */
  36. private $productDataProvider;
  37. /**
  38. * @var MetadataPool
  39. */
  40. private $metadataPool;
  41. /**
  42. * @var Product[]
  43. */
  44. private $parentProducts = [];
  45. /**
  46. * @var array
  47. */
  48. private $childrenMap = [];
  49. /**
  50. * @var string[]
  51. */
  52. private $attributeCodes = [];
  53. /**
  54. * @param CollectionFactory $childCollectionFactory
  55. * @param ProductFactory $productFactory
  56. * @param SearchCriteriaBuilder $searchCriteriaBuilder
  57. * @param DataProvider $productDataProvider
  58. * @param MetadataPool $metadataPool
  59. */
  60. public function __construct(
  61. CollectionFactory $childCollectionFactory,
  62. ProductFactory $productFactory,
  63. SearchCriteriaBuilder $searchCriteriaBuilder,
  64. DataProvider $productDataProvider,
  65. MetadataPool $metadataPool
  66. ) {
  67. $this->childCollectionFactory = $childCollectionFactory;
  68. $this->productFactory = $productFactory;
  69. $this->searchCriteriaBuilder = $searchCriteriaBuilder;
  70. $this->productDataProvider = $productDataProvider;
  71. $this->metadataPool = $metadataPool;
  72. }
  73. /**
  74. * Add parent to collection filter
  75. *
  76. * @param Product $product
  77. * @return void
  78. */
  79. public function addParentProduct(Product $product) : void
  80. {
  81. if (isset($this->parentProducts[$product->getId()])) {
  82. return;
  83. }
  84. if (!empty($this->childrenMap)) {
  85. $this->childrenMap = [];
  86. }
  87. $this->parentProducts[$product->getId()] = $product;
  88. }
  89. /**
  90. * Add attributes to collection filter
  91. *
  92. * @param array $attributeCodes
  93. * @return void
  94. */
  95. public function addEavAttributes(array $attributeCodes) : void
  96. {
  97. $this->attributeCodes = array_replace($this->attributeCodes, $attributeCodes);
  98. }
  99. /**
  100. * Retrieve child products from for passed in parent id.
  101. *
  102. * @param int $id
  103. * @return array
  104. */
  105. public function getChildProductsByParentId(int $id) : array
  106. {
  107. $childrenMap = $this->fetch();
  108. if (!isset($childrenMap[$id])) {
  109. return [];
  110. }
  111. return $childrenMap[$id];
  112. }
  113. /**
  114. * Fetch all children products from parent id's.
  115. *
  116. * @return array
  117. * @throws \Exception
  118. */
  119. private function fetch() : array
  120. {
  121. if (empty($this->parentProducts) || !empty($this->childrenMap)) {
  122. return $this->childrenMap;
  123. }
  124. $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
  125. foreach ($this->parentProducts as $product) {
  126. $attributeData = $this->getAttributesCodes($product);
  127. /** @var ChildCollection $childCollection */
  128. $childCollection = $this->childCollectionFactory->create();
  129. $childCollection->addAttributeToSelect($attributeData);
  130. /** @var Product $product */
  131. $product->setData($linkField, $product->getId());
  132. $childCollection->setProductFilter($product);
  133. /** @var Product $childProduct */
  134. foreach ($childCollection->getItems() as $childProduct) {
  135. $formattedChild = ['model' => $childProduct, 'sku' => $childProduct->getSku()];
  136. $parentId = (int)$childProduct->getParentId();
  137. if (!isset($this->childrenMap[$parentId])) {
  138. $this->childrenMap[$parentId] = [];
  139. }
  140. $this->childrenMap[$parentId][] = $formattedChild;
  141. }
  142. }
  143. return $this->childrenMap;
  144. }
  145. /**
  146. * Get attributes code
  147. *
  148. * @param \Magento\Catalog\Model\Product $currentProduct
  149. * @return array
  150. */
  151. private function getAttributesCodes(Product $currentProduct): array
  152. {
  153. $attributeCodes = [];
  154. $allowAttributes = $currentProduct->getTypeInstance()->getConfigurableAttributes($currentProduct);
  155. foreach ($allowAttributes as $attribute) {
  156. $productAttribute = $attribute->getProductAttribute();
  157. if (!\in_array($productAttribute->getAttributeCode(), $attributeCodes)) {
  158. $attributeCodes[] = $productAttribute->getAttributeCode();
  159. }
  160. }
  161. return $attributeCodes;
  162. }
  163. }