vendor/shopware/core/Content/Product/Subscriber/ProductSubscriber.php line 75

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Product\Subscriber;
  3. use Shopware\Core\Content\Product\AbstractIsNewDetector;
  4. use Shopware\Core\Content\Product\AbstractProductMaxPurchaseCalculator;
  5. use Shopware\Core\Content\Product\AbstractProductVariationBuilder;
  6. use Shopware\Core\Content\Product\AbstractPropertyGroupSorter;
  7. use Shopware\Core\Content\Product\AbstractSalesChannelProductBuilder;
  8. use Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice\CheapestPriceContainer;
  9. use Shopware\Core\Content\Product\ProductDefinition;
  10. use Shopware\Core\Content\Product\ProductEntity;
  11. use Shopware\Core\Content\Product\ProductEvents;
  12. use Shopware\Core\Content\Product\SalesChannel\Price\AbstractProductPriceCalculator;
  13. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  14. use Shopware\Core\Content\Property\Aggregate\PropertyGroupOption\PropertyGroupOptionCollection;
  15. use Shopware\Core\Framework\Context;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Entity;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Event\PartialEntityLoadedEvent;
  19. use Shopware\Core\Framework\Feature;
  20. use Shopware\Core\System\SalesChannel\Entity\PartialSalesChannelEntityLoadedEvent;
  21. use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
  22. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  23. use Shopware\Core\System\SystemConfig\SystemConfigService;
  24. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  25. class ProductSubscriber implements EventSubscriberInterface
  26. {
  27.     private AbstractSalesChannelProductBuilder $salesChannelProductBuilder;
  28.     private AbstractProductVariationBuilder $productVariationBuilder;
  29.     private AbstractProductPriceCalculator $calculator;
  30.     private AbstractPropertyGroupSorter $propertyGroupSorter;
  31.     private AbstractProductMaxPurchaseCalculator $maxPurchaseCalculator;
  32.     private AbstractIsNewDetector $isNewDetector;
  33.     private SystemConfigService $systemConfigService;
  34.     /**
  35.      * @internal
  36.      */
  37.     public function __construct(
  38.         AbstractSalesChannelProductBuilder $salesChannelProductBuilder,
  39.         AbstractProductVariationBuilder $productVariationBuilder,
  40.         AbstractProductPriceCalculator $calculator,
  41.         AbstractPropertyGroupSorter $propertyGroupSorter,
  42.         AbstractProductMaxPurchaseCalculator $maxPurchaseCalculator,
  43.         AbstractIsNewDetector $isNewDetector,
  44.         SystemConfigService $systemConfigService
  45.     ) {
  46.         $this->salesChannelProductBuilder $salesChannelProductBuilder;
  47.         $this->productVariationBuilder $productVariationBuilder;
  48.         $this->calculator $calculator;
  49.         $this->propertyGroupSorter $propertyGroupSorter;
  50.         $this->maxPurchaseCalculator $maxPurchaseCalculator;
  51.         $this->isNewDetector $isNewDetector;
  52.         $this->systemConfigService $systemConfigService;
  53.     }
  54.     public static function getSubscribedEvents(): array
  55.     {
  56.         return [
  57.             ProductEvents::PRODUCT_LOADED_EVENT => 'loaded',
  58.             'product.partial_loaded' => 'partialEntityLoaded',
  59.             'sales_channel.' ProductEvents::PRODUCT_LOADED_EVENT => 'salesChannelLoaded',
  60.             'sales_channel.product.partial_loaded' => 'partialSalesChannelLoaded',
  61.         ];
  62.     }
  63.     public function loaded(EntityLoadedEvent $event): void
  64.     {
  65.         $this->entityLoaded($event->getEntities(), $event->getContext());
  66.     }
  67.     /**
  68.      * @internal
  69.      */
  70.     public function partialEntityLoaded(PartialEntityLoadedEvent $event): void
  71.     {
  72.         $this->entityLoaded($event->getEntities(), $event->getContext());
  73.     }
  74.     public function salesChannelLoaded(SalesChannelEntityLoadedEvent $event): void
  75.     {
  76.         $this->productSalesChannelLoaded($event->getEntities(), $event->getSalesChannelContext());
  77.     }
  78.     /**
  79.      * @internal
  80.      */
  81.     public function partialSalesChannelLoaded(PartialSalesChannelEntityLoadedEvent $event): void
  82.     {
  83.         $this->productSalesChannelLoaded($event->getEntities(), $event->getSalesChannelContext());
  84.     }
  85.     /**
  86.      * @param Entity[] $collection
  87.      */
  88.     private function entityLoaded(array $collectionContext $context): void
  89.     {
  90.         /** @var ProductEntity $product */
  91.         foreach ($collection as $product) {
  92.             // CheapestPrice will only be added to SalesChannelProductEntities in the Future
  93.             if (!Feature::isActive('FEATURE_NEXT_16151')) {
  94.                 $price $product->get('cheapestPrice');
  95.                 if ($price instanceof CheapestPriceContainer) {
  96.                     $resolved $price->resolve($context);
  97.                     $product->assign([
  98.                         'cheapestPrice' => $resolved,
  99.                         'cheapestPriceContainer' => $price,
  100.                     ]);
  101.                 }
  102.             }
  103.             $this->setDefaultLayout($product);
  104.             $this->productVariationBuilder->build($product);
  105.         }
  106.     }
  107.     /**
  108.      * @param Entity[] $elements
  109.      */
  110.     private function productSalesChannelLoaded(array $elementsSalesChannelContext $context): void
  111.     {
  112.         /** @var SalesChannelProductEntity $product */
  113.         foreach ($elements as $product) {
  114.             if (Feature::isActive('FEATURE_NEXT_16151')) {
  115.                 $price $product->get('cheapestPrice');
  116.                 if ($price instanceof CheapestPriceContainer) {
  117.                     $resolved $price->resolve($context->getContext());
  118.                     $product->assign([
  119.                         'cheapestPrice' => $resolved,
  120.                         'cheapestPriceContainer' => $price,
  121.                     ]);
  122.                 }
  123.             }
  124.             if (Feature::isActive('v6.5.0.0')) {
  125.                 $assigns = [];
  126.                 if (($properties $product->get('properties')) !== null && $properties instanceof PropertyGroupOptionCollection) {
  127.                     $assigns['sortedProperties'] = $this->propertyGroupSorter->sort($properties);
  128.                 }
  129.                 $assigns['calculatedMaxPurchase'] = $this->maxPurchaseCalculator->calculate($product$context);
  130.                 $assigns['isNew'] = $this->isNewDetector->isNew($product$context);
  131.                 $product->assign($assigns);
  132.             } else {
  133.                 Feature::callSilentIfInactive('v6.5.0.0', function () use ($product$context): void {
  134.                     $this->salesChannelProductBuilder->build($product$context);
  135.                 });
  136.             }
  137.             $this->setDefaultLayout($product$context->getSalesChannelId());
  138.         }
  139.         $this->calculator->calculate($elements$context);
  140.     }
  141.     /**
  142.      * @param Entity $product - typehint as Entity because it could be a ProductEntity or PartialEntity
  143.      */
  144.     private function setDefaultLayout(Entity $product, ?string $salesChannelId null): void
  145.     {
  146.         if (!Feature::isActive('v6.5.0.0') || !$product->has('cmsPageId')) {
  147.             return;
  148.         }
  149.         if ($product->get('cmsPageId') !== null) {
  150.             return;
  151.         }
  152.         $cmsPageId $this->systemConfigService->get(ProductDefinition::CONFIG_KEY_DEFAULT_CMS_PAGE_PRODUCT$salesChannelId);
  153.         if (!$cmsPageId) {
  154.             return;
  155.         }
  156.         $product->assign(['cmsPageId' => $cmsPageId]);
  157.     }
  158. }