-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #97 from Setono/dispatch-purchase-message
Dispatch message when completing an order to later on send a purchase event to Google Analytics
- Loading branch information
Showing
15 changed files
with
229 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/EventSubscriber/DispatchSendPurchaseRequestSubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusAnalyticsPlugin\EventSubscriber; | ||
|
||
use Setono\GoogleAnalyticsBundle\Context\ClientIdContextInterface; | ||
use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\PurchaseEvent; | ||
use Setono\SyliusAnalyticsPlugin\Message\Command\SendPurchaseEvent; | ||
use Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolverInterface; | ||
use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; | ||
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; | ||
use Sylius\Component\Core\Model\OrderInterface; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\Messenger\Envelope; | ||
use Symfony\Component\Messenger\MessageBusInterface; | ||
use Symfony\Component\Messenger\Stamp\DelayStamp; | ||
use Webmozart\Assert\Assert; | ||
|
||
final class DispatchSendPurchaseRequestSubscriber implements EventSubscriberInterface | ||
{ | ||
use FormatAmountTrait; | ||
|
||
private ClientIdContextInterface $clientIdContext; | ||
|
||
private MessageBusInterface $commandBus; | ||
|
||
private ItemsResolverInterface $itemsResolver; | ||
|
||
private int $delay; | ||
|
||
public function __construct(ClientIdContextInterface $clientIdContext, MessageBusInterface $commandBus, ItemsResolverInterface $itemsResolver, int $delay = 43_200) | ||
{ | ||
$this->clientIdContext = $clientIdContext; | ||
$this->commandBus = $commandBus; | ||
$this->itemsResolver = $itemsResolver; | ||
$this->delay = $delay; | ||
} | ||
|
||
public static function getSubscribedEvents(): array | ||
{ | ||
return [ | ||
'sylius.order.post_complete' => 'dispatch', | ||
]; | ||
} | ||
|
||
public function dispatch(ResourceControllerEvent $event): void | ||
{ | ||
$order = $event->getSubject(); | ||
if (!$order instanceof OrderInterface) { | ||
return; | ||
} | ||
|
||
$clientId = $this->clientIdContext->getClientId(); | ||
if (null === $clientId) { | ||
return; | ||
} | ||
|
||
$channel = $order->getChannel(); | ||
Assert::notNull($channel); | ||
|
||
$this->commandBus->dispatch(new Envelope( | ||
new SendPurchaseEvent( | ||
PurchaseEvent::create((string) $order->getNumber()) | ||
->setAffiliation(sprintf( | ||
'%s (%s)', | ||
(string) $channel->getName(), | ||
(string) $order->getLocaleCode(), | ||
)) | ||
->setValue(self::formatAmount($order->getTotal())) | ||
->setCurrency($order->getCurrencyCode()) | ||
->setTax(self::formatAmount($order->getTaxTotal())) | ||
->setShipping(self::formatAmount($order->getShippingTotal())) | ||
->setItems($this->itemsResolver->resolveFromOrder($order)), | ||
(int) $order->getId(), | ||
$clientId | ||
), | ||
[new DelayStamp($this->delay)] | ||
)); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusAnalyticsPlugin\Message\Command; | ||
|
||
interface CommandInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusAnalyticsPlugin\Message\Command; | ||
|
||
use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\PurchaseEvent; | ||
|
||
final class SendPurchaseEvent implements CommandInterface | ||
{ | ||
public PurchaseEvent $event; | ||
|
||
public int $orderId; | ||
|
||
public string $clientId; | ||
|
||
public function __construct(PurchaseEvent $event, int $orderId, string $clientId) | ||
{ | ||
$this->event = $event; | ||
$this->orderId = $orderId; | ||
$this->clientId = $clientId; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusAnalyticsPlugin\Message\Handler; | ||
|
||
use Psr\EventDispatcher\EventDispatcherInterface; | ||
use Setono\GoogleAnalyticsBundle\Event\ServerSideEvent; | ||
use Setono\GoogleAnalyticsBundle\ValueObject\Property; | ||
use Setono\SyliusAnalyticsPlugin\Message\Command\SendPurchaseEvent; | ||
use Setono\SyliusAnalyticsPlugin\Repository\PropertyRepositoryInterface; | ||
use Sylius\Component\Core\Model\OrderInterface; | ||
use Sylius\Component\Core\OrderCheckoutStates; | ||
use Sylius\Component\Core\OrderPaymentStates; | ||
use Sylius\Component\Order\Repository\OrderRepositoryInterface; | ||
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; | ||
use Webmozart\Assert\Assert; | ||
|
||
/** | ||
* NOT final to make it easy to decorate and extend this handler | ||
* | ||
* todo this only works with gtag enabled and not tag manager | ||
*/ | ||
class SendPurchaseEventHandler | ||
{ | ||
private OrderRepositoryInterface $orderRepository; | ||
|
||
private PropertyRepositoryInterface $propertyRepository; | ||
|
||
private EventDispatcherInterface $eventDispatcher; | ||
|
||
public function __construct(OrderRepositoryInterface $orderRepository, PropertyRepositoryInterface $propertyRepository, EventDispatcherInterface $eventDispatcher) | ||
{ | ||
$this->orderRepository = $orderRepository; | ||
$this->propertyRepository = $propertyRepository; | ||
$this->eventDispatcher = $eventDispatcher; | ||
} | ||
|
||
public function __invoke(SendPurchaseEvent $message): void | ||
{ | ||
$order = $this->orderRepository->find($message->orderId); | ||
if (!$order instanceof OrderInterface) { | ||
throw new UnrecoverableMessageHandlingException(sprintf( | ||
'The order with id %d does not exist or is not an instance of %s', | ||
$message->orderId, | ||
OrderInterface::class | ||
)); | ||
} | ||
|
||
if (!$this->isEligible($order)) { | ||
throw new \RuntimeException(sprintf('The order with id %d is not eligible for a Google Analytics purchase event to be sent', $message->orderId)); | ||
} | ||
|
||
$channel = $order->getChannel(); | ||
Assert::notNull($channel); | ||
|
||
$propertyEntities = $this->propertyRepository->findEnabledByChannel($channel); | ||
if ([] === $propertyEntities) { | ||
throw new UnrecoverableMessageHandlingException('You have not defined any Google Analytics properties'); | ||
} | ||
|
||
$properties = []; | ||
foreach ($propertyEntities as $propertyEntity) { | ||
$measurementId = $propertyEntity->getMeasurementId(); | ||
$apiSecret = $propertyEntity->getApiSecret(); | ||
|
||
if (null === $measurementId || null === $apiSecret) { | ||
continue; | ||
} | ||
|
||
$properties[] = new Property($measurementId, $apiSecret); | ||
} | ||
|
||
$this->eventDispatcher->dispatch(new ServerSideEvent($message->event, $message->clientId, $properties)); | ||
} | ||
|
||
protected function isEligible(OrderInterface $order): bool | ||
{ | ||
return in_array($order->getPaymentState(), [OrderPaymentStates::STATE_AUTHORIZED, OrderPaymentStates::STATE_PAID], true) && $order->getCheckoutState() === OrderCheckoutStates::STATE_COMPLETED; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
|
||
<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://symfony.com/schema/dic/services" | ||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | ||
<services> | ||
<service id="setono_sylius_analytics.message.handler.send_purchase_request" | ||
class="Setono\SyliusAnalyticsPlugin\Message\Handler\SendPurchaseEventHandler"> | ||
<argument type="service" id="sylius.repository.order"/> | ||
<argument type="service" id="setono_sylius_analytics.repository.property"/> | ||
<argument type="service" id="event_dispatcher"/> | ||
|
||
<tag name="messenger.message_handler"/> | ||
</service> | ||
</services> | ||
</container> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.