<?php
namespace App\Service;
use CoreShop\Bundle\TrackingBundle\Tracker\AbstractEcommerceTracker;
use Pimcore\Model\DataObject\CoreShopProduct;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Twig\Environment;
class CustomGA4Ecommerce extends AbstractEcommerceTracker
{
private ?RequestStack $requestStack;
public function __construct(Environment $twig, array $options = [], bool $enabled = false, RequestStack $requestStack = null)
{
parent::__construct($twig, $options);
$this->setEnabled($enabled);
$this->requestStack = $requestStack;
}
protected function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);
$resolver->setDefaults(['template_prefix' => '@CoreShopFrontend/Tracking/ga4tm']);
$this->setEnabled(true);
}
public function trackProduct($product): void
{
$parameters = [];
$actionData = [
'items' => [$this->transformProductAction($product)],
];
$parameters['actionData'] = $actionData;
//unset($parameters['actionData']['quantity']);
$this->buildCode($this->renderTemplate('product_view', $parameters));
}
public function trackProductImpression($product): void
{
$parameters = [];
if (isset($product['itemlist']) && is_iterable($product['itemlist'])) {
$actionData = [];
foreach ($product['itemlist'] as $item) {
$actionData[] = $this->transformProductAction($this->convertProductToArray($item));
}
$parameters['actionData'] = [
'item_list_id' => $product['item_list_id'] ?? '',
'item_list_name' => $product['item_list_name'] ?? '',
'items' => $actionData
];
} else {
$actionData = [
'currency' => $product['currency'] ?? null,
'value' => $product['price'] ?? 0,
'items' => [$this->transformProductAction($product)],
];
$parameters['actionData'] = $actionData;
}
//unset($parameters['actionData']['quantity']);
$parameters['event'] = $product['event'] ?? 'product_impression';
$this->buildCode($this->renderTemplate('product_action', $parameters));
}
public function trackCartAdd($cart, $product, float $quantity = 1.0): void
{
$this->trackCartAction($product, 'add', $quantity);
}
public function trackCartRemove($cart, $product, float $quantity = 1.0): void
{
$this->trackCartAction($product, 'remove', $quantity);
}
public function trackCheckoutStep($cart, $stepIdentifier = null, bool $isFirstStep = false, $checkoutOption = null): void
{
$parameters = [];
$actionData = [];
$actionData['items'] = $cart['items'];
$actionData['currency'] = $cart['currency'];
$actionData['value'] = $cart['total'];
if (null !== $stepIdentifier || null !== $checkoutOption) {
$actionData['checkout_step'] = $stepIdentifier + 1;
if (!empty($cart['voucher'])) {
$actionData['coupon'] = $cart['voucher'];
}
}
$parameters['actionData'] = $actionData;
$parameters['event'] = $isFirstStep === true ? 'begin_checkout' : 'checkout_progress';
$this->buildCode($this->renderTemplate('checkout', $parameters));
}
public function trackCheckoutComplete($order): void
{
$orderData = $this->transformOrder($order);
$actionData = array_merge($orderData, ['items' => $order['items'] ?? []]);
$parameters = [];
$parameters['actionData'] = $actionData;
$this->buildCode($this->renderTemplate('checkout_complete', $parameters));
}
protected function trackCartAction($product, $action, float $quantity = 1.0): void
{
$product = $this->transformProductAction($product);
$product['quantity'] = $quantity;
$parameters = [];
$actionData = ['currency' => $product['currency'] ?? null, 'value' => $product['price'] * $quantity, 'items' => []];
$actionData['items'][] = $product;
$parameters['actionData'] = $actionData;
$parameters['event'] = $action === 'remove' ? 'remove_from_cart' : 'add_to_cart';
$this->buildCode($this->renderTemplate('product_action', $parameters));
}
protected function transformOrder(array $actionData): array
{
return [
'transaction_id' => $actionData['id'],
// 'affiliation' => $actionData['affiliation'] ?: '',
'value' => $actionData['total'],
'tax' => $actionData['totalTax'],
'shipping' => $actionData['shipping'],
'currency' => $actionData['currency'],
];
}
protected function transformProductAction(array $item): array
{
if (!$item) {
return [];
}
$product = CoreShopProduct::getById((int)$item['id']);
$categoriesArray = [];
if ($product instanceof CoreShopProduct) {
$i = 2;
foreach ($product->getCategories() as $category) {
if (empty($categoriesArray)) {
$categoriesArray['item_category'] = $category->getName();
} else {
$categoriesArray['item_category' . $i++] = $category->getName();
}
}
$item['brand'] = $product->getBrand();
}
return $this->filterNullValues(array_merge([
'item_id' => $item['id'],
'item_name' => $item['name'],
'item_brand' => $item['brand'] ?? null,
'item_variant' => $item['variant'] ?? null,
'price' => round($item['price'], 2),
'quantity' => $item['quantity'] ?? 1,
'index' => $item['position'] ?? null,
'currency' => $item['currency'],
'item_gender' => $item['gender'] ?? null,
'item_collection' => $item['collection'] ?? null,
'item_subcollection' => $item['subcollection'] ?? null
], $categoriesArray));
}
protected function buildCheckoutCalls(array $items): array
{
$calls = [];
foreach ($items as $item) {
$calls[] = $this->transformProductAction($item);
}
return $calls;
}
protected function buildCode(string $code): void
{
if (!$code) {
return;
}
$session = $this->requestStack?->getSession();
if (!$session instanceof SessionInterface) {
return;
}
if ($session->has('TRACKER_CODE')) {
$code = $session->get('TRACKER_CODE') . "\n\n\n" . $code;
}
$session->set('TRACKER_CODE', $code);
}
private function convertProductToArray(CoreShopProduct $product): array
{
return [
'id' => $product->getId(),
'name' => $product->getName(),
'category' => $product->getCategories(),
'brand' => $product->getBrand(),
'variant' => null,
'price' => $product->getWholeSalePrice() / 100,
'quantity' => 1,
'index' => null,
'currency' => 'HUF',
'collection' => $product->getCollection(),
'subcollection' => $product->getSubCollection(),
'gender' => $product->getTypeofwatch()
];
}
}