vendor/store.shopware.com/netzpevents6/src/Subscriber/FrontendSubscriber.php line 352

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