vendor/pimcore/pimcore/lib/Analytics/Google/Tracker.php line 174

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * Pimcore
  5.  *
  6.  * This source file is available under two different licenses:
  7.  * - GNU General Public License version 3 (GPLv3)
  8.  * - Pimcore Enterprise License (PEL)
  9.  * Full copyright and license information is available in
  10.  * LICENSE.md which is distributed with this source code.
  11.  *
  12.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  13.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  14.  */
  15. namespace Pimcore\Analytics\Google;
  16. use Pimcore\Analytics\AbstractTracker;
  17. use Pimcore\Analytics\Code\CodeBlock;
  18. use Pimcore\Analytics\Code\CodeCollector;
  19. use Pimcore\Analytics\Google\Config\Config;
  20. use Pimcore\Analytics\Google\Config\ConfigProvider;
  21. use Pimcore\Analytics\Google\Event\TrackingDataEvent;
  22. use Pimcore\Analytics\SiteId\SiteId;
  23. use Pimcore\Analytics\SiteId\SiteIdProvider;
  24. use Pimcore\Config\Config as ConfigObject;
  25. use Pimcore\Event\Analytics\GoogleAnalyticsEvents;
  26. use Psr\Log\LoggerAwareTrait;
  27. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  28. use Symfony\Component\Templating\EngineInterface;
  29. class Tracker extends AbstractTracker
  30. {
  31.     use LoggerAwareTrait;
  32.     const BLOCK_BEFORE_SCRIPT_TAG 'beforeScriptTag';
  33.     const BLOCK_BEFORE_SCRIPT 'beforeScript';
  34.     const BLOCK_BEFORE_INIT 'beforeInit';
  35.     const BLOCK_BEFORE_TRACK 'beforeTrack';
  36.     const BLOCK_AFTER_TRACK 'afterTrack';
  37.     const BLOCK_AFTER_SCRIPT 'afterScript';
  38.     const BLOCK_AFTER_SCRIPT_TAG 'afterScriptTag';
  39.     /**
  40.      * @var SiteIdProvider
  41.      */
  42.     private $siteIdProvider;
  43.     /**
  44.      * @var ConfigProvider
  45.      */
  46.     private $configProvider;
  47.     /**
  48.      * @var EventDispatcherInterface
  49.      */
  50.     private $eventDispatcher;
  51.     /**
  52.      * @var EngineInterface
  53.      */
  54.     private $templatingEngine;
  55.     /**
  56.      * @var string|null
  57.      */
  58.     private $defaultPath;
  59.     /**
  60.      * @var array
  61.      */
  62.     private $blocks = [
  63.         self::BLOCK_BEFORE_SCRIPT_TAG,
  64.         self::BLOCK_BEFORE_SCRIPT,
  65.         self::BLOCK_BEFORE_INIT,
  66.         self::BLOCK_BEFORE_TRACK,
  67.         self::BLOCK_AFTER_TRACK,
  68.         self::BLOCK_AFTER_SCRIPT,
  69.         self::BLOCK_AFTER_SCRIPT_TAG,
  70.     ];
  71.     public function __construct(
  72.         SiteIdProvider $siteIdProvider,
  73.         ConfigProvider $configProvider,
  74.         EventDispatcherInterface $eventDispatcher,
  75.         EngineInterface $templatingEngine
  76.     ) {
  77.         parent::__construct($siteIdProvider);
  78.         $this->siteIdProvider $siteIdProvider;
  79.         $this->configProvider $configProvider;
  80.         $this->eventDispatcher $eventDispatcher;
  81.         $this->templatingEngine $templatingEngine;
  82.     }
  83.     public function getDefaultPath()
  84.     {
  85.         return $this->defaultPath;
  86.     }
  87.     public function setDefaultPath(string $defaultPath null)
  88.     {
  89.         $this->defaultPath $defaultPath;
  90.     }
  91.     protected function buildCodeCollector(): CodeCollector
  92.     {
  93.         return new CodeCollector($this->blocksself::BLOCK_AFTER_TRACK);
  94.     }
  95.     protected function buildCode(SiteId $siteId)
  96.     {
  97.         $config $this->configProvider->getConfig();
  98.         $configKey $siteId->getConfigKey();
  99.         if (!$config->isSiteConfigured($configKey)) {
  100.             return null;
  101.         }
  102.         $siteConfig $config->getConfigForSite($configKey);
  103.         return $this->doBuildCode($siteId$config$siteConfig);
  104.     }
  105.     /**
  106.      * This method exists for BC with the existing Pimcore\Google\Analytics implementation which supports to pass a config
  107.      * object without a Site ID. Should be removed at a later point.
  108.      *
  109.      * @param ConfigObject $siteConfig
  110.      * @param SiteId|null $siteId
  111.      *
  112.      * @return string
  113.      */
  114.     public function generateCodeForSiteConfig(ConfigObject $siteConfigSiteId $siteId null)
  115.     {
  116.         if (null === $siteId) {
  117.             $siteId $this->siteIdProvider->getForRequest();
  118.         }
  119.         $config $this->configProvider->getConfig();
  120.         return $this->doBuildCode($siteId$config$siteConfig);
  121.     }
  122.     private function doBuildCode(SiteId $siteIdConfig $configConfigObject $siteConfig)
  123.     {
  124.         $data = [
  125.             'siteId' => $siteId,
  126.             'config' => $config,
  127.             'siteConfig' => $siteConfig,
  128.             'trackId' => $siteConfig->get('trackid'),
  129.             'defaultPath' => $this->getDefaultPath(),
  130.             'universalConfiguration' => $siteConfig->get('universal_configuration') ?? null,
  131.             'retargeting' => $siteConfig->get('retargetingcode') ?? false,
  132.         ];
  133.         if ($siteConfig->get('gtagcode')) {
  134.             $template '@PimcoreCore/Analytics/Tracking/Google/Analytics/gtagTrackingCode.html.twig';
  135.             $data['gtagConfig'] = $this->getTrackerConfigurationFromJson($siteConfig->get('universal_configuration') ?? null, [
  136.                 'anonymize_ip' => true,
  137.             ]);
  138.         } elseif ($siteConfig->get('asynchronouscode') || $siteConfig->get('retargetingcode')) {
  139.             $template '@PimcoreCore/Analytics/Tracking/Google/Analytics/asynchronousTrackingCode.html.twig';
  140.         } else {
  141.             $template '@PimcoreCore/Analytics/Tracking/Google/Analytics/universalTrackingCode.html.twig';
  142.         }
  143.         $blocks $this->buildCodeBlocks($siteId$siteConfig);
  144.         $event = new TrackingDataEvent($config$siteId$data$blocks$template);
  145.         $this->eventDispatcher->dispatch(GoogleAnalyticsEvents::CODE_TRACKING_DATA$event);
  146.         return $this->renderTemplate($event);
  147.     }
  148.     private function getTrackerConfigurationFromJson($configValue null, array $defaultConfig = []): array
  149.     {
  150.         $config = [];
  151.         if (!empty($configValue)) {
  152.             $jsonConfig = @json_decode($configValuetrue);
  153.             if (JSON_ERROR_NONE === json_last_error() && is_array($jsonConfig)) {
  154.                 $config $jsonConfig;
  155.             } else {
  156.                 $this->logger->warning('Failed to parse analytics tracker custom configuration: {error}', [
  157.                     'error' => json_last_error_msg() ?? 'not an array',
  158.                 ]);
  159.             }
  160.         }
  161.         return array_merge($defaultConfig$config);
  162.     }
  163.     private function buildCodeBlocks(SiteId $siteIdConfigObject $siteConfig): array
  164.     {
  165.         $blockData $this->buildBlockData($siteConfig);
  166.         $blocks = [];
  167.         foreach ($this->blocks as $block) {
  168.             $codeBlock = new CodeBlock();
  169.             if (isset($blockData[$block])) {
  170.                 $codeBlock->append($blockData[$block]);
  171.             }
  172.             $this->getCodeCollector()->enrichCodeBlock($siteId$codeBlock$block);
  173.             $blocks[$block] = $codeBlock;
  174.         }
  175.         return $blocks;
  176.     }
  177.     private function buildBlockData(ConfigObject $siteConfig): array
  178.     {
  179.         $blockData = [];
  180.         if (!empty($siteConfig->get('additionalcodebeforeinit'))) {
  181.             $blockData[self::BLOCK_BEFORE_INIT] = $siteConfig->get('additionalcodebeforeinit');
  182.         }
  183.         if (!empty($siteConfig->get('additionalcodebeforepageview'))) {
  184.             $blockData[self::BLOCK_BEFORE_TRACK] = $siteConfig->get('additionalcodebeforepageview');
  185.         }
  186.         if (!empty($siteConfig->get('additionalcode'))) {
  187.             $blockData[self::BLOCK_AFTER_TRACK] = $siteConfig->get('additionalcode');
  188.         }
  189.         return $blockData;
  190.     }
  191.     private function renderTemplate(TrackingDataEvent $event): string
  192.     {
  193.         $data $event->getData();
  194.         $data['blocks'] = $event->getBlocks();
  195.         $code $this->templatingEngine->render(
  196.             $event->getTemplate(),
  197.             $data
  198.         );
  199.         $code trim($code);
  200.         if (!empty($code)) {
  201.             $code "\n" $code "\n";
  202.         }
  203.         return $code;
  204.     }
  205. }