custom/plugins/MaxiaListingVariants6/src/Service/VariantMappingLoader.php line 37

Open in your IDE?
  1. <?php
  2. namespace Maxia\MaxiaListingVariants6\Service;
  3. use Monolog\Logger;
  4. use Maxia\MaxiaListingVariants6\Config\ProductConfig;
  5. use Maxia\MaxiaListingVariants6\Config\PropertyGroupConfig;
  6. use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
  7. use Shopware\Core\Content\Product\ProductEntity;
  8. use Shopware\Core\Content\Property\Aggregate\PropertyGroupOption\PropertyGroupOptionEntity;
  9. use Shopware\Core\Content\Property\PropertyGroupCollection;
  10. use Shopware\Core\Content\Property\PropertyGroupEntity;
  11. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  12. /**
  13.  * Loads product assignments for each option.
  14.  */
  15. class VariantMappingLoader implements VariantMappingLoaderInterface 
  16. {
  17.     protected Logger $logger;
  18.     protected ConfigService $configService;
  19.     protected ProductCombinationFinderInterface $combinationFinder;
  20.     public function __construct(
  21.         Logger $logger,
  22.         ConfigService $configService,
  23.         ProductCombinationFinderInterface $combinationFinder)
  24.     {
  25.         $this->logger $logger;
  26.         $this->configService $configService;
  27.         $this->combinationFinder $combinationFinder;
  28.     }
  29.     /**
  30.      * Search product IDs for each option
  31.      */
  32.     public function loadAllMappings(ProductEntity $productSalesChannelContext $context): array
  33.     {
  34.         /** @var ProductConfig $config */
  35.         $config $product->getExtension('maxiaListingVariants');
  36.         $hideUnavailable $this->configService->getBaseConfig($context)->isHideSoldOutCloseoutProducts()
  37.             && $config->getTotalGroupCount() === 1;
  38.         $settings $config->getOptions();
  39.         $mappings $config->getOptionProductMappings() ?: [];
  40.         foreach ($settings->getElements() as $group) {
  41.             /** @var PropertyGroupConfig $groupConfig */
  42.             $groupConfig $group->getExtension('maxiaListingVariants');
  43.             $optionIndex 0;
  44.             foreach ($group->getOptions() as $key => $option) {
  45.                 if (isset($mappings[$option->getId()])) {
  46.                     continue;
  47.                 }
  48.                 $mappings[$option->getId()] = $this->loadMapping($product$group$option$context);
  49.                 if ($hideUnavailable && !$option->getCombinable()
  50.                     && !in_array($option->getId(), $product->getOptionIds()))
  51.                 {
  52.                     $group->getOptions()->remove($key);
  53.                     continue;
  54.                 }
  55.                 $optionIndex++;
  56.                 if ($groupConfig->getMaxEntries()
  57.                     && !$config->isExpanded()
  58.                     && $optionIndex $groupConfig->getMaxEntries()
  59.                 ) {
  60.                     break;
  61.                 }
  62.             }
  63.         }
  64.         return $mappings;
  65.     }
  66.     /**
  67.      * Loads variant mapping for the given option.
  68.      */
  69.     public function loadMapping(
  70.         ProductEntity $product,
  71.         PropertyGroupEntity $group,
  72.         PropertyGroupOptionEntity $option,
  73.         SalesChannelContext $context
  74.     ): array {
  75.         /** @var ProductConfig $productConfig */
  76.         $productConfig $product->getExtension('maxiaListingVariants');
  77.         /** @var PropertyGroupOptionEntity $option */
  78.         $combinationOptionIds $this->getCombinationOptionIds($product$productConfig->getOptions(), $option);
  79.         $parentId $product->getParentId() ?: $product->getId();
  80.         // use less restrictive search, only if quick buy is off and expand by property values is inactive
  81.         $preferExactOptions $productConfig->isQuickBuyActive();
  82.         if ($product->getConfiguratorGroupConfig()) {
  83.             foreach ($product->getConfiguratorGroupConfig() as $item) {
  84.                 if ($item['expressionForListings']) {
  85.                     $preferExactOptions true;
  86.                 }
  87.             }
  88.         }
  89.         try {
  90.             // try to find available variants first
  91.             $foundCombination $this->combinationFinder->find(
  92.                 $parentId,
  93.                 $group->getId(),
  94.                 $combinationOptionIds,
  95.                 false,
  96.                 $context
  97.             );
  98.             $option->setCombinable(true);
  99.             $mapping = [
  100.                 'productId' => $foundCombination->getVariantId(),
  101.                 'isCombinable' => $option->getCombinable()
  102.             ];
  103.         } catch (ProductNotFoundException $e) {
  104.             try {
  105.                 if ($preferExactOptions) {
  106.                     $foundCombination $this->combinationFinder->find(
  107.                         $parentId,
  108.                         $group->getId(),
  109.                         $combinationOptionIds,
  110.                         true,
  111.                         $context
  112.                     );
  113.                     $option->setCombinable(false);
  114.                 } else {
  115.                     try {
  116.                         $foundCombination $this->combinationFinder->find(
  117.                             $parentId,
  118.                             $group->getId(),
  119.                             [$option->getId()],
  120.                             false,
  121.                             $context
  122.                         );
  123.                         $option->setCombinable(true);
  124.                     } catch (ProductNotFoundException $e) {
  125.                         $foundCombination $this->combinationFinder->find(
  126.                             $parentId,
  127.                             $group->getId(),
  128.                             [$option->getId()],
  129.                             true,
  130.                             $context
  131.                         );
  132.                         $option->setCombinable(false);
  133.                     }
  134.                 }
  135.                 $mapping = [
  136.                     'productId' => $foundCombination->getVariantId(),
  137.                     'isCombinable' => $option->getCombinable()
  138.                 ];
  139.             } catch (ProductNotFoundException $e) {
  140.                 $this->logger->debug('No products found for combination', [
  141.                     'productId' => $product->getId(),
  142.                     'combinationOptionIds' => $combinationOptionIds
  143.                 ]);
  144.                 $mapping = [
  145.                     'productId' => $product->getId(),
  146.                     'isCombinable' => $product->getAvailable()
  147.                 ];
  148.             }
  149.         }
  150.         return $mapping;
  151.     }
  152.     /**
  153.      * Returns the option IDs that are used for resolving the product for each option.
  154.      */
  155.     public function getCombinationOptionIds(
  156.         ProductEntity $productEntity,
  157.         PropertyGroupCollection $settings,
  158.         PropertyGroupOptionEntity $option): array
  159.     {
  160.         $optionIds = [];
  161.         if (!$productEntity->getOptionIds()) {
  162.             return [$option->getId()];
  163.         }
  164.         foreach ($productEntity->getOptionIds() as $optionId) {
  165.             $group $settings->filter(function (PropertyGroupEntity $group) use ($optionId) {
  166.                 $optionIds $group->getOptions()->map(function(PropertyGroupOptionEntity $option) {
  167.                     return $option->getId();
  168.                 });
  169.                 return in_array($optionId$optionIds);
  170.             })->first();
  171.             if ($group && $group->getId() === $option->getGroupId()) {
  172.                 continue;
  173.             } else {
  174.                 $optionIds[] = $optionId;
  175.             }
  176.         }
  177.         $optionIds[] = $option->getId();
  178.         return $optionIds;
  179.     }
  180. }