vendor/shopware/core/Content/Product/SalesChannel/SalesChannelProductSubscriber.php line 49

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Product\SalesChannel;
  3. use Shopware\Core\Checkout\Cart\Price\QuantityPriceCalculator;
  4. use Shopware\Core\Checkout\Cart\Price\Struct\PriceCollection;
  5. use Shopware\Core\Content\Product\ProductEntity;
  6. use Shopware\Core\Content\Product\SalesChannel\Price\ProductPriceDefinitionBuilderInterface;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\CalculatedListingPrice;
  8. use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
  9. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  10. use Shopware\Core\System\SystemConfig\SystemConfigService;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. class SalesChannelProductSubscriber implements EventSubscriberInterface
  13. {
  14.     /**
  15.      * @var QuantityPriceCalculator
  16.      */
  17.     private $priceCalculator;
  18.     /**
  19.      * @var ProductPriceDefinitionBuilderInterface
  20.      */
  21.     private $priceDefinitionBuilder;
  22.     /**
  23.      * @var SystemConfigService
  24.      */
  25.     private $systemConfigService;
  26.     public function __construct(
  27.         QuantityPriceCalculator $priceCalculator,
  28.         ProductPriceDefinitionBuilderInterface $priceDefinitionBuilder,
  29.         SystemConfigService $systemConfigService
  30.     ) {
  31.         $this->priceCalculator $priceCalculator;
  32.         $this->priceDefinitionBuilder $priceDefinitionBuilder;
  33.         $this->systemConfigService $systemConfigService;
  34.     }
  35.     public static function getSubscribedEvents()
  36.     {
  37.         return [
  38.             'sales_channel.product.loaded' => 'loaded',
  39.         ];
  40.     }
  41.     public function loaded(SalesChannelEntityLoadedEvent $event): void
  42.     {
  43.         /** @var SalesChannelProductEntity $product */
  44.         foreach ($event->getEntities() as $product) {
  45.             $this->calculatePrices($event->getSalesChannelContext(), $product);
  46.             $product->setCalculatedMaxPurchase(
  47.                 $this->calculateMaxPurchase($product$event->getSalesChannelContext()->getSalesChannel()->getId())
  48.             );
  49.             $this->markAsNew($event->getSalesChannelContext(), $product);
  50.             $product->setGrouped(
  51.                 $this->isGrouped($product)
  52.             );
  53.         }
  54.     }
  55.     private function isGrouped(ProductEntity $product): bool
  56.     {
  57.         if ($product->getMainVariantId() !== null) {
  58.             return false;
  59.         }
  60.         // get all configured expanded groups
  61.         $groups array_filter(
  62.             (array) $product->getConfiguratorGroupConfig(),
  63.             static function (array $config) {
  64.                 return $config['expressionForListings'] ?? false;
  65.             }
  66.         );
  67.         // get ids of groups for later usage
  68.         $groups array_column($groups'id');
  69.         // expanded group count matches option count? All variants are displayed
  70.         if ($product->getOptionIds() !== null && \count($groups) === \count($product->getOptionIds())) {
  71.             return false;
  72.         }
  73.         if ($product->getParentId()) {
  74.             return true;
  75.         }
  76.         return false;
  77.     }
  78.     private function calculatePrices(SalesChannelContext $contextSalesChannelProductEntity $product): void
  79.     {
  80.         $prices $this->priceDefinitionBuilder->build($product$context);
  81.         //calculate listing price
  82.         $product->setCalculatedListingPrice(
  83.             new CalculatedListingPrice(
  84.                 $this->priceCalculator->calculate($prices->getFrom(), $context),
  85.                 $this->priceCalculator->calculate($prices->getTo(), $context)
  86.             )
  87.         );
  88.         $priceCollection = new PriceCollection();
  89.         foreach ($prices->getPrices() as $price) {
  90.             $priceCollection->add($this->priceCalculator->calculate($price$context));
  91.         }
  92.         //calculate context prices
  93.         $product->setCalculatedPrices($priceCollection);
  94.         //calculate simple price
  95.         $product->setCalculatedPrice(
  96.             $this->priceCalculator->calculate($prices->getPrice(), $context)
  97.         );
  98.     }
  99.     private function calculateMaxPurchase(SalesChannelProductEntity $productstring $salesChannelId): int
  100.     {
  101.         $fallback $this->systemConfigService->getInt('core.cart.maxQuantity'$salesChannelId);
  102.         $max $product->getMaxPurchase() ?? $fallback;
  103.         if ($product->getIsCloseout() && $product->getAvailableStock() < $max) {
  104.             $max = (int) $product->getAvailableStock();
  105.         }
  106.         $max floor((int) $max / ($product->getPurchaseSteps() ?? 1)) * $product->getPurchaseSteps();
  107.         return (int) max($max0);
  108.     }
  109.     private function markAsNew(SalesChannelContext $contextSalesChannelProductEntity $product): void
  110.     {
  111.         $markAsNewDayRange $this->systemConfigService->get('core.listing.markAsNew'$context->getSalesChannel()->getId());
  112.         $now = new \DateTime();
  113.         /* @var SalesChannelProductEntity $product */
  114.         $product->setIsNew(
  115.             $product->getReleaseDate() instanceof \DateTimeInterface
  116.             && $product->getReleaseDate()->diff($now)->days <= $markAsNewDayRange
  117.         );
  118.     }
  119. }