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

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