custom/plugins/WbmTagManagerEcomm/src/Services/DataLayerRenderer.php line 46

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Wbm\TagManagerEcomm\Services;
  3. use Doctrine\DBAL\Connection;
  4. use Twig\Environment;
  5. class DataLayerRenderer implements DataLayerRendererInterface
  6. {
  7.     const STRING_VALUES = [
  8.         'name',
  9.         'id',
  10.         'brand',
  11.         'category',
  12.     ];
  13.     /**
  14.      * @var Environment
  15.      */
  16.     private $twig;
  17.     /**
  18.      * @var Connection
  19.      */
  20.     private $connection;
  21.     /**
  22.      * @var array
  23.      */
  24.     private $variables = [];
  25.     /**
  26.      * @var array
  27.      */
  28.     private $dataLayer = [];
  29.     public function __construct(
  30.         Environment $twig,
  31.         Connection  $connection
  32.     )
  33.     {
  34.         $this->twig = clone $twig;
  35.         $this->connection = $connection;
  36.     }
  37.     public function renderDataLayer(string $route): DataLayerRendererInterface
  38.     {
  39.         $properties = $this->getChildrenList(null, $route);
  40.         $dataLayer = $this->fillValues($properties);
  41.         try {
  42.             $template = $this->twig->createTemplate($dataLayer);
  43.             $dataLayer = $template->render($this->getVariables($route));
  44.             $dataLayer = preg_replace('/[[:cntrl:]]/', '', $dataLayer);
  45.             $dataLayer = json_decode($dataLayer, true);
  46.             if (json_last_error() > 0) {
  47.                 throw new \Exception(json_last_error_msg(), 1620985321);
  48.             }
  49.             if (!empty($dataLayer)) {
  50.                 array_walk_recursive($dataLayer, [$this, 'castArrayValues']);
  51.             }
  52.         } catch (\Exception $e) {
  53.             $dataLayer = [];
  54.             $dataLayer['default'] = json_encode(['error' => $e->getMessage()]);
  55.         }
  56.         if (!empty($dataLayer['default'])) {
  57.             if (!empty($dataLayer['onEvent']) && !empty($dataLayer['default']['event'])) {
  58.                 unset($dataLayer['default']['event']);
  59.             }
  60.             $this->dataLayer[$route]['default'] = json_encode($dataLayer['default']);
  61.         }
  62.         if (!empty($dataLayer['onEvent'])) {
  63.             $dataLayer['onEvent']['event'] = $dataLayer['onEvent']['event'] ?? ucfirst(array_key_first($dataLayer['onEvent'])) . 'Push';
  64.             $this->dataLayer[$route]['onEvent'] = json_encode($dataLayer['onEvent']);
  65.         }
  66.         return $this;
  67.     }
  68.     public function getVariables(string $route): array
  69.     {
  70.         return $this->variables[$route];
  71.     }
  72.     public function setVariables(string $route, $variables): DataLayerRendererInterface
  73.     {
  74.         $this->variables[$route] = $variables;
  75.         return $this;
  76.     }
  77.     public function getDataLayer($route): ?array
  78.     {
  79.         return $this->dataLayer[$route] ?? null;
  80.     }
  81.     public function fillValues(array $dataLayer): string
  82.     {
  83.         $dataLayer = json_encode($dataLayer);
  84.         $search = [',{"endArrayOf":true}'];
  85.         $replace = ['{% endverbatim %}{% if not loop.last %},{% endif %}{% endfor %}{% verbatim %}'];
  86.         $dataLayer = str_replace($search, $replace, $dataLayer);
  87.         while (preg_match('/({"startArrayOf":".*?"},)/i', $dataLayer, $matches)) {
  88.             foreach ($matches as $match) {
  89.                 $foreachObj = json_decode(rtrim($match, ','));
  90.                 if ($foreachObj->startArrayOf) {
  91.                     $arguments = explode(' in ', $foreachObj->startArrayOf);
  92.                     $dataLayer = str_replace(
  93.                         $match,
  94.                         '{% endverbatim %}{% for ' . @$arguments[0] . ' in ' . @$arguments[1] . ' %}{% verbatim %}',
  95.                         $dataLayer
  96.                     );
  97.                 }
  98.             }
  99.         }
  100.         $dataLayer = '{% verbatim %}' . $dataLayer . '{% endverbatim %}';
  101.         return $dataLayer;
  102.     }
  103.     public function getChildrenList($id = null, $module = null): array
  104.     {
  105.         $qb = $this->connection->createQueryBuilder();
  106.         $qb->from('wbm_data_layer_properties', 'property');
  107.         if ($id !== null) {
  108.             $qb->where('property.parent_id = :parentId')
  109.                 ->setParameter(':parentId', $id);
  110.         } else {
  111.             $qb->where('property.parent_id IS NULL');
  112.         }
  113.         $qb->andWhere('property.module = :moduleName')
  114.             ->setParameter(':moduleName', $module);
  115.         $qb->select(
  116.             [
  117.                 'property.name',
  118.                 'property.value',
  119.                 'property.id',
  120.                 'property.child_count',
  121.                 'property.on_event',
  122.                 'property.event_name',
  123.                 'property.parent_id',
  124.             ]
  125.         );
  126.         $properties = $qb->execute()->fetchAll(\PDO::FETCH_ASSOC);
  127.         $namedProperties = [];
  128.         foreach ($properties as $key => &$property) {
  129.             $root = ($property['parent_id'] === null);
  130.             $onEvent = ($property['on_event'] === '1');
  131.             $eventName = trim($property['event_name']);
  132.             $subProperties = null;
  133.             if ((int)$property['child_count'] > 0) {
  134.                 $subProperties = $this->getChildrenList($property['id'], $module);
  135.             }
  136.             $value = $property['value'];
  137.             $name = $property['name'];
  138.             unset(
  139.                 $property['name'],
  140.                 $property['value'],
  141.                 $property['id'],
  142.                 $property['child_count'],
  143.                 $property['on_event'],
  144.                 $property['event_name'],
  145.                 $property['parent_id']
  146.             );
  147.             if (!empty($subProperties)) {
  148.                 if (empty($value)) {
  149.                     $property = $subProperties;
  150.                 } else {
  151.                     $property = [
  152.                         ['startArrayOf' => $value],
  153.                         $subProperties,
  154.                         ['endArrayOf' => true],
  155.                     ];
  156.                 }
  157.             } else {
  158.                 $property = '{% endverbatim %}' . $value . '{% verbatim %}';
  159.             }
  160.             if ($root) {
  161.                 $key = ($onEvent ? 'onEvent' : 'default');
  162.                 if ($key === 'onEvent' && !empty($eventName)) {
  163.                     $namedProperties[$key]['event'] = $eventName;
  164.                 }
  165.                 $namedProperties[$key][$name] = $property;
  166.             } else {
  167.                 $namedProperties[$name] = $property;
  168.             }
  169.         }
  170.         return $namedProperties;
  171.     }
  172.     private function castArrayValues(&$value, $key): void
  173.     {
  174.         if (in_array($key, self::STRING_VALUES, true)) {
  175.             return;
  176.         }
  177.         if (preg_match('/^\"(.*)\"$/', $value)) {
  178.             $value = json_decode($value);
  179.             return;
  180.         }
  181.         switch (true) {
  182.             case is_array(json_decode($value)):
  183.             case is_int(json_decode($value)):
  184.             case is_float(json_decode($value)):
  185.             case is_bool(json_decode($value)):
  186.                 $value = json_decode($value);
  187.         }
  188.     }
  189. }