src/Twig/GoogleAnalyticsEvents.php line 252

Open in your IDE?
  1. <?php
  2. namespace App\Twig;
  3. use App\DTO\AppDTO;
  4. use App\Entity\Prod;
  5. use App\Env;
  6. use App\Repository\CatRepository;
  7. use App\Repository\OrderRepository;
  8. use App\Repository\UserRepository;
  9. use Symfony\Component\HttpFoundation\RequestStack;
  10. use Twig\Extension\AbstractExtension;
  11. use Twig\TwigFunction;
  12. class GoogleAnalyticsEvents extends AbstractExtension
  13. {
  14.     public function __construct(
  15.         private RequestStack $requestStack,
  16.         private AppDTO $app,
  17.         private OrderRepository $orderRepository,
  18.         private CatRepository $catRepository,
  19.     )
  20.     {
  21.         
  22.     }
  23.     public function getFunctions(): array
  24.     {
  25.         return [
  26.             new TwigFunction('ga_events_init', [$this'init']),
  27.             new TwigFunction('ga_events_search', [$this'searchResults']),
  28.             new TwigFunction('ga_events_prodlist', [$this'prodList']),
  29.             new TwigFunction('ga_events_prodcont', [$this'prodCont']),
  30.             new TwigFunction('ga_events_addtocart', [$this'addToCart']),
  31.             new TwigFunction('ga_events_deletefromcart', [$this'deleteFromCart']),
  32.             new TwigFunction('ga_events_cart', [$this'cartItemList']),            
  33.             new TwigFunction('ga_events_checkout_begin', [$this'checkoutBegin']),
  34.             new TwigFunction('ga_events_checkout_finish', [$this'checkoutFinish']),
  35.             new TwigFunction('ga_events_checkout_client_email', [$this'clientEmail']),                        
  36.         ];
  37.     }
  38.     public function getName(): string
  39.     {
  40.         return 'app_google_analytics_extension';
  41.     }
  42.     public function init(): string
  43.     {
  44.         if (empty(Env::code_gtm())) {
  45.             return '';
  46.         }
  47.         
  48.         $url $this->requestStack->getCurrentRequest()->getPathInfo();
  49.         if (strstr($url'checkout/completed') || strstr($url'checkout/finish')) {
  50.             return '<script>
  51.                 window.dataLayer = window.dataLayer || [];
  52.                 function gtag(arguments) {
  53.                     window.dataLayer.push(arguments);
  54.                 }
  55.                 </script>';
  56.         } else {
  57.             return '<script>
  58.                 window.dataLayer = window.dataLayer || [];
  59.                 function gtag(arguments) {
  60.                     window.dataLayer.push(arguments);
  61.                 }
  62.                 </script>';
  63.         }
  64.         
  65.     }
  66.     /**
  67.      * 
  68.      * @param string $q 
  69.      * @param \App\Entity\Prod[] $prods 
  70.      * @return string 
  71.      */
  72.     public function searchResults(?string $q, array $prods)
  73.     {
  74.         if (empty(Env::code_gtm())) {
  75.             return '';
  76.         }
  77.         $sum 0;
  78.         $i 0;
  79.         $i 0;
  80.         
  81.         foreach ($prods as $prod) {
  82.             $i++;
  83.             if ($i 10) {
  84.                 break;
  85.             }
  86.             $sum += $prod->getPrice() * (100 $prod->getSkidka()) / 100;
  87.         }
  88.         $result '<script>
  89.         gtag("event", "view_search_results", {
  90.             search_term: "'.$q.'",
  91.             currency: "'.Env::currency_code().'",
  92.             value: '.round($sumEnv::price_precission()).',
  93.             items: [';
  94.         $i 0;
  95.         foreach ($prods as $prod) {
  96.             $i++;
  97.             if ($i 10) {
  98.                 break;
  99.             }
  100.             $result .= '
  101.                 {
  102.                     id: "'.$prod->getId().'-'.$this->requestStack->getCurrentRequest()->getLocale().'",
  103.                     name: "'.str_replace('"'''$prod->getName()).'",
  104.                     price: '.round(($prod->getPrice() * (100 $prod->getSkidka()) / 100), Env::price_precission()).',
  105.                     google_business_vertical: "retail"
  106.                 }';
  107.             if ($i 10) {
  108.                 $result .= ',';
  109.             }
  110.         }
  111.         $result .= '
  112.             ]
  113.         });</script>';
  114.         
  115.         return $result;
  116.     }
  117.     /**
  118.      * 
  119.      * @param \App\Entity\Prod[] $prods 
  120.      * @return string 
  121.      */
  122.     public function prodList(array $prods)
  123.     {
  124.         if (empty(Env::code_gtm())) {
  125.             return '';
  126.         }
  127.         $currency Env::currency_code();
  128.         $locale $this->requestStack->getCurrentRequest()->getLocale();
  129.         $result '<script>
  130.         window.dataLayer.push({
  131.         event: "view_item_list",
  132.         ecommerce: {
  133.             items: [';
  134.         $i 0;
  135.         $total min(count($prods), 10);
  136.         foreach ($prods as $prod) {
  137.             $cat $this->catRepository->get($prod->getCat());
  138.             $i++;
  139.             if ($i 10) {
  140.                 break;
  141.             }
  142.             $price round(($prod->getPrice() * (100 $prod->getSkidka()) / 100), Env::price_precission());
  143.             $result .= '
  144.             {
  145.                 item_name: "'.str_replace('"'''$prod->getName()).'",
  146.                 item_id: "'.$prod->getId().'",
  147.                 price: '.$price.',
  148.                 currency: "'.$currency.'",
  149.                 item_category: "'.$cat->getName().'",
  150.                 item_list_name: "Category List",
  151.                 item_list_id: "category_list",
  152.                 index: '.$i.',
  153.                 quantity: 1
  154.             }';
  155.             if ($i $total) {
  156.                 $result .= ',';
  157.             }
  158.         }
  159.         $result .= '
  160.             ]
  161.         }
  162.         });
  163.         </script>';
  164.         return $result;
  165.     }
  166.     // public function selectItemJs(Prod $prod, int $index = 1)
  167.     // {
  168.     //     if (empty(Env::code_gtm())) {
  169.     //         return '';
  170.     //     }
  171.     //     $currency = Env::currency_code();
  172.     //     $price = round(
  173.     //         $prod->getPrice() * (100 - $prod->getSkidka()) / 100,
  174.     //         Env::price_precission()
  175.     //     );
  176.     //     return '
  177.     //     function gaSelectItem_'.$prod->getId().'() {
  178.     //         window.dataLayer.push({
  179.     //         event: "select_item",
  180.     //         ecommerce: {
  181.     //             items: [{
  182.     //             item_name: "'.str_replace('"', '', $prod->getName()).'",
  183.     //             item_id: "'.$prod->getId().'",
  184.     //             price: '.$price.',
  185.     //             discount: '.intval($prod->getSkidka()).',
  186.     //             currency: "'.$currency.'",
  187.     //             item_category: "'.$prod->getCategoryName().'",
  188.     //             item_category2: "'.$prod->getCategoryLevel2Name().'",
  189.     //             item_list_name: "Category List",
  190.     //             item_list_id: "ID2",
  191.     //             index: '.$index.'
  192.     //             }]
  193.     //         }
  194.     //         });
  195.     //     }
  196.     //     ';
  197.     // }
  198.     /**
  199.      * 
  200.      * @param \App\Entity\Prod $prod
  201.      * @return string 
  202.      */
  203.     public function prodCont(Prod $prodint $index 1)
  204.     {
  205.         if (empty(Env::code_gtm())) {
  206.             return '';
  207.         }
  208.         $currency Env::currency_code();
  209.         $price round(
  210.             $prod->getPrice() * (100 $prod->getSkidka()) / 100,
  211.             Env::price_precission()
  212.         );
  213.         $cat $this->catRepository->get($prod->getCat());
  214.         $result '<script>
  215.         window.dataLayer.push({
  216.         event: "view_item",
  217.         ecommerce: {
  218.             items: [{
  219.             item_name: "'.str_replace('"'''$prod->getName()).'",
  220.             item_id: "'.$prod->getId().'",
  221.             price: '.$price.',
  222.             discount: '.intval($prod->getSkidka()).',
  223.             currency: "'.$currency.'",
  224.             item_category: "'.$cat->getName().'",
  225.             item_list_name: "Category List",
  226.             item_list_id: "ID2",
  227.             index: '.$index.'
  228.             }]
  229.         }
  230.         });
  231.         </script>';
  232.         return $result;
  233.     }
  234.     /**
  235.      * 
  236.      * @param \App\Entity\Prod $prod
  237.      * @return string 
  238.      */
  239.     public function addToCart()
  240.     {
  241.         if (empty(Env::code_gtm())) {
  242.             return '';
  243.         }
  244.         return '
  245.         <script>
  246.         document.addEventListener("DOMContentLoaded", function() {
  247.             document.querySelectorAll(".add-to-cart").forEach(function(button) {
  248.                 button.addEventListener("click", function() {
  249.                     const item = {
  250.                         item_name: this.dataset.name,
  251.                         item_id: this.dataset.id,
  252.                         price: parseFloat(this.dataset.price),
  253.                         discount: parseInt(this.dataset.discount || 0),
  254.                         currency: this.dataset.currency || "'.Env::currency_code().'",
  255.                         item_brand: this.dataset.brand || "",
  256.                         item_category: this.dataset.category || "",
  257.                         item_category2: this.dataset.category2 || "",
  258.                         item_list_name: this.dataset.listName || "Category List",
  259.                         item_list_id: this.dataset.listId || "ID2",
  260.                         index: parseInt(this.dataset.index || 1),
  261.                         quantity: parseInt(this.dataset.quantity || 1)
  262.                     };
  263.                     window.dataLayer = window.dataLayer || [];
  264.                     window.dataLayer.push({
  265.                         event: "add_to_cart",
  266.                         ecommerce: {
  267.                             items: [item]
  268.                         }
  269.                     });
  270.                     console.log("GA4 add_to_cart:", item);
  271.                 });
  272.             });
  273.         });
  274.         </script>
  275.         ';
  276.     }
  277.     public function deleteFromCart()
  278.     {
  279.         if (empty(Env::code_gtm())) {
  280.             return '';
  281.         }
  282.         return '
  283.         <script>
  284.         document.addEventListener("DOMContentLoaded", function() {
  285.             document.querySelectorAll(".delete-from-cart").forEach(function(button) {
  286.                 button.addEventListener("click", function() {
  287.                     const item = {
  288.                         item_name: this.dataset.name,
  289.                         item_id: this.dataset.id,
  290.                         price: parseFloat(this.dataset.price),
  291.                         discount: parseInt(this.dataset.discount || 0),
  292.                         currency: this.dataset.currency || "'.Env::currency_code().'",
  293.                         item_brand: this.dataset.brand || "",
  294.                         item_category: this.dataset.category || "",
  295.                         item_category2: this.dataset.category2 || "",
  296.                         item_list_name: this.dataset.listName || "Category List",
  297.                         item_list_id: this.dataset.listId || "ID2",
  298.                         index: parseInt(this.dataset.index || 1),
  299.                         quantity: parseInt(this.dataset.quantity || 1)
  300.                     };
  301.                     const cartValue = parseFloat(this.dataset.cartValue || item.price);
  302.                     window.dataLayer = window.dataLayer || [];
  303.                     window.dataLayer.push({
  304.                         event: "view_cart",
  305.                         ecommerce: {
  306.                             currency: item.currency,
  307.                             value: cartValue,
  308.                             items: [item]
  309.                         }
  310.                     });
  311.                     console.log("GA4 view_cart after delete:", item);
  312.                 });
  313.             });
  314.         });
  315.         </script>
  316.         ';
  317.     }
  318.     public function cartItemList(array $cart_items)
  319.     {
  320.         if (empty(Env::code_gtm())) {
  321.             return '';
  322.         }
  323.         $currency Env::currency_code();
  324.         $locale $this->requestStack->getCurrentRequest()->getLocale();
  325.         $result '<script>
  326.         window.dataLayer.push({
  327.         event: "view_cart",
  328.         ecommerce: {
  329.             items: [';
  330.         $i 0;
  331.         $total min(count($cart_items), 10);
  332.         foreach ($cart_items as $cart_item) {
  333.             /** @var \App\Entity\Prod $prod */
  334.             $prod $cart_item['prod'];
  335.             $cat $this->catRepository->get($prod->getCat());
  336.             $i++;
  337.             if ($i 10) {
  338.                 break;
  339.             }
  340.             $price round(($prod->getPrice() * (100 $prod->getSkidka()) / 100), Env::price_precission());
  341.             $result .= '
  342.             {
  343.                 item_name: "'.str_replace('"'''$prod->getName()).'",
  344.                 item_id: "'.$prod->getId().'",
  345.                 price: '.$price.',
  346.                 currency: "'.$currency.'",
  347.                 item_category: "'.$cat->getName().'",
  348.                 item_list_name: "Category List",
  349.                 item_list_id: "category_list",
  350.                 index: '.$i.',
  351.                 quantity: 1
  352.             }';
  353.             if ($i $total) {
  354.                 $result .= ',';
  355.             }
  356.         }
  357.         $result .= '
  358.             ]
  359.         }
  360.         });
  361.         </script>';
  362.         return $result;
  363.     }
  364.     /**
  365.      * 
  366.      * @param array $prods 
  367.      * @return string 
  368.      */
  369.     public function checkoutBegin(array $cart_items)
  370.     {
  371.         if (empty(Env::code_gtm())) {
  372.             return '';
  373.         }
  374.         $currency Env::currency_code();
  375.         $sum 0;
  376.         foreach ($cart_items as $v) {
  377.             $sum += $v['price'] * $v['num'];
  378.         }
  379.         $result '<script>
  380.         window.dataLayer = window.dataLayer || [];
  381.         window.dataLayer.push({
  382.         event: "begin_checkout",
  383.         ecommerce: {
  384.             currency: "'.$currency.'",
  385.             value: '.round($sumEnv::price_precission()).',
  386.             items: [';
  387.         $i 0;
  388.         $total count($cart_items);
  389.         foreach ($cart_items as $v) {
  390.             /** @var \App\Entity\Prod $prod */
  391.             $prod $v["prod"];
  392.             $cat $this->catRepository->get($prod->getCat());
  393.             $i++;
  394.             $price round(
  395.                 $v["price"],
  396.                 Env::price_precission()
  397.             );
  398.             $result .= '
  399.             {
  400.                 item_name: "'.str_replace('"'''$prod->getName()).'",
  401.                 item_id: "'.$prod->getId().'",
  402.                 price: '.$price.',
  403.                 discount: '.intval($prod->getSkidka()).',
  404.                 currency: "'.$currency.'",
  405.                 item_category: "'.$cat->getName().'",
  406.                 item_list_name: "Category List",
  407.                 item_list_id: "ID2",
  408.                 index: '.$i.',
  409.                 quantity: '.$v["num"].'
  410.             }';
  411.             if ($i $total) {
  412.                 $result .= ',';
  413.             }
  414.         }
  415.         $result .= '
  416.             ]
  417.         }
  418.         });
  419.         </script>';
  420.         return $result;
  421.     }
  422.     public function checkoutFinish(int $order_idfloat $amount, array $cart_items)
  423.     {
  424.         if (empty(Env::code_gtm())) {
  425.             return '';
  426.         }
  427.         $currency Env::currency_code();
  428.         $order $this->orderRepository->find($order_id);
  429.         $result '<script>
  430.         window.dataLayer.push({
  431.         event: "purchase",
  432.         ecommerce: {
  433.             transaction_id: "'.$order_id.'",
  434.             value: '.round($amountEnv::price_precission()).',
  435.             currency: "'.$currency.'",
  436.             form_id: "'.$order->getUser().'",
  437.             form_name: "'.$order->getName().'",
  438.             number: "'.$order->getPhone().'",
  439.             email: "'.$order->getEmail().'",
  440.             items: [';
  441.         $total count($cart_items);
  442.         $i 0;
  443.         foreach ($cart_items as $v) {
  444.             /** @var \App\Entity\Prod $prod */
  445.             $prod $v['prod'];
  446.             $i++;
  447.             $result .= '
  448.             {
  449.                 item_name: "'.$prod->getName().'",
  450.                 item_id: "'.$prod->getId().'",
  451.                 price: '.round($v['price'], Env::price_precission()).',
  452.                 currency: "'.$currency.'",
  453.                 item_list_name: "Checkout",
  454.                 item_list_id: "checkout",
  455.                 quantity: '.$v['num'].'
  456.             }';
  457.             if ($i $total) {
  458.                 $result .= ',';
  459.             }
  460.         }
  461.         $result .= '
  462.             ]
  463.         }
  464.         });
  465.         </script>';
  466.         return $result;
  467.     }
  468.     public function clientEmail(?string $email) {
  469.         return '';
  470.     }
  471. }