<?php
/**
* @author Antony Tkachenko <at@canaryknight.ru>
*/
namespace App\Event;
use App\Utm\Utm;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class UtmSubscriber implements EventSubscriberInterface
{
const UTM_COOKIE_NAME = 'gmb_campaign';
private $setCookie = false;
public function parseUtm(RequestEvent $event)
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
$request->attributes->set(self::UTM_COOKIE_NAME, Utm::fromArray([]));
$value = $request->cookies->get(self::UTM_COOKIE_NAME, '[]');
try {
$data = json_decode($value, true, JSON_THROW_ON_ERROR);
} catch (\Throwable $e) {
$data = [];
}
if (!empty($data)) {
// utm cookie already set
$request->attributes->set(self::UTM_COOKIE_NAME, Utm::fromArray($data));
return;
}
$values = [];
foreach (Utm::PARAMS as $param) {
if (!$request->query->has($param)) {
continue;
}
$values[$param] = (string) $request->query->get($param);
}
[$referrer, $source] = $this->parseReferrer((string) $request->headers->get('referer'));
if ($referrer) {
$values['referrer'] = $referrer;
}
$values['utm_source'] = $values['utm_source'] ?? $source;
$utm = Utm::fromArray($values);
$request->attributes->set(self::UTM_COOKIE_NAME, $utm);
if (!empty($values)) {
$this->setCookie = true;
}
}
public function saveUtm(ResponseEvent $event)
{
if (!$this->setCookie) {
return;
}
$response = $event->getResponse();
$request = $event->getRequest();
if (!$request->attributes->has(self::UTM_COOKIE_NAME)) {
return;
}
$value = json_encode($request->attributes->get(self::UTM_COOKIE_NAME));
$cookie = Cookie::create(self::UTM_COOKIE_NAME)
->withValue($value)
->withExpires(strtotime("+1 year"))
->withDomain('.'.$event->getRequest()->getHost())
;
$response->headers->setCookie($cookie);
}
private function parseReferrer(string $referrer)
{
if (empty($referrer)) {
return [null, 'direct'];
}
$host = parse_url($referrer, PHP_URL_HOST);
if (false === $host) {
// not valid url
return [null, null];
}
$hostNames = (array) explode(".", mb_strtolower($host));
$count = count($hostNames);
if ($count < 2) {
return [$host, null];
}
$tld = $hostNames[$count-2] . '.' . $hostNames[$count-1];
if (in_array($tld, ['getmeback.ru', 'getmeback.io'], true)) {
return [null, 'direct'];
}
$searchEngines = [
'google.com',
'yandex.ru',
'mail.ru',
'rambler.ru',
'duckduckgo.com',
'yahoo.com',
'bing.com',
'baidu.com',
];
$source = in_array($tld, $searchEngines, true) ? 'organic' : null;
return [$tld, $source];
}
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => 'parseUtm',
KernelEvents::RESPONSE => 'saveUtm',
];
}
}