Files
kupshop/bundles/KupShop/GTMBundle/ServerSideGTMEvent/AbstractServerSideGTMEvent.php
2025-08-02 16:30:27 +02:00

249 lines
8.4 KiB
PHP

<?php
namespace KupShop\GTMBundle\ServerSideGTMEvent;
use KupShop\GTMBundle\ServerSideGTMEvent\DataLoaders\Products;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Context\DomainContext;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Context\PriceLevelContext;
use KupShop\KupShopBundle\Context\UserContext;
use KupShop\KupShopBundle\Util\System\AsyncQueue;
use KupShop\OrderingBundle\Event\OrderEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\EventDispatcher\Event;
abstract class AbstractServerSideGTMEvent
{
use AnalyticsSessionIDsTrait;
use FetchUsersStatsOrderData;
public const ContainerConfigPath = '/_kyticka';
private $debugHash;
private $serverUrl;
protected ?Request $request = null;
public function __construct(
protected readonly DomainContext $domainContext,
protected readonly CurrencyContext $currencyContext,
protected readonly LanguageContext $languageContext,
protected readonly UserContext $userContext,
protected readonly Products $productLoader,
protected readonly RequestStack $requestStack,
protected readonly PriceLevelContext $priceLevelContext,
protected readonly LoggerInterface $logger,
protected readonly AsyncQueue $asyncQueue,
) {
$dbCfg = \Settings::getDefault();
$this->setDebugHash($dbCfg['analytics']['google_tag_manager']['debugHash'] ?? false);
$this->setServerUrl($dbCfg['analytics']['google_tag_manager']['serverUrl'] ?? false);
}
public function setDebugHash($hash)
{
$this->debugHash = $hash;
}
public function setServerUrl($url)
{
$this->serverUrl = $url;
}
public static function getContainerConfigPath(): ?string
{
global $cfg;
$hasUrl = $cfg['Addr']['print'] ?? null;
if (findModule(\Modules::GTM, \Modules::SUB_CONTAINER_CONFIG) && $hasUrl) {
return substr($cfg['Addr']['print'], 0, -1).AbstractServerSideGTMEvent::ContainerConfigPath;
}
return null;
}
public function getServerUrl(): string
{
$dbcfg = \Settings::getDefault();
if (
(($dbcfg['analytics']['google_tag_manager']['container_config_ss'] ?? false) === 'Y')
&& ($domain = self::getContainerConfigPath())
) {
return $domain;
}
return $this->serverUrl;
}
public function start(Event $event)
{
$serverUrl = $this->getServerUrl();
if (!$serverUrl) {
return;
}
$payload = $this->getPayload($event);
$payloadJson = json_encode($payload);
// Protože skripty v údržbě končí exit(), tím pádem se tam neprovede async handling
// A takovej divnej if proto, abysme si byli jisti ze to je udrzba, resp. ze to dela superadmin
if (isAdministration() && isSuperuser()) {
$this->sendData($serverUrl, $payloadJson, $this->getHeader());
} else {
$this->sendDataAsync($serverUrl, $payloadJson);
}
$this->logger->notice('[GTM-SS] Purchase payload', $payload);
}
public function setRequest(?Request $request)
{
$this->request = $request;
}
abstract protected function getPayload(Event $event): array;
final protected function sendDataAsync(string $url, string $payload)
{
$headers = $this->getHeader();
$this->asyncQueue->addHandler(fn () => $this->sendData($url, $payload, $headers), '[GTM-SS] measure event');
}
protected function sendData(string $url, string $payload, ?array $headers = null): void
{
$headers ??= $this->getHeader();
if ($this->debugHash) {
$headers[] = 'x-gtm-server-preview: '.$this->debugHash;
}
$ch = curl_init('https://'.$url.'/measure'); // example: https://m.shop.wpj.cz/measure
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
/**
* @return string[]
*/
public function getHeader(): array
{
return [
'Content-Type: application/json',
"Cookie: _fbp={$this->getBrowserFBPixelSessionId($this->getRequest())}",
];
}
protected function getCommonData(Event $event): array
{
$domain = $this->domainContext->getActiveId();
$request = $this->getRequest();
$referer = $request->headers->get('referer');
return [
'client_id' => $this->getClientId(),
'user_id' => $this->getUserId(),
'ga_session_id' => $this->getBrowserGASessionId($request),
'ga_session_id_2' => $this->getBrowserGASessionId($request, '_2'),
'ga_session_id_3' => $this->getBrowserGASessionId($request, '_3'),
'currency' => $this->currencyContext->getActiveId(),
'language' => $this->languageContext->getActiveId(),
'page_encoding' => 'UTF-8',
'page_hostname' => $domain,
'page_location' => "https://{$domain}",
'ip_override' => $request->getClientIp(),
'page_path' => $referer,
'page_title' => null,
'page_referrer' => $referer,
'user_agent' => $request->headers->get('User-Agent'),
'user_data' => $this->getUserData($event),
'domain' => $domain,
];
}
protected function getUserId(): string
{
return (string) \Cart::getCartID(false);
}
protected function getClientId(): string
{
return \Cart::getCartID(false).'_noCookie';
}
protected function getUserData(Event $event): ?array
{
$prefixArray = [];
if ($priceLevel = $this->priceLevelContext->getActive()) {
$prefixArray['price_level'] = $priceLevel->name;
}
if ($event instanceof OrderEvent) {
$order = $event->getOrder();
$user = $order->getUser();
$prefixArray += [
'id' => $user instanceof \User ? (string) $user->id : null,
'groups' => is_array($user?->getGroups()) ? array_values(array_map(fn ($v) => $v['name'], $user->getGroups())) : null,
];
if ($admin = getAdminUser()) {
$prefixArray['admin'] = $admin['login'];
}
$userStats = $this->fetchUsersStatsOrderData($order);
return $prefixArray + [
'lastOrderDate' => $userStats['last_date'] ?? null,
'firstOrderDate' => $userStats['first_date'] ?? null,
'countOrders' => $userStats['count'] ?? null,
'email_address' => $order->invoice_email,
'phone_number' => $order->invoice_phone,
'address' => [
'first_name' => $order->invoice_name,
'last_name' => $order->invoice_surname,
'street' => $order->invoice_street,
'city' => $order->invoice_city,
'region' => $order->invoice_state,
'postal_code' => $order->invoice_zip,
'country' => $order->invoice_country,
],
];
}
if ($user = $this->userContext->getActive()) {
return $prefixArray + [
'email_address' => $user->email ?? null,
'phone_number' => $user->phone ?? null,
'address' => [
'first_name' => $user->name ?? null,
'last_name' => $user->surname ?? null,
'street' => $user->street ?? null,
'city' => $user->city ?? null,
'region' => $user->state ?? null,
'postal_code' => $user->zip ?? null,
'country' => $user->country ?? null,
],
];
}
return null;
}
protected function getRequest(): ?Request
{
$request = $this->request ?? $this->requestStack->getMainRequest();
if (!$request && !isFrontend()) {
$request = new Request();
}
return $request;
}
}