custom/plugins/NetzpEvents6/src/Subscriber/FrontendSubscriber.php line 126

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace NetzpEvents6\Subscriber;
  3. use NetzpEvents6\Components\EventsHelper;
  4. use NetzpEvents6\Components\SlotStruct;
  5. use NetzpEvents6\Components\TicketDocumentGenerator;
  6. use NetzpEvents6\Core\SearchResult;
  7. use Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent;
  8. use Shopware\Core\Checkout\Cart\Event\BeforeLineItemQuantityChangedEvent;
  9. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  10. use Shopware\Core\Checkout\Cart\Order\CartConvertedEvent;
  11. use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
  12. use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
  13. use Shopware\Core\Content\Product\Events\ProductSuggestCriteriaEvent;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  20. use Shopware\Core\Framework\Struct\ArrayStruct;
  21. use Shopware\Core\Framework\Uuid\Uuid;
  22. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  23. use Shopware\Core\System\SystemConfig\SystemConfigService;
  24. use Shopware\Storefront\Controller\CartLineItemController;
  25. use Shopware\Storefront\Page\Account\Order\AccountOrderPageLoadedEvent;
  26. use Shopware\Storefront\Page\Product\ProductPageCriteriaEvent;
  27. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  28. use Symfony\Component\DependencyInjection\ContainerInterface;
  29. use Symfony\Component\HttpFoundation\RequestStack;
  30. use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
  31. use Shopware\Core\Checkout\Order\Event\OrderStateMachineStateChangeEvent;
  32. use Shopware\Core\Framework\Struct;
  33. use Symfony\Contracts\EventDispatcher\Event;
  34. use NetzpEvents6\Core\Content\Participant\ParticipantEntity;
  35. class FrontendSubscriber implements EventSubscriberInterface
  36. {
  37.     const SEARCH_TYPE_EVENTS 11;
  38.     private $container;
  39.     private $config;
  40.     private $requestStack;
  41.     private $helper;
  42.     private $withoutParticipants;
  43.     public function __construct(
  44.         ContainerInterface $container,
  45.         SystemConfigService $config,
  46.         RequestStack $requestStack,
  47.         EventsHelper $helper
  48.     ) {
  49.         $this->container $container;
  50.         $this->config $config;
  51.         $this->requestStack $requestStack;
  52.         $this->helper $helper;
  53.         $pluginConfig $this->config->get('NetzpEvents6.config');
  54.         $this->withoutParticipants = (bool)$pluginConfig['anonymous'];
  55.     }
  56.     public static function getSubscribedEvents(): array
  57.     {
  58.         return [
  59.             ProductPageCriteriaEvent::class            => 'onProductCriteriaLoaded',
  60.             ProductListingCriteriaEvent::class         => 'onProductListingCriteria',
  61.             ProductSearchCriteriaEvent::class          => 'onSearchCriteria',
  62.             ProductSuggestCriteriaEvent::class         => 'onSuggestCriteria',
  63.             BeforeLineItemAddedEvent::class            => 'onLineItemAdded',
  64.             BeforeLineItemQuantityChangedEvent::class  => 'onLineItemUpdated',
  65.             CartConvertedEvent::class                  => 'onCartConverted',
  66.             CheckoutOrderPlacedEvent::class            => 'onOrderPlaced',
  67.             AccountOrderPageLoadedEvent::class         => 'onOrderLoaded',
  68.             ControllerArgumentsEvent::class            => 'onControllerEvent',
  69.             'state_enter.order.state.cancelled'        => 'orderStateCanceled',
  70.             'netzp.search.register'                    => 'registerSearchProvider'
  71.         ];
  72.     }
  73.     public function onOrderLoaded(AccountOrderPageLoadedEvent $event)
  74.     {
  75.         $repo $this->container->get('document.repository');
  76.         $repoDocumentType $this->container->get('document_type.repository');
  77.         $criteria = new Criteria();
  78.         $criteria->addFilter(new EqualsFilter('technicalName'TicketDocumentGenerator::EVENT_TICKET));
  79.         $documentType $repoDocumentType->search($criteria$event->getContext())->first();
  80.         if( ! $documentType) {
  81.             return;
  82.         }
  83.         foreach ($event->getPage()->getOrders() as $order) {
  84.             $criteria = new Criteria();
  85.             $criteria->addFilter(new EqualsFilter('orderId'$order->getId()));
  86.             $criteria->addFilter(new EqualsFilter('documentTypeId'$documentType->getId()));
  87.             $document $repo->search($criteria$event->getContext())->first();
  88.             if($document) {
  89.                 $order->addExtension('ticket',
  90.                     new Struct\ArrayStruct(['id' => $document->getId(), 'deeplinkCode' => $document->getDeeplinkCode()])
  91.                 );
  92.             }
  93.         }
  94.     }
  95.     public function onProductCriteriaLoaded(ProductPageCriteriaEvent $event): void
  96.     {
  97.         $this->addCriteria($eventtrue);
  98.     }
  99.     public function onProductListingCriteria(ProductListingCriteriaEvent $event): void
  100.     {
  101.         $this->addCriteria($event);
  102.     }
  103.     public function onSearchCriteria(ProductSearchCriteriaEvent $event): void
  104.     {
  105.         $this->addCriteria($event);
  106.     }
  107.     public function onSuggestCriteria(ProductSuggestCriteriaEvent $event): void
  108.     {
  109.         $this->addCriteria($event);
  110.     }
  111.     private function addCriteria($eventbool $addFilter false)
  112.     {
  113.         $criteria $event->getCriteria();
  114.         $criteria->addAssociation('event');
  115.         $criteria->addAssociation('event.slots');
  116.         $criteria->addAssociation('eventparent');
  117.         $criteria->addAssociation('eventparent.slots');
  118.         if($addFilter) {
  119.             $bookingPeriod 'start';
  120.             $pluginConfig $this->config->get('NetzpEvents6.config');
  121.             if(array_key_exists('bookingperiod'$pluginConfig)) {
  122.                 $bookingPeriod $pluginConfig['bookingperiod'];
  123.             }
  124.             $now $this->helper->getCurrentDateTimeFormatted($this->requestStack);
  125.             $slots $criteria->getAssociation('event')->getAssociation('slots');
  126.             if($bookingPeriod == 'end') {
  127.                 $slots->addFilter(new RangeFilter('until', ['gte' => $now]));
  128.             }
  129.             else {
  130.                 $slots->addFilter(new RangeFilter('from', ['gt' => $now]));
  131.             }
  132.             $slots->addFilter(new EqualsFilter('active'1));
  133.             $slots->addSorting(new FieldSorting('from''ASC'));
  134.             $slotsParent $criteria->getAssociation('eventparent')->getAssociation('slots');
  135.             if($bookingPeriod == 'end') {
  136.                 $slotsParent->addFilter(new RangeFilter('until', ['gte' => $now]));
  137.             }
  138.             else {
  139.                 $slotsParent->addFilter(new RangeFilter('from', ['gt' => $now]));
  140.             }
  141.             $slotsParent->addFilter(new EqualsFilter('active'1));
  142.             $slotsParent->addSorting(new FieldSorting('from''ASC'));
  143.         }
  144.     }
  145.     public function onLineItemAdded(BeforeLineItemAddedEvent $event)
  146.     {
  147.         $lineItem $event->getLineItem();
  148.         $request $this->requestStack->getCurrentRequest()->request;
  149.         if ($request->has('netzpEventId')) {
  150.             $eventId $request->get('netzpEventId');
  151.             $repo $this->container->get('s_plugin_netzp_events_slots.repository');
  152.             $criteria = new Criteria([$eventId]);
  153.             $criteria->addAssociation('event');
  154.             $netzpEventSlot $repo->search($criteria$event->getContext())->getEntities()->first();
  155.             if($netzpEventSlot) {
  156.                 $dateFrom $netzpEventSlot->getFrom() ?
  157.                                 $netzpEventSlot->getFrom()->format(\DateTimeInterface::ATOM) :
  158.                                 '';
  159.                 $dateUntil $netzpEventSlot->getUntil() ?
  160.                                 $netzpEventSlot->getUntil()->format(\DateTimeInterface::ATOM) :
  161.                                 '';
  162.                 $slot = new SlotStruct();
  163.                 $slot->setId($netzpEventSlot->getId());
  164.                 $slot->setTitle($netzpEventSlot->getEvent()->getTranslated()['title']);
  165.                 $slot->setLocation($netzpEventSlot->getTranslated()['location']);
  166.                 $slot->setAddress($netzpEventSlot->getTranslated()['address']);
  167.                 $slot->setFrom($dateFrom);
  168.                 $slot->setUntil($dateUntil);
  169.                 $slot->setAvailable($netzpEventSlot->getTicketsAvailable() - $netzpEventSlot->getTicketsBooked());
  170.                 if($this->withoutParticipants) {
  171.                     $participants = [];
  172.                     $participantsIds = [];
  173.                     for($i 1$i <= $lineItem->getQuantity(); $i++) {
  174.                         $participants[$i] = '(' $i ')';
  175.                         $participantsIds[$i] = Uuid::randomHex();
  176.                     }
  177.                     $slot->setParticipants($participants);
  178.                     $slot->setParticipantsIds($participantsIds);
  179.                 }
  180.                 $lineItem->setPayloadValue('netzp_event'$slot->getVars());
  181.             }
  182.         }
  183.     }
  184.     public function onLineItemUpdated(BeforeLineItemQuantityChangedEvent $event)
  185.     {
  186.         $lineItem $event->getLineItem();
  187.         $request $this->requestStack->getCurrentRequest()->request;
  188.         if ($lineItem->hasPayloadValue('netzp_event')) {
  189.             if($this->withoutParticipants) {
  190.                 $participants = [];
  191.                 $participantsIds = [];
  192.                 for($i 1$i <= $lineItem->getQuantity(); $i++) {
  193.                     $participants[$i] = '(' $i ')';
  194.                     $participantsIds[$i] = Uuid::randomHex();
  195.                 }
  196.                 $payload $lineItem->getPayloadValue('netzp_event');
  197.                 $payload['participants'] = $participants;
  198.                 $payload['participantsIds'] = $participantsIds;
  199.                 $lineItem->setPayloadValue('netzp_event'$payload);
  200.             }
  201.             else if($request->has('netzpEventParticipant')) {
  202.                 $participants $request->get('netzpEventParticipant');
  203.                 $participantsIds = [];
  204.                 $n 1;
  205.                 foreach($participants as $participant) {
  206.                     $participantsIds[$n] = Uuid::randomHex();
  207.                     $n++;
  208.                 }
  209.                 $payload $lineItem->getPayloadValue('netzp_event');
  210.                 $payload['participants'] = $participants;
  211.                 $payload['participantsIds'] = $participantsIds;
  212.                 $lineItem->setPayloadValue('netzp_event'$payload);
  213.             }
  214.         }
  215.     }
  216.     public function onControllerEvent(ControllerArgumentsEvent $event): void
  217.     {
  218.         $controller $event->getController();
  219.         $route $event->getRequest()->get('_route') ?? '';
  220.         if (is_array($controller) && count($controller) > 0) {
  221.             $controller $controller[0];
  222.         }
  223.         if ( ! $controller) return;
  224.         if($controller instanceof CartLineItemController &&
  225.            $route === 'frontend.checkout.line-item.add')
  226.         {
  227.             $args $event->getArguments();
  228.             // prevent article stacking only for events
  229.             if(count($args) >= && $event->getRequest()->get('netzpEventId''') != '') {
  230.                 $keys $args[1]->get('lineItems')->keys();
  231.                 if($keys && is_array($keys) && count($keys) > 0) {
  232.                     $lineItem $args[1]->get('lineItems')->get($keys[0]);
  233.                     if ($lineItem) {
  234.                         $lineItem->set('id'Uuid::randomHex());
  235.                         $event->setArguments($args);
  236.                     }
  237.                 }
  238.             }
  239.         }
  240.     }
  241.     public function onCartConverted(CartConvertedEvent $event)
  242.     {
  243.         $cart $event->getCart();
  244.         $lineItems $cart->getLineItems();
  245.         foreach($lineItems as $lineItem) {
  246.             if($lineItem->hasPayloadValue('netzp_event')) {
  247.                 $this->helper->processEvent($lineItem$event->getContext());
  248.             }
  249.         }
  250.     }
  251.     public function onOrderPlaced(CheckoutOrderPlacedEvent $event)
  252.     {
  253.         $this->helper->processOrder($event);
  254.     }
  255.     public function orderStateCanceled(OrderStateMachineStateChangeEvent $event)
  256.     {
  257.         $repoSlots $this->container->get('s_plugin_netzp_events_slots.repository');
  258.         $repoParticipants $this->container->get('s_plugin_netzp_events_participants.repository');
  259.         $context $event->getContext();
  260.         $lineItems $event->getOrder()->getLineItems();
  261.         foreach($lineItems as $lineItem) {
  262.             $payload $lineItem->getPayload();
  263.             if(array_key_exists('netzp_event'$payload)) {
  264.                 $ticket $payload['netzp_event'];
  265.                 $criteria = new Criteria([$ticket['id']]);
  266.                 $criteria->addAssociations(['event''participants''event.product']);
  267.                 $slot $repoSlots->search($criteria$context)->getEntities()->first();
  268.                 $numberOfParticipants count($ticket['participants']);
  269.                 $newTicketsBooked $slot->getTicketsBooked() - $numberOfParticipants;
  270.                 $repoSlots->update([
  271.                     [
  272.                         'id'            => $slot->getId(),
  273.                         'ticketsBooked' => $newTicketsBooked
  274.                     ]
  275.                 ], $context);
  276.                 $this->helper->invalidateProductCache($slot->getEvent()->getProductid());
  277.                 $this->helper->invalidateEventListing();
  278.                 foreach($ticket['participants'] as $participantNo => $participant) {
  279.                     $participantId $ticket['participantsIds'][$participantNo];
  280.                     $repoParticipants->update([
  281.                         [
  282.                             'id'     => $participantId,
  283.                             'status' => ParticipantEntity::STATUS_CANCELED
  284.                         ]
  285.                     ], $context);
  286.                 }
  287.             }
  288.         }
  289.     }
  290.     public function registerSearchProvider(Event $event)
  291.     {
  292.         $pluginConfig $this->config->get('NetzpEvents6.config');
  293.         if((bool)$pluginConfig['searchEvents'] === false) {
  294.             return;
  295.         }
  296.         $event->setData([
  297.             'key'      => 'events',
  298.             'label'    => 'netzp.events.searchLabel',
  299.             'function' => [$this'doSearch']
  300.         ]);
  301.     }
  302.     public function doSearch(string $querySalesChannelContext $salesChannelContextbool $isSuggest false): array
  303.     {
  304.         $results = [];
  305.         $events $this->getEvents($query$salesChannelContext$isSuggest);
  306.         if($events == null) {
  307.             return [];
  308.         }
  309.         foreach ($events->getEntities() as $event) {
  310.             if( ! $event->getProduct()) continue;
  311.             $tmpResult = new SearchResult();
  312.             $tmpResult->setType(static::SEARCH_TYPE_EVENTS);
  313.             $tmpResult->setId($event->getId());
  314.             $tmpResult->setTitle($event->getTranslated()['title'] ?? '');
  315.             $tmpResult->setDescription($event->getTranslated()['teaser'] ?? '');
  316.             $tmpResult->setMedia($event->getImage());
  317.             $tmpResult->setTotal($events->getTotal());
  318.             $tmpResult->addExtension('productId', new ArrayStruct(['value' => $event->getProduct()->getId()]));
  319.             $tmpResult->addExtension('slots', new ArrayStruct(['value' => $event->getSlots()->count()]));
  320.             $results[] = $tmpResult;
  321.         }
  322.         return $results;
  323.     }
  324.     private function getEvents($querySalesChannelContext $salesChannelContextbool $isSuggest false)
  325.     {
  326.         $query trim($query);
  327.         $words explode(' '$query);
  328.         if (count($words) > 0) {
  329.             $now $this->helper->getCurrentDateTimeFormatted($this->requestStack);
  330.             $repo $this->container->get('s_plugin_netzp_events.repository');
  331.             $criteria = new Criteria();
  332.             $criteria->addAssociation('product');
  333.             $criteria->addAssociation('image');
  334.             $criteria->addAssociation('event.slots');
  335.             $slots $criteria->getAssociation('slots');
  336.             $slots->addSorting(new FieldSorting('from''ASC'));
  337.             $slots->addFilter(new RangeFilter('from', ['gt' => $now]));
  338.             $slots->addFilter(new EqualsFilter('active'true));
  339.             $criteria->addSorting(new FieldSorting('title'FieldSorting::ASCENDING));
  340.             $criteria->addFilter(new EqualsFilter('bookable'true));
  341.             $filter = [];
  342.             foreach ($words as $word) {
  343.                 $filter[] = new ContainsFilter('title'$word);
  344.                 $filter[] = new ContainsFilter('teaser'$word);
  345.                 $filter[] = new ContainsFilter('description'$word);
  346.             }
  347.             $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR$filter));
  348.             return $repo->search($criteria$salesChannelContext->getContext());
  349.         }
  350.         return null;
  351.     }
  352. }