custom/plugins/KlikensteenThemeCustomChanges/src/Subscriber/KlikensteenAllVariantDetailPage.php line 62

Open in your IDE?
  1. <?php
  2. namespace Klikensteen\ThemeCustomChanges\Subscriber;
  3. use Shopware\Core\Content\Product\ProductEntity;
  4. use Shopware\Core\Content\Property\PropertyGroupCollection;
  5. use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepository;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  9. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  10. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\DependencyInjection\ContainerInterface;
  13. use Shopware\Core\Framework\Context;
  14. /**
  15.  * Class AllVariantDetailPage
  16.  *
  17.  * Used to collect the information of the variants
  18.  */
  19. class KlikensteenAllVariantDetailPage implements EventSubscriberInterface
  20. {
  21.     /**
  22.      * @var SalesChannelRepository
  23.      */
  24.     private $productRepository;
  25.     /**
  26.      * @var ContainerInterface
  27.      */
  28.     protected $container;
  29.     /**
  30.      * AllVariantDetailPage constructor.
  31.      *
  32.      * @param SalesChannelRepository $productRepository
  33.      */
  34.     public function __construct(
  35.         SalesChannelRepository $productRepository,
  36.         ContainerInterface $container
  37.     )
  38.     {
  39.         $this->productRepository $productRepository;
  40.         $this->container $container;
  41.     }
  42.     /**
  43.      * @return string[]
  44.      */
  45.     public static function getSubscribedEvents(): array
  46.     {
  47.         return [
  48.             ProductPageLoadedEvent::class => 'addAllVariantToDetailPage'
  49.         ];
  50.     }
  51.     /**
  52.      * Used to prepare the information of the variants for the overview table.
  53.      *
  54.      * @param ProductPageLoadedEvent $event
  55.      */
  56.     public function addAllVariantToDetailPage(ProductPageLoadedEvent $event): void
  57.     {
  58.         $salesChannelContext  $event->getSalesChannelContext();
  59.         $taxState $salesChannelContext->getTaxState();
  60.         // Determines the current product
  61.         $product $event
  62.             ->getPage()
  63.             ->getProduct()
  64.         ;
  65.         // Check for a parent product and skip if it's not a variant
  66.         $parentId $product->getParentId();
  67.         if (empty($parentId)) { 
  68.             $totalTax 0;
  69.             foreach(($product->getCalculatedPrice()->getCalculatedTaxes()->getElements()) as $tax) {
  70.                 $totalTax +=$tax->getTax();
  71.             }
  72.              
  73.             $event->getPage()->assign([
  74.                 'KlikensteenCalculatedPrice'=> $product->getCalculatedPrice(),
  75.                 'KlikensteenCalculatedPriceTax'=> $totalTax
  76.             ]);
  77.             return;
  78.         }
  79.         // Get all siblings (products with the same parent)
  80.         $siblings $this->getSiblings(
  81.             $parentId,
  82.             $event->getSalesChannelContext()
  83.         );
  84.         // If the siblings are empty, the method can be exited
  85.         if (empty($siblings)) {
  86.             return;
  87.         }
  88.         // Determines the required data of the variants and writes them into the $variants array
  89.         $variants = [];
  90.         foreach ($siblings->getElements() as $index => $sibling) {
  91.             if (!$sibling->getActive()) {
  92.                 continue;
  93.             }
  94.             // The stock is determined.
  95.             // Set to true by default.
  96.             // If there is no more available stock it is set to false.
  97.             $stock true;
  98.             if ($sibling->getAvailableStock() < 1) {
  99.                 $stock false;
  100.             }
  101.             // Determines the price, base price, the unit and the name of the unit
  102.             $referencePrice 0;
  103.             $referenceUnitName '';
  104.             $referenceUnit 1;
  105.             $price $sibling->getCalculatedPrice()->getTotalPrice();
  106.             if (null != $sibling->getCalculatedPrice()->getReferencePrice()) {
  107.                 $referencePrice $sibling->getCalculatedPrice()->getReferencePrice()->getPrice();
  108.                 $referenceUnitName $sibling->getCalculatedPrice()->getReferencePrice()->getUnitName();
  109.                 $referenceUnit $sibling->getCalculatedPrice()->getReferencePrice()->getReferenceUnit();
  110.             }
  111.             // The names of the variant options are determined.
  112.             $variantOptions = [];
  113.             foreach ($sibling->getVariation() as $variation) {
  114.                 $variantOptions[] = $variation['option'];
  115.             }
  116.             // The url of the image is determined. If there is no image, null is returned.
  117.             $image null;
  118.             $altTag null;
  119.             foreach ($sibling->getMedia()->getElements() as $media) {
  120.                 if ($sibling->getCoverId() == $media->getId()) {
  121.                     $image $media->getMedia()->getUrl();
  122.                 }
  123.                 if (!empty($media->getMedia()->getAlt())) {
  124.                     $altTag $media->getMedia()->getAlt();
  125.                 } else {
  126.                     // Artikelnummer
  127.                     $altTag $sibling->getProductNumber();
  128.                 }
  129.             }
  130.             // The delivery time is determined.
  131.             $deliveryTime null;
  132.             if (null != $sibling->getDeliveryTime()){
  133.                 $deliveryTime $sibling->getDeliveryTime()->getName();
  134.             }
  135.             // Determines the position of the variant in the order
  136.             // in which the variants should later appear
  137.             $positions $this->getPosition($event->getPage()->getConfiguratorSettings());
  138.             $position 0;
  139.             foreach($sibling->getOptions() as $option) {
  140.                 foreach ($positions as $index => $positionId) {
  141.                     if ($option->getId() == $index) {
  142.                         $position $position.$positionId;
  143.                     }
  144.                 }
  145.             }
  146.             // All information is written to the array
  147.             $variants[$position] = [
  148.                 'media' => $image,
  149.                 'altTag' => $altTag,
  150.                 'productNumber' => $sibling->getProductNumber(),
  151.                 'manufacturerNumber' => $sibling->getManufacturerNumber(),
  152.                 'variation' => null,
  153.                 'price' => $price,
  154.                 'referenceUnitPrice' => $referencePrice,
  155.                 'referenceUnitName' => $referenceUnitName,
  156.                 'referenceUnit' => $referenceUnit,
  157.                 'inStock' => $stock,
  158.                 'options' => $variantOptions,
  159.                 'deliveryTime' => $deliveryTime,
  160.                 'id' => $sibling->getId(),
  161.                 'available' => $sibling->getAvailable(),
  162.                 'minPurchase' => $sibling->getMinPurchase(),
  163.                 'purchaseSteps' => $sibling->getPurchaseSteps(),
  164.                 'availableStock' => $sibling->getAvailableStock(),
  165.                 'translated' => $sibling->getTranslated(),
  166.                 'restockTime' => $sibling->getRestockTime(),
  167.                 'deliveryTimeTranslation' => $deliveryTime,
  168.                 'priceList'=>$sibling->getCalculatedPrice(),
  169.                 'pricesFullList'=> $this->getRulePrices$parentId),
  170.                 'priceRuleData'=> json_decode($this->getRulePrices$parentId)),
  171.                 'minimum_range'=> $this->getMinimumPrice($parentId,$taxState),
  172.                 'taxState'=> $taxState
  173.             ];
  174.         }
  175.         // Sorts the variants by position to match the order of the Configurator options
  176.         ksort($variants);
  177.         // The array is passed to the page and can be found at page.extensions.allVariants.
  178.         $event
  179.             ->getPage()
  180.             ->assign(['KlikensteenAllVariants'=> $variants]);
  181.     }
  182.     /**
  183.      * Determines the variants and all associated information based on the passed parentId.
  184.      *
  185.      * @param string $parent
  186.      * @param SalesChannelContext $context
  187.      * @return ProductEntity|null
  188.      */
  189.     private function getSiblings(
  190.         string $parent,
  191.         SalesChannelContext $context
  192.     ): ?EntitySearchResult {
  193.         $criteria = new Criteria();
  194.         $criteria
  195.             ->addFilter(new EqualsFilter('parentId'$parent))
  196.             ->addAssociation('manufacturer.media')
  197.             ->addAssociation('options.group')
  198.             ->addAssociation('properties.group')
  199.             ->addAssociation('mainCategories.category')
  200.             ->addAssociation('deliveryTime.deliveryTime')
  201.             ->getAssociation('media');
  202.         return $this
  203.             ->productRepository
  204.             ->search($criteria$context);
  205.     }
  206.     /**
  207.      * Sets the order of the Configurator options
  208.      *
  209.      * @param PropertyGroupCollection $configSettings
  210.      * @return array
  211.      */
  212.     private function getPosition(PropertyGroupCollection $configSettings): array {
  213.         $positions = [];
  214.         $i 1;
  215.         foreach ($configSettings as $configSetting) {
  216.             foreach ($configSetting->getOptions() as $index => $option) {
  217.                 $positions[$index] = $i;
  218.                 $i++;
  219.             }
  220.         }
  221.         return $positions;
  222.     }
  223.     private function getRulePrices($prodId ) {
  224.         $criteria = (new Criteria())->addFilter(new EqualsFilter('product_price.productId'$prodId));
  225.         $result $this->container->get('product_price.repository')->search($criteriaContext::createDefaultContext());
  226.         $response = [];
  227.         foreach($result->getElements() as $prices) {
  228.             $amounts $prices->getPrice()->getElements();
  229.             foreach($amounts as $amount) {
  230.                 $amt = [
  231.                     'net' => $amount->getNet(),
  232.                     'gross' => $amount->getGross(),
  233.                 ]; 
  234.             }
  235.             $response[] = [
  236.                 'quantityStart' => $prices->getQuantityStart(),
  237.                 'quantityEnd' => $prices->getQuantityEnd(),
  238.                 'net' => $amt['net'],
  239.                 'gross' => $amt['gross'],
  240.             ];
  241.         } 
  242.         return !empty($response) ? json_encode($response) : false;
  243.     }
  244.     private function getMinimumPrice($prodId$taxState) {
  245.         $criteria = (new Criteria())->addFilter(new EqualsFilter('product_price.productId'$prodId));
  246.         $result $this->container->get('product_price.repository')->search($criteriaContext::createDefaultContext());
  247.         $response = [];
  248.         foreach($result->getElements() as $prices) {
  249.             $amounts $prices->getPrice()->getElements();
  250.             foreach($amounts as $amount) {
  251.                 $amt = [
  252.                     'net' => $amount->getNet(),
  253.                     'gross' => $amount->getGross(),
  254.                 ]; 
  255.             }
  256.             $start $prices->getQuantityStart()>0?$prices->getQuantityStart():0;
  257.             $response[$start] = [
  258.                 'quantityStart' => $prices->getQuantityStart(),
  259.                 'quantityEnd' => $prices->getQuantityEnd(),
  260.                 'net' => $amt['net'],
  261.                 'gross' => $amt['gross'],
  262.             ];
  263.           
  264.             
  265.         }  
  266.         
  267.         usort($response, function ($a$b) {
  268.             return $a['quantityStart'] - $b['quantityStart'];
  269.         });
  270.         if($taxState == 'net') {
  271.             return isset($response[0]['net']) ? $response[0]['net'] : null;
  272.         }
  273.         return isset($response[0]['gross']) ? $response[0]['gross'] : null;
  274.     }
  275.     
  276. }