custom/plugins/ZweiPunktVariantsTableOverview/src/Subscriber/AllVariantDetailPage.php line 55

Open in your IDE?
  1. <?php
  2. namespace ZweiPunktVariantsTableOverview\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. /**
  13.  * Class AllVariantDetailPage
  14.  *
  15.  * Used to collect the information of the variants
  16.  */
  17. class AllVariantDetailPage implements EventSubscriberInterface
  18. {
  19.     /**
  20.      * @var SalesChannelRepository
  21.      */
  22.     private $productRepository;
  23.     /**
  24.      * AllVariantDetailPage constructor.
  25.      *
  26.      * @param SalesChannelRepository $productRepository
  27.      */
  28.     public function __construct(
  29.         SalesChannelRepository $productRepository
  30.     )
  31.     {
  32.         $this->productRepository $productRepository;
  33.     }
  34.     /**
  35.      * @return string[]
  36.      */
  37.     public static function getSubscribedEvents(): array
  38.     {
  39.         return [
  40.             ProductPageLoadedEvent::class => 'addAllVariantToDetailPage'
  41.         ];
  42.     }
  43.     /**
  44.      * Used to prepare the information of the variants for the overview table.
  45.      *
  46.      * @param ProductPageLoadedEvent $event
  47.      */
  48.     public function addAllVariantToDetailPage(ProductPageLoadedEvent $event): void
  49.     {
  50.         // Determines the current product
  51.         $product $event
  52.             ->getPage()
  53.             ->getProduct()
  54.         ;
  55.         // Check for a parent product and skip if it's not a variant
  56.         $parentId $product->getParentId();
  57.         if (empty($parentId)) {
  58.             return;
  59.         }
  60.         // Get all siblings (products with the same parent)
  61.         $siblings $this->getSiblings(
  62.             $parentId,
  63.             $event->getSalesChannelContext()
  64.         );
  65.         // If the siblings are empty, the method can be exited
  66.         if (empty($siblings)) {
  67.             return;
  68.         }
  69.         // Determines the required data of the variants and writes them into the $variants array
  70.         $variants = [];
  71.         foreach ($siblings->getElements() as $index => $sibling) {
  72.             if (!$sibling->getActive()) {
  73.                 continue;
  74.             }
  75.             // The stock is determined.
  76.             // Set to true by default.
  77.             // If there is no more available stock it is set to false.
  78.             $stock true;
  79.             if ($sibling->getAvailableStock() < 1) {
  80.                 $stock false;
  81.             }
  82.             // Determines the price, base price, the unit and the name of the unit
  83.             $referencePrice 0;
  84.             $referenceUnitName '';
  85.             $referenceUnit 1;
  86.             $price $sibling->getCalculatedPrice()->getTotalPrice();
  87.             if (null != $sibling->getCalculatedPrice()->getReferencePrice()) {
  88.                 $referencePrice $sibling->getCalculatedPrice()->getReferencePrice()->getPrice();
  89.                 $referenceUnitName $sibling->getCalculatedPrice()->getReferencePrice()->getUnitName();
  90.                 $referenceUnit $sibling->getCalculatedPrice()->getReferencePrice()->getReferenceUnit();
  91.             }
  92.             // The names of the variant options are determined.
  93.             $variantOptions = [];
  94.             foreach ($sibling->getVariation() as $variation) {
  95.                 $variantOptions[] = $variation['option'];
  96.             }
  97.             // The url of the image is determined. If there is no image, null is returned.
  98.             $image null;
  99.             $altTag null;
  100.             foreach ($sibling->getMedia()->getElements() as $media) {
  101.                 if ($sibling->getCoverId() == $media->getId()) {
  102.                     $image $media->getMedia()->getUrl();
  103.                 }
  104.                 if (!empty($media->getMedia()->getAlt())) {
  105.                     $altTag $media->getMedia()->getAlt();
  106.                 } else {
  107.                     // Artikelnummer
  108.                     $altTag $sibling->getProductNumber();
  109.                 }
  110.             }
  111.             // The delivery time is determined.
  112.             $deliveryTime null;
  113.             if (null != $sibling->getDeliveryTime()){
  114.                 $deliveryTime $sibling->getDeliveryTime()->getName();
  115.             }
  116.             // Determines the position of the variant in the order
  117.             // in which the variants should later appear
  118.             $positions $this->getPosition($event->getPage()->getConfiguratorSettings());
  119.             $position 0;
  120.             foreach($sibling->getOptions() as $option) {
  121.                 foreach ($positions as $index => $positionId) {
  122.                     if ($option->getId() == $index) {
  123.                         $position $position.$positionId;
  124.                     }
  125.                 }
  126.             }
  127.             // All information is written to the array
  128.             $variants[$position] = [
  129.                 'media' => $image,
  130.                 'altTag' => $altTag,
  131.                 'productNumber' => $sibling->getProductNumber(),
  132.                 'manufacturerNumber' => $sibling->getManufacturerNumber(),
  133.                 'variation' => null,
  134.                 'price' => $price,
  135.                 'referenceUnitPrice' => $referencePrice,
  136.                 'referenceUnitName' => $referenceUnitName,
  137.                 'referenceUnit' => $referenceUnit,
  138.                 'inStock' => $stock,
  139.                 'options' => $variantOptions,
  140.                 'deliveryTime' => $deliveryTime,
  141.                 'id' => $sibling->getId(),
  142.                 'available' => $sibling->getAvailable(),
  143.                 'minPurchase' => $sibling->getMinPurchase(),
  144.                 'purchaseSteps' => $sibling->getPurchaseSteps(),
  145.                 'availableStock' => $sibling->getAvailableStock(),
  146.                 'translated' => $sibling->getTranslated(),
  147.                 'restockTime' => $sibling->getRestockTime(),
  148.                 'deliveryTimeTranslation' => $deliveryTime
  149.             ];
  150.         }
  151.         // Sorts the variants by position to match the order of the Configurator options
  152.         ksort($variants);
  153.         // The array is passed to the page and can be found at page.extensions.allVariants.
  154.         $event
  155.             ->getPage()
  156.             ->assign(['allVariants'=> $variants]);
  157.     }
  158.     /**
  159.      * Determines the variants and all associated information based on the passed parentId.
  160.      *
  161.      * @param string $parent
  162.      * @param SalesChannelContext $context
  163.      * @return ProductEntity|null
  164.      */
  165.     private function getSiblings(
  166.         string $parent,
  167.         SalesChannelContext $context
  168.     ): ?EntitySearchResult {
  169.         $criteria = new Criteria();
  170.         $criteria
  171.             ->addFilter(new EqualsFilter('parentId'$parent))
  172.             ->addAssociation('manufacturer.media')
  173.             ->addAssociation('options.group')
  174.             ->addAssociation('properties.group')
  175.             ->addAssociation('mainCategories.category')
  176.             ->addAssociation('deliveryTime.deliveryTime')
  177.             ->getAssociation('media');
  178.         return $this
  179.             ->productRepository
  180.             ->search($criteria$context);
  181.     }
  182.     /**
  183.      * Sets the order of the Configurator options
  184.      *
  185.      * @param PropertyGroupCollection $configSettings
  186.      * @return array
  187.      */
  188.     private function getPosition(PropertyGroupCollection $configSettings): array {
  189.         $positions = [];
  190.         $i 1;
  191.         foreach ($configSettings as $configSetting) {
  192.             foreach ($configSetting->getOptions() as $index => $option) {
  193.                 $positions[$index] = $i;
  194.                 $i++;
  195.             }
  196.         }
  197.         return $positions;
  198.     }
  199. }