Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Data.php
Go to the documentation of this file.
1 <?php
7 
15 use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
20 use Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory as SwatchCollectionFactory;
24 
30 class Data
31 {
35  const EMPTY_IMAGE_VALUE = 'no_selection';
36 
40  const DEFAULT_STORE_ID = 0;
41 
46 
50  protected $productRepository;
51 
55  protected $storeManager;
56 
61 
67  private $metadataPool;
68 
72  private $swatchAttributesProvider;
73 
81  'update_product_preview_image',
82  'use_product_image_for_swatch'
83  ];
84 
90  private $serializer;
91 
95  private $swatchTypeChecker;
96 
100  private $imageUrlBuilder;
101 
112  public function __construct(
113  CollectionFactory $productCollectionFactory,
116  SwatchCollectionFactory $swatchCollectionFactory,
117  UrlBuilder $urlBuilder,
118  Json $serializer = null,
119  SwatchAttributesProvider $swatchAttributesProvider = null,
120  SwatchAttributeType $swatchTypeChecker = null
121  ) {
122  $this->productCollectionFactory = $productCollectionFactory;
123  $this->productRepository = $productRepository;
124  $this->storeManager = $storeManager;
125  $this->swatchCollectionFactory = $swatchCollectionFactory;
126  $this->serializer = $serializer ?: ObjectManager::getInstance()->create(Json::class);
127  $this->swatchAttributesProvider = $swatchAttributesProvider
128  ?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class);
129  $this->swatchTypeChecker = $swatchTypeChecker
130  ?: ObjectManager::getInstance()->create(SwatchAttributeType::class);
131  $this->imageUrlBuilder = $urlBuilder;
132  }
133 
139  {
140  $initialAdditionalData = [];
141  $additionalData = (string)$attribute->getData('additional_data');
142  if (!empty($additionalData)) {
143  $additionalData = $this->serializer->unserialize($additionalData);
144  if (is_array($additionalData)) {
145  $initialAdditionalData = $additionalData;
146  }
147  }
148 
149  $dataToAdd = [];
150  foreach ($this->eavAttributeAdditionalDataKeys as $key) {
151  $dataValue = $attribute->getData($key);
152  if (null !== $dataValue) {
153  $dataToAdd[$key] = $dataValue;
154  }
155  }
156  $additionalData = array_merge($initialAdditionalData, $dataToAdd);
157  $attribute->setData('additional_data', $this->serializer->serialize($additionalData));
158  return $this;
159  }
160 
168  private function isMediaAvailable(ModelProduct $product, string $attributeCode): bool
169  {
170  $isAvailable = false;
171 
172  $mediaGallery = $product->getMediaGalleryEntries();
173  foreach ($mediaGallery as $mediaEntry) {
174  if (in_array($attributeCode, $mediaEntry->getTypes(), true)) {
175  $isAvailable = !$mediaEntry->isDisabled();
176  break;
177  }
178  }
179 
180  return $isAvailable;
181  }
182 
189  private function loadFirstVariation($attributeCode, ModelProduct $configurableProduct, array $requiredAttributes)
190  {
191  if ($this->isProductHasSwatch($configurableProduct)) {
192  $usedProducts = $configurableProduct->getTypeInstance()->getUsedProducts($configurableProduct);
193 
194  foreach ($usedProducts as $simpleProduct) {
195  if (!array_diff_assoc($requiredAttributes, $simpleProduct->getData())
196  && $this->isMediaAvailable($simpleProduct, $attributeCode)
197  ) {
198  return $simpleProduct;
199  }
200  }
201  }
202 
203  return false;
204  }
205 
211  public function loadFirstVariationWithSwatchImage(Product $configurableProduct, array $requiredAttributes)
212  {
213  return $this->loadFirstVariation('swatch_image', $configurableProduct, $requiredAttributes);
214  }
215 
221  public function loadFirstVariationWithImage(Product $configurableProduct, array $requiredAttributes)
222  {
223  return $this->loadFirstVariation('image', $configurableProduct, $requiredAttributes);
224  }
225 
233  public function loadVariationByFallback(Product $parentProduct, array $attributes)
234  {
235  if (!$this->isProductHasSwatch($parentProduct)) {
236  return false;
237  }
238 
239  $productCollection = $this->productCollectionFactory->create();
240 
241  $productLinkedFiled = $this->getMetadataPool()
242  ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
243  ->getLinkField();
244  $parentId = $parentProduct->getData($productLinkedFiled);
245 
246  $this->addFilterByParent($productCollection, $parentId);
247 
248  $configurableAttributes = $this->getAttributesFromConfigurable($parentProduct);
249  $allAttributesArray = [];
250  foreach ($configurableAttributes as $attribute) {
251  if (!empty($attribute['default_value'])) {
252  $allAttributesArray[$attribute['attribute_code']] = $attribute['default_value'];
253  }
254  }
255 
256  $resultAttributesToFilter = array_merge(
257  $attributes,
258  array_diff_key($allAttributesArray, $attributes)
259  );
260 
261  $this->addFilterByAttributes($productCollection, $resultAttributesToFilter);
262 
263  $variationProduct = $productCollection->getFirstItem();
264  if ($variationProduct && $variationProduct->getId()) {
265  return $this->productRepository->getById($variationProduct->getId());
266  }
267 
268  return false;
269  }
270 
276  private function addFilterByAttributes(ProductCollection $productCollection, array $attributes)
277  {
278  foreach ($attributes as $code => $option) {
279  $productCollection->addAttributeToFilter($code, ['eq' => $option]);
280  }
281  }
282 
288  private function addFilterByParent(ProductCollection $productCollection, $parentId)
289  {
290  $tableProductRelation = $productCollection->getTable('catalog_product_relation');
292  ->getSelect()
293  ->join(
294  ['pr' => $tableProductRelation],
295  'e.entity_id = pr.child_id'
296  )
297  ->where('pr.parent_id = ?', $parentId);
298  }
299 
314  {
315  $baseImage = null;
316  $gallery = [];
317 
318  $mediaGallery = $product->getMediaGalleryEntries();
319  foreach ($mediaGallery as $mediaEntry) {
320  if ($mediaEntry->isDisabled()) {
321  continue;
322  }
323 
324  if (in_array('image', $mediaEntry->getTypes(), true) || !$baseImage) {
325  $baseImage = $mediaEntry->getFile();
326  }
327 
328  $gallery[$mediaEntry->getId()] = $this->getAllSizeImages($mediaEntry->getFile());
329  }
330 
331  if (!$baseImage) {
332  return [];
333  }
334 
335  $resultGallery = $this->getAllSizeImages($baseImage);
336  $resultGallery['gallery'] = $gallery;
337 
338  return $resultGallery;
339  }
340 
345  private function getAllSizeImages($imageFile)
346  {
347  return [
348  'large' => $this->imageUrlBuilder->getUrl($imageFile, 'product_swatch_image_large'),
349  'medium' => $this->imageUrlBuilder->getUrl($imageFile, 'product_swatch_image_medium'),
350  'small' => $this->imageUrlBuilder->getUrl($imageFile, 'product_swatch_image_small')
351  ];
352  }
353 
360  private function getSwatchAttributes(Product $product)
361  {
362  $swatchAttributes = $this->swatchAttributesProvider->provide($product);
363  return $swatchAttributes;
364  }
365 
372  public function getAttributesFromConfigurable(Product $product)
373  {
374  $result = [];
375  $typeInstance = $product->getTypeInstance();
376  if ($typeInstance instanceof Configurable) {
377  $configurableAttributes = $typeInstance->getConfigurableAttributes($product);
379  foreach ($configurableAttributes as $configurableAttribute) {
381  $attribute = $configurableAttribute->getProductAttribute();
382  $result[] = $attribute;
383  }
384  }
385  return $result;
386  }
387 
394  public function getSwatchAttributesAsArray(Product $product)
395  {
396  $result = [];
397  $swatchAttributes = $this->getSwatchAttributes($product);
398  foreach ($swatchAttributes as $swatchAttribute) {
399  $swatchAttribute->setStoreId($this->storeManager->getStore()->getId());
400  $attributeData = $swatchAttribute->getData();
401  foreach ($swatchAttribute->getSource()->getAllOptions(false) as $option) {
402  $attributeData['options'][$option['value']] = $option['label'];
403  }
404  $result[$attributeData['attribute_id']] = $attributeData;
405  }
406 
407  return $result;
408  }
409 
413  private $swatchesCache = [];
414 
421  public function getSwatchesByOptionsId(array $optionIds)
422  {
423  $swatches = $this->getCachedSwatches($optionIds);
424 
425  if (count($swatches) !== count($optionIds)) {
426  $swatchOptionIds = array_diff($optionIds, array_keys($swatches));
428  $swatchCollection = $this->swatchCollectionFactory->create();
429  $swatchCollection->addFilterByOptionsIds($swatchOptionIds);
430 
431  $swatches = [];
432  $fallbackValues = [];
433  $currentStoreId = $this->storeManager->getStore()->getId();
434  foreach ($swatchCollection as $item) {
435  if ($item['type'] != Swatch::SWATCH_TYPE_TEXTUAL) {
436  $swatches[$item['option_id']] = $item->getData();
437  } elseif ($item['store_id'] == $currentStoreId && $item['value'] != '') {
438  $fallbackValues[$item['option_id']][$currentStoreId] = $item->getData();
439  } elseif ($item['store_id'] == self::DEFAULT_STORE_ID) {
440  $fallbackValues[$item['option_id']][self::DEFAULT_STORE_ID] = $item->getData();
441  }
442  }
443 
444  if (!empty($fallbackValues)) {
445  $swatches = $this->addFallbackOptions($fallbackValues, $swatches);
446  }
447  $this->setCachedSwatches($swatchOptionIds, $swatches);
448  }
449 
450  return array_filter($this->getCachedSwatches($optionIds));
451  }
452 
459  private function getCachedSwatches(array $optionIds)
460  {
461  return array_intersect_key($this->swatchesCache, array_combine($optionIds, $optionIds));
462  }
463 
471  private function setCachedSwatches(array $optionIds, array $swatches)
472  {
473  foreach ($optionIds as $optionId) {
474  $this->swatchesCache[$optionId] = isset($swatches[$optionId]) ? $swatches[$optionId] : null;
475  }
476  }
477 
483  private function addFallbackOptions(array $fallbackValues, array $swatches)
484  {
485  $currentStoreId = $this->storeManager->getStore()->getId();
486  foreach ($fallbackValues as $optionId => $optionsArray) {
487  if (isset($optionsArray[$currentStoreId]['type'], $swatches[$optionId]['type'])
488  && $swatches[$optionId]['type'] === $optionsArray[$currentStoreId]['type']
489  ) {
490  $swatches[$optionId] = $optionsArray[$currentStoreId];
491  } elseif (isset($optionsArray[self::DEFAULT_STORE_ID])) {
492  $swatches[$optionId] = $optionsArray[self::DEFAULT_STORE_ID];
493  }
494  }
495 
496  return $swatches;
497  }
498 
505  public function isProductHasSwatch(Product $product)
506  {
507  return !empty($this->getSwatchAttributes($product));
508  }
509 
517  {
518  return $this->swatchTypeChecker->isSwatchAttribute($attribute);
519  }
520 
528  {
529  return $this->swatchTypeChecker->isVisualSwatch($attribute);
530  }
531 
539  {
540  return $this->swatchTypeChecker->isTextSwatch($attribute);
541  }
542 
549  protected function getMetadataPool()
550  {
551  if (!$this->metadataPool) {
553  ->get(\Magento\Framework\EntityManager\MetadataPool::class);
554  }
555  return $this->metadataPool;
556  }
557 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
isVisualSwatch(Attribute $attribute)
Definition: Data.php:527
loadFirstVariationWithImage(Product $configurableProduct, array $requiredAttributes)
Definition: Data.php:221
getSwatchAttributesAsArray(Product $product)
Definition: Data.php:394
__construct(CollectionFactory $productCollectionFactory, ProductRepositoryInterface $productRepository, StoreManagerInterface $storeManager, SwatchCollectionFactory $swatchCollectionFactory, UrlBuilder $urlBuilder, Json $serializer=null, SwatchAttributesProvider $swatchAttributesProvider=null, SwatchAttributeType $swatchTypeChecker=null)
Definition: Data.php:112
isTextSwatch(Attribute $attribute)
Definition: Data.php:538
isSwatchAttribute(Attribute $attribute)
Definition: Data.php:516
$attributeCode
Definition: extend.phtml:12
loadFirstVariationWithSwatchImage(Product $configurableProduct, array $requiredAttributes)
Definition: Data.php:211
$attributes
Definition: matrix.phtml:13
assembleAdditionalDataEavAttribute(Attribute $attribute)
Definition: Data.php:138
isProductHasSwatch(Product $product)
Definition: Data.php:505
loadVariationByFallback(Product $parentProduct, array $attributes)
Definition: Data.php:233
getProductMediaGallery(ModelProduct $product)
Definition: Data.php:313
$code
Definition: info.phtml:12