vendor/pimcore/pimcore/bundles/EcommerceFrameworkBundle/Tracking/Tracker/Analytics/EnhancedEcommerce.php line 142

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics;
  15. use Pimcore\Analytics\Google\Tracker as GoogleTracker;
  16. use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartInterface;
  17. use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\CheckoutStepInterface as CheckoutManagerCheckoutStepInterface;
  18. use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractOrder;
  19. use Pimcore\Bundle\EcommerceFrameworkBundle\Model\ProductInterface;
  20. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\CartProductActionAddInterface;
  21. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\CartProductActionRemoveInterface;
  22. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\CheckoutCompleteInterface;
  23. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\CheckoutInterface;
  24. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\CheckoutStepInterface;
  25. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\IProductActionAdd;
  26. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\IProductActionRemove;
  27. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\ProductAction;
  28. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\ProductImpression;
  29. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\ProductImpressionInterface;
  30. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\ProductViewInterface;
  31. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackEventInterface;
  32. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingCodeAwareInterface;
  33. use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Transaction;
  34. use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
  35. use Symfony\Component\OptionsResolver\OptionsResolver;
  36. class EnhancedEcommerce extends AbstractAnalyticsTracker implements
  37.     ProductViewInterface,
  38.     ProductImpressionInterface,
  39.     IProductActionAdd,
  40.     IProductActionRemove,
  41.     CartProductActionAddInterface,
  42.     CartProductActionRemoveInterface,
  43.     CheckoutInterface,
  44.     CheckoutStepInterface,
  45.     CheckoutCompleteInterface,
  46.     TrackEventInterface,
  47.     TrackingCodeAwareInterface
  48. {
  49.     /**
  50.      * Dependencies to include before any tracking actions
  51.      *
  52.      * @var array
  53.      */
  54.     protected $dependencies = ['ec'];
  55.     /**
  56.      * @var bool
  57.      */
  58.     protected $dependenciesIncluded false;
  59.     /**
  60.      * @var string[]
  61.      */
  62.     protected $trackedCodes = [];
  63.     protected function configureOptions(OptionsResolver $resolver)
  64.     {
  65.         parent::configureOptions($resolver);
  66.         $resolver->setDefaults([
  67.             'template_prefix' => 'PimcoreEcommerceFrameworkBundle:Tracking/analytics/enhanced',
  68.         ]);
  69.     }
  70.     /**
  71.      * Track product view
  72.      *
  73.      * @param ProductInterface $product
  74.      */
  75.     public function trackProductView(ProductInterface $product)
  76.     {
  77.         $this->ensureDependencies();
  78.         $item $this->trackingItemBuilder->buildProductViewItem($product);
  79.         $parameters = [];
  80.         $parameters['productData'] = $this->transformProductAction($item);
  81.         unset($parameters['productData']['price']);
  82.         unset($parameters['productData']['quantity']);
  83.         $result $this->renderTemplate('product_view'$parameters);
  84.         $this->trackCode($result);
  85.     }
  86.     /**
  87.      * Track product view
  88.      *
  89.      * @param ProductInterface $product
  90.      * @param string $list
  91.      */
  92.     public function trackProductImpression(ProductInterface $productstring $list 'default')
  93.     {
  94.         $this->ensureDependencies();
  95.         $item $this->trackingItemBuilder->buildProductImpressionItem($product$list);
  96.         $parameters = [
  97.             'productData' => $this->transformProductImpression($item),
  98.         ];
  99.         $result $this->renderTemplate('product_impression'$parameters);
  100.         $this->trackCode($result);
  101.     }
  102.     /**
  103.      * @inheritDoc
  104.      */
  105.     public function trackCartProductActionAdd(CartInterface $cartProductInterface $product$quantity 1)
  106.     {
  107.         return $this->trackProductActionAdd($product$quantity);
  108.     }
  109.     /**
  110.      * Track product action add
  111.      *
  112.      * @param ProductInterface $product
  113.      * @param int|float $quantity
  114.      */
  115.     public function trackProductActionAdd(ProductInterface $product$quantity 1)
  116.     {
  117.         $this->ensureDependencies();
  118.         $this->trackProductAction($product'add'$quantity);
  119.     }
  120.     /**
  121.      * @inheritDoc
  122.      */
  123.     public function trackCartProductActionRemove(CartInterface $cartProductInterface $product$quantity 1)
  124.     {
  125.         $this->trackProductActionRemove($product$quantity);
  126.     }
  127.     /**
  128.      * Track product remove from cart
  129.      *
  130.      * @param ProductInterface $product
  131.      * @param int|float $quantity
  132.      */
  133.     public function trackProductActionRemove(ProductInterface $product$quantity 1)
  134.     {
  135.         $this->ensureDependencies();
  136.         $this->trackProductAction($product'remove'$quantity);
  137.     }
  138.     /**
  139.      * @param ProductInterface $product
  140.      * @param string $action
  141.      * @param int|float $quantity
  142.      */
  143.     protected function trackProductAction($product$action$quantity 1)
  144.     {
  145.         $item $this->trackingItemBuilder->buildProductActionItem($product);
  146.         $item->setQuantity($quantity);
  147.         $parameters = [];
  148.         $parameters['productData'] = $this->transformProductAction($item);
  149.         $parameters['action'] = $action;
  150.         $result $this->renderTemplate('product_action'$parameters);
  151.         $this->trackCode($result);
  152.     }
  153.     /**
  154.      * Track start checkout with first step
  155.      *
  156.      * @param CartInterface $cart
  157.      */
  158.     public function trackCheckout(CartInterface $cart)
  159.     {
  160.         $this->ensureDependencies();
  161.         $items $this->trackingItemBuilder->buildCheckoutItemsByCart($cart);
  162.         $parameters = [];
  163.         $parameters['items'] = $items;
  164.         $parameters['calls'] = $this->buildCheckoutCalls($items);
  165.         $parameters['actionData'] = [
  166.             'step' => 1,
  167.         ];
  168.         $result $this->renderTemplate('checkout'$parameters);
  169.         $this->trackCode($result);
  170.     }
  171.     /**
  172.      * @param CheckoutManagerCheckoutStepInterface $step
  173.      * @param CartInterface $cart
  174.      * @param string|null $stepNumber
  175.      * @param string|null $checkoutOption
  176.      */
  177.     public function trackCheckoutStep(CheckoutManagerCheckoutStepInterface $stepCartInterface $cart$stepNumber null$checkoutOption null)
  178.     {
  179.         $this->ensureDependencies();
  180.         $items $this->trackingItemBuilder->buildCheckoutItemsByCart($cart);
  181.         $parameters = [];
  182.         $parameters['items'] = $items;
  183.         $parameters['calls'] = [];
  184.         if (!is_null($stepNumber) || !is_null($checkoutOption)) {
  185.             $actionData = ['step' => $stepNumber];
  186.             if (!is_null($checkoutOption)) {
  187.                 $actionData['option'] = $checkoutOption;
  188.             }
  189.             $parameters['actionData'] = $actionData;
  190.         }
  191.         $result $this->renderTemplate('checkout'$parameters);
  192.         $this->trackCode($result);
  193.     }
  194.     /**
  195.      * Track checkout complete
  196.      *
  197.      * @param AbstractOrder $order
  198.      */
  199.     public function trackCheckoutComplete(AbstractOrder $order)
  200.     {
  201.         $this->ensureDependencies();
  202.         $transaction $this->trackingItemBuilder->buildCheckoutTransaction($order);
  203.         $items $this->trackingItemBuilder->buildCheckoutItems($order);
  204.         $parameters = [];
  205.         $parameters['transaction'] = $this->transformTransaction($transaction);
  206.         $parameters['items'] = $items;
  207.         $parameters['calls'] = $this->buildCheckoutCompleteCalls($transaction$items);
  208.         $result $this->renderTemplate('checkout_complete'$parameters);
  209.         $this->trackCode($result);
  210.     }
  211.     public function trackEvent(
  212.         string $eventCategory,
  213.         string $eventAction,
  214.         string $eventLabel null,
  215.         int $eventValue null
  216.     ) {
  217.         $parameters = [
  218.             'eventCategory' => $eventCategory,
  219.             'eventAction' => $eventAction,
  220.             'eventLabel' => $eventLabel,
  221.             'eventValue' => $eventValue,
  222.         ];
  223.         $result $this->renderTemplate('track_event'$parameters);
  224.         $this->trackCode($result);
  225.     }
  226.     public function getTrackedCodes(): array
  227.     {
  228.         return $this->trackedCodes;
  229.     }
  230.     public function trackCode(string $code)
  231.     {
  232.         $this->trackedCodes[] = $code;
  233.         $this->tracker->addCodePart($codeGoogleTracker::BLOCK_BEFORE_TRACK);
  234.     }
  235.     /**
  236.      * @param Transaction $transaction
  237.      * @param ProductAction[] $items
  238.      *
  239.      * @return mixed
  240.      */
  241.     protected function buildCheckoutCompleteCalls(Transaction $transaction, array $items)
  242.     {
  243.         $calls = [];
  244.         foreach ($items as $item) {
  245.             $calls[] = $this->transformProductAction($item);
  246.         }
  247.         return $calls;
  248.     }
  249.     /**
  250.      * Transform transaction into classic analytics data array
  251.      *
  252.      * @note city, state, country were dropped as they were optional and never used
  253.      *
  254.      * @param Transaction $transaction
  255.      *
  256.      * @return array
  257.      */
  258.     protected function transformTransaction(Transaction $transaction)
  259.     {
  260.         return array_merge([
  261.             'id' => $transaction->getId(),                           // order ID - required
  262.             'affiliation' => $transaction->getAffiliation() ?: '',            // affiliation or store name
  263.             'revenue' => round($transaction->getTotal(), 2),     // total - required
  264.             'tax' => round($transaction->getTax(), 2),       // tax
  265.             'coupon' => $transaction->getCoupon(), // voucher code - optional
  266.             'shipping' => round($transaction->getShipping(), 2),  // shipping
  267.         ],
  268.             $transaction->getAdditionalAttributes()
  269.         );
  270.     }
  271.     protected function buildCheckoutCalls(array $items)
  272.     {
  273.         $calls = [];
  274.         foreach ($items as $item) {
  275.             $calls[] = $this->transformProductAction($item);
  276.         }
  277.         return $calls;
  278.     }
  279.     /**
  280.      * Transform product action into enhanced data object
  281.      *
  282.      * @param ProductAction $item
  283.      *
  284.      * @return array
  285.      */
  286.     protected function transformProductAction(ProductAction $item)
  287.     {
  288.         return $this->filterNullValues(
  289.             array_merge([
  290.                 'id' => $item->getId(),
  291.                 'name' => $item->getName(),
  292.                 'category' => $item->getCategory(),
  293.                 'brand' => $item->getBrand(),
  294.                 'variant' => $item->getVariant(),
  295.                 'price' => $item->getPrice() ? Decimal::fromNumeric($item->getPrice())->asString() : '',
  296.                 'quantity' => $item->getQuantity() ?: 1,
  297.                 'position' => $item->getPosition(),
  298.                 'coupon' => $item->getCoupon(),
  299.             ],
  300.                 $item->getAdditionalAttributes())
  301.         );
  302.     }
  303.     /**
  304.      * Transform product action into enhanced data object
  305.      *
  306.      * @param ProductImpression $item
  307.      *
  308.      * @return array
  309.      */
  310.     protected function transformProductImpression(ProductImpression $item)
  311.     {
  312.         $data $this->filterNullValues(array_merge([
  313.             'id' => $item->getId(),
  314.             'name' => $item->getName(),
  315.             'category' => $item->getCategory(),
  316.             'brand' => $item->getBrand(),
  317.             'variant' => $item->getVariant(),
  318.             'price' => $item->getPrice() ? Decimal::fromNumeric($item->getPrice())->asString() : '',
  319.             'list' => $item->getList(),
  320.             'position' => $item->getPosition(),
  321.         ], $item->getAdditionalAttributes()));
  322.         return $data;
  323.     }
  324.     /**
  325.      * Makes sure dependencies are included once before any call
  326.      */
  327.     protected function ensureDependencies()
  328.     {
  329.         if ($this->dependenciesIncluded || empty($this->dependencies)) {
  330.             return;
  331.         }
  332.         $result $this->renderTemplate('dependencies', [
  333.             'dependencies' => $this->dependencies,
  334.         ]);
  335.         $this->trackCode($result);
  336.         $this->dependenciesIncluded true;
  337.     }
  338. }