249 lines
8.4 KiB
PHP
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;
|
|
}
|
|
}
|