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 (!$config->isExpanded() && $optionIndex $groupConfig->getMaxEntries()) {
  57.                     break;
  58.                 }
  59.             }
  60.         }
  61.         return $mappings;
  62.     }
  63.     /**
  64.      * Loads variant mapping for the given option.
  65.      */
  66.     public function loadMapping(
  67.         ProductEntity $product,
  68.         PropertyGroupEntity $group,
  69.         PropertyGroupOptionEntity $option,
  70.         SalesChannelContext $context
  71.     ): array {
  72.         /** @var ProductConfig $productConfig */
  73.         $productConfig $product->getExtension('maxiaListingVariants');
  74.         /** @var PropertyGroupOptionEntity $option */
  75.         $combinationOptionIds $this->getCombinationOptionIds($product$productConfig->getOptions(), $option);
  76.         $parentId $product->getParentId() ?: $product->getId();
  77.         // use less restrictive search, only if quick buy is off and expand by property values is inactive
  78.         $preferExactOptions $productConfig->isQuickBuyActive();
  79.         if ($product->getConfiguratorGroupConfig()) {
  80.             foreach ($product->getConfiguratorGroupConfig() as $item) {
  81.                 if ($item['expressionForListings']) {
  82.                     $preferExactOptions true;
  83.                 }
  84.             }
  85.         }
  86.         try {
  87.             // try to find available variants first
  88.             $foundCombination $this->combinationFinder->find(
  89.                 $parentId,
  90.                 $group->getId(),
  91.                 $combinationOptionIds,
  92.                 false,
  93.                 $context
  94.             );
  95.             $option->setCombinable(true);
  96.             $mapping = [
  97.                 'productId' => $foundCombination->getVariantId(),
  98.                 'isCombinable' => $option->getCombinable()
  99.             ];
  100.         } catch (ProductNotFoundException $e) {
  101.             try {
  102.                 if ($preferExactOptions) {
  103.                     $foundCombination $this->combinationFinder->find(
  104.                         $parentId,
  105.                         $group->getId(),
  106.                         $combinationOptionIds,
  107.                         true,
  108.                         $context
  109.                     );
  110.                     $option->setCombinable(false);
  111.                 } else {
  112.                     try {
  113.                         $foundCombination $this->combinationFinder->find(
  114.                             $parentId,
  115.                             $group->getId(),
  116.                             [$option->getId()],
  117.                             false,
  118.                             $context
  119.                         );
  120.                         $option->setCombinable(true);
  121.                     } catch (ProductNotFoundException $e) {
  122.                         $foundCombination $this->combinationFinder->find(
  123.                             $parentId,
  124.                             $group->getId(),
  125.                             [$option->getId()],
  126.                             true,
  127.                             $context
  128.                         );
  129.                         $option->setCombinable(false);
  130.                     }
  131.                 }
  132.                 $mapping = [
  133.                     'productId' => $foundCombination->getVariantId(),
  134.                     'isCombinable' => $option->getCombinable()
  135.                 ];
  136.             } catch (ProductNotFoundException $e) {
  137.                 $this->logger->debug('No products found for combination', [
  138.                     'productId' => $product->getId(),
  139.                     'combinationOptionIds' => $combinationOptionIds
  140.                 ]);
  141.                 $mapping = [
  142.                     'productId' => $product->getId(),
  143.                     'isCombinable' => $product->getAvailable()
  144.                 ];
  145.             }
  146.         }
  147.         return $mapping;
  148.     }
  149.     /**
  150.      * Returns the option IDs that are used for resolving the product for each option.
  151.      */
  152.     public function getCombinationOptionIds(
  153.         ProductEntity $productEntity,
  154.         PropertyGroupCollection $settings,
  155.         PropertyGroupOptionEntity $option): array
  156.     {
  157.         $optionIds = [];
  158.         if (!$productEntity->getOptionIds()) {
  159.             return [$option->getId()];
  160.         }
  161.         foreach ($productEntity->getOptionIds() as $optionId) {
  162.             $group $settings->filter(function (PropertyGroupEntity $group) use ($optionId) {
  163.                 $optionIds $group->getOptions()->map(function(PropertyGroupOptionEntity $option) {
  164.                     return $option->getId();
  165.                 });
  166.                 return in_array($optionId$optionIds);
  167.             })->first();
  168.             if ($group && $group->getId() === $option->getGroupId()) {
  169.                 continue;
  170.             } else {
  171.                 $optionIds[] = $optionId;
  172.             }
  173.         }
  174.         $optionIds[] = $option->getId();
  175.         return $optionIds;
  176.     }
  177. }