custom/plugins/SwagCustomizedProducts/src/Storefront/Page/Product/ProductPageSubscriber.php line 122

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. /*
  3.  * (c) shopware AG <info@shopware.com>
  4.  * For the full copyright and license information, please view the LICENSE
  5.  * file that was distributed with this source code.
  6.  */
  7. namespace Swag\CustomizedProducts\Storefront\Page\Product;
  8. use Shopware\Core\Content\Media\MediaEntity;
  9. use Shopware\Core\Content\Product\ProductEntity;
  10. use Shopware\Core\Framework\Context;
  11. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  14. use Shopware\Core\Framework\Uuid\Uuid;
  15. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  16. use Swag\CustomizedProducts\Core\Content\Product\ProductWrittenSubscriber;
  17. use Swag\CustomizedProducts\Migration\Migration1565933910TemplateProduct;
  18. use Swag\CustomizedProducts\Storefront\Page\Product\Extensions\EditConfigurationExtension;
  19. use Swag\CustomizedProducts\Storefront\Page\Product\Extensions\ShareConfigurationExtension;
  20. use Swag\CustomizedProducts\Template\Aggregate\TemplateConfiguration\Aggregate\TemplateConfigurationShareEntity;
  21. use Swag\CustomizedProducts\Template\Aggregate\TemplateConfiguration\Service\TemplateConfigurationService;
  22. use Swag\CustomizedProducts\Template\Aggregate\TemplateConfiguration\TemplateConfigurationEntity;
  23. use Swag\CustomizedProducts\Template\SalesChannel\Price\PriceService;
  24. use Swag\CustomizedProducts\Template\TemplateEntity;
  25. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  26. use Symfony\Component\HttpFoundation\Session\Session;
  27. use Symfony\Contracts\Translation\TranslatorInterface;
  28. class ProductPageSubscriber implements EventSubscriberInterface
  29. {
  30.     public const EDIT_CONFIGURATION_PARAMETER 'swagCustomizedProductsConfigurationEdit';
  31.     public const SHARE_CONFIGURATION_PARAMETER 'swagCustomizedProductsConfigurationShare';
  32.     /**
  33.      * @var EntityRepositoryInterface
  34.      */
  35.     private $productRepository;
  36.     /**
  37.      * @var PriceService
  38.      */
  39.     private $priceService;
  40.     /**
  41.      * @var EntityRepositoryInterface
  42.      */
  43.     private $configurationRepository;
  44.     /**
  45.      * @var EntityRepositoryInterface
  46.      */
  47.     private $configurationShareRepository;
  48.     /**
  49.      * @var Session
  50.      */
  51.     private $session;
  52.     /**
  53.      * @var TranslatorInterface
  54.      */
  55.     private $translator;
  56.     /**
  57.      * @var TemplateConfigurationService
  58.      */
  59.     private $configurationService;
  60.     /**
  61.      * @var EntityRepositoryInterface
  62.      */
  63.     private $mediaRepository;
  64.     public function __construct(
  65.         EntityRepositoryInterface $productRepository,
  66.         PriceService $priceService,
  67.         EntityRepositoryInterface $configurationRepository,
  68.         EntityRepositoryInterface $configurationShareRepository,
  69.         Session $session,
  70.         TranslatorInterface $translator,
  71.         TemplateConfigurationService $configurationService,
  72.         EntityRepositoryInterface $mediaRepository
  73.     ) {
  74.         $this->productRepository $productRepository;
  75.         $this->priceService $priceService;
  76.         $this->configurationRepository $configurationRepository;
  77.         $this->configurationShareRepository $configurationShareRepository;
  78.         $this->session $session;
  79.         $this->translator $translator;
  80.         $this->configurationService $configurationService;
  81.         $this->mediaRepository $mediaRepository;
  82.     }
  83.     public static function getSubscribedEvents(): array
  84.     {
  85.         return [
  86.             ProductPageLoadedEvent::class => [
  87.                 ['addMediaToTemplate'500],
  88.                 ['removeCustomizedProductsTemplateFromNoneInheritedVariant'400],
  89.                 ['enrichOptionPriceAbleDisplayPrices'300],
  90.                 ['addEditConfigurationExtension'200],
  91.                 ['addShareConfigurationExtension'100],
  92.             ],
  93.         ];
  94.     }
  95.     /**
  96.      * @deprecated tag:v4.0.0 Will be removed use addMediaToTemplate instead.
  97.      */
  98.     public function addCustomizedProductsDetailAssociations(ProductPageLoadedEvent $event): void
  99.     {
  100.         $this->addMediaToTemplate($event);
  101.     }
  102.     /**
  103.      * Please bear in mind, that the SalesChannelProductRepository gets decorated here: Swag\CustomizedProducts\Core\Content\Product\SalesChannel\SalesChannelProductRepositoryDecorator
  104.      * And that the SalesChannelTemplateDefinition requires all associations except the media per default here: Swag\CustomizedProducts\Template\SalesChannel\SalesChannelTemplateDefinition::processCriteria
  105.      * For better performance we only load the media once its needed on the product detail page.
  106.      */
  107.     public function addMediaToTemplate(ProductPageLoadedEvent $event): void
  108.     {
  109.         try {
  110.             /** @var TemplateEntity|null $template */
  111.             $template $event->getPage()
  112.                 ->getProduct()
  113.                 ->get(Migration1565933910TemplateProduct::PRODUCT_TEMPLATE_INHERITANCE_COLUMN);
  114.         } catch (\InvalidArgumentException $e) {
  115.             return;
  116.         }
  117.         if ($template === null) {
  118.             return;
  119.         }
  120.         $criteria = new Criteria();
  121.         $criteria->setLimit(1);
  122.         $criteria->addFilter(
  123.             new EqualsFilter('swagCustomizedProductsTemplate.id'$template->getId())
  124.         );
  125.         /** @var MediaEntity|null $media */
  126.         $media $this->mediaRepository->search($criteria$event->getSalesChannelContext()->getContext())->first();
  127.         if ($media === null) {
  128.             return;
  129.         }
  130.         $template->setMediaId($media->getId());
  131.         $template->setMedia($media);
  132.     }
  133.     public function removeCustomizedProductsTemplateFromNoneInheritedVariant(ProductPageLoadedEvent $event): void
  134.     {
  135.         $product $event->getPage()->getProduct();
  136.         $parentId $product->getParentId();
  137.         if ($parentId === null) {
  138.             return;
  139.         }
  140.         $customFields $product->getCustomFields();
  141.         if ($customFields === null
  142.             || !\array_key_exists(ProductWrittenSubscriber::SWAG_CUSTOMIZED_PRODUCTS_TEMPLATE_INHERITED_CUSTOM_FIELD$customFields)
  143.         ) {
  144.             return;
  145.         }
  146.         if ($customFields[ProductWrittenSubscriber::SWAG_CUSTOMIZED_PRODUCTS_TEMPLATE_INHERITED_CUSTOM_FIELD]) {
  147.             return;
  148.         }
  149.         if ($this->variantHasOwnTemplateAssigned($product->getId(), $event->getContext())) {
  150.             return;
  151.         }
  152.         $product->removeExtension(Migration1565933910TemplateProduct::PRODUCT_TEMPLATE_INHERITANCE_COLUMN);
  153.     }
  154.     public function enrichOptionPriceAbleDisplayPrices(ProductPageLoadedEvent $event): void
  155.     {
  156.         /** @var TemplateEntity|null $customizedProductsTemplate */
  157.         $customizedProductsTemplate $event->getPage()->getProduct()->getExtension(Migration1565933910TemplateProduct::PRODUCT_TEMPLATE_INHERITANCE_COLUMN);
  158.         if ($customizedProductsTemplate === null) {
  159.             return;
  160.         }
  161.         $this->priceService->calculateCurrencyPrices($customizedProductsTemplate$event->getSalesChannelContext());
  162.     }
  163.     public function addEditConfigurationExtension(ProductPageLoadedEvent $event): void
  164.     {
  165.         $query $event->getRequest()->query;
  166.         if (!$query->has(self::EDIT_CONFIGURATION_PARAMETER)) {
  167.             return;
  168.         }
  169.         $configurationId $query->getAlnum(self::EDIT_CONFIGURATION_PARAMETER);
  170.         if (!Uuid::isValid($configurationId)) {
  171.             return;
  172.         }
  173.         $context $event->getContext();
  174.         $configuration $this->getConfiguration($configurationId$context);
  175.         if ($configuration === null) {
  176.             $this->session->getFlashBag()->add(
  177.                 'info',
  178.                 $this->translator->trans('customizedProducts.configurationEdit.notRestorable')
  179.             );
  180.             return;
  181.         }
  182.         if (!$this->configurationService->isConfigurationFullyRestorable($configuration$context)) {
  183.             $this->session->getFlashBag()->add(
  184.                 'info',
  185.                 $this->translator->trans('customizedProducts.configurationEdit.notFullyRestorable')
  186.             );
  187.         }
  188.         $editConfigurationExtension = (new EditConfigurationExtension())->assign([
  189.             'oldHash' => $configuration->getHash(),
  190.             'configuration' => $configuration->getConfiguration(),
  191.         ]);
  192.         $event->getPage()->addExtension(self::EDIT_CONFIGURATION_PARAMETER$editConfigurationExtension);
  193.     }
  194.     public function addShareConfigurationExtension(ProductPageLoadedEvent $event): void
  195.     {
  196.         $context $event->getContext();
  197.         $query $event->getRequest()->query;
  198.         if (!$query->has(self::SHARE_CONFIGURATION_PARAMETER)) {
  199.             return;
  200.         }
  201.         $shareId $query->getAlnum(self::SHARE_CONFIGURATION_PARAMETER);
  202.         if (!Uuid::isValid($shareId)) {
  203.             return;
  204.         }
  205.         $configurationShare $this->getShare($shareId$context);
  206.         if ($configurationShare === null) {
  207.             $this->session->getFlashBag()->add(
  208.                 'info',
  209.                 $this->translator->trans('customizedProducts.configurationShare.unavailable')
  210.             );
  211.             return;
  212.         }
  213.         $shareConfigurationExtension = (new ShareConfigurationExtension())->assign([
  214.             'configuration' => $configurationShare->getTemplateConfiguration()->getConfiguration(),
  215.         ]);
  216.         $event->getPage()->addExtension(self::SHARE_CONFIGURATION_PARAMETER$shareConfigurationExtension);
  217.         if ($configurationShare->isOneTime()) {
  218.             $this->configurationShareRepository->delete([['id' => $configurationShare->getId()]], $context);
  219.         }
  220.     }
  221.     private function variantHasOwnTemplateAssigned(string $idContext $context): bool
  222.     {
  223.         $considerInheritance $context->considerInheritance();
  224.         $criteria = new Criteria([$id]);
  225.         $criteria->addAssociation(Migration1565933910TemplateProduct::PRODUCT_TEMPLATE_INHERITANCE_COLUMN);
  226.         $criteria->setLimit(1);
  227.         $context->setConsiderInheritance(false);
  228.         /** @var ProductEntity|null $product */
  229.         $product $this->productRepository->search($criteria$context)->first();
  230.         $context->setConsiderInheritance($considerInheritance);
  231.         if ($product === null) {
  232.             return false;
  233.         }
  234.         return $product->hasExtension(Migration1565933910TemplateProduct::PRODUCT_TEMPLATE_INHERITANCE_COLUMN);
  235.     }
  236.     private function getConfiguration(string $configurationIdContext $context): ?TemplateConfigurationEntity
  237.     {
  238.         $criteria = new Criteria([$configurationId]);
  239.         return $this->configurationRepository->search($criteria$context)->first();
  240.     }
  241.     private function getShare(string $shareIdContext $context): ?TemplateConfigurationShareEntity
  242.     {
  243.         $criteria = new Criteria([$shareId]);
  244.         $criteria->addAssociation('templateConfiguration');
  245.         return $this->configurationShareRepository->search($criteria$context)->first();
  246.     }
  247. }