vendor/pimcore/customer-management-framework-bundle/src/Targeting/SegmentTracker.php line 153

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 Commercial License (PCL)
  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 PCL
  14.  */
  15. namespace CustomerManagementFrameworkBundle\Targeting;
  16. use CustomerManagementFrameworkBundle\ActionTrigger\Event\SegmentTracked;
  17. use CustomerManagementFrameworkBundle\Model\CustomerInterface;
  18. use CustomerManagementFrameworkBundle\Model\CustomerSegmentInterface;
  19. use CustomerManagementFrameworkBundle\SegmentManager\SegmentManagerInterface;
  20. use CustomerManagementFrameworkBundle\Targeting\DataProvider\Customer;
  21. use Pimcore\Targeting\DataLoaderInterface;
  22. use Pimcore\Targeting\Model\VisitorInfo;
  23. use Pimcore\Targeting\Storage\TargetingStorageInterface;
  24. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  25. /**
  26.  * Handles storage of tracked segments to request-persistent targeting storage (e.g. session)
  27.  */
  28. class SegmentTracker
  29. {
  30.     const KEY_SEGMENTS 'cmf:sg';
  31.     /**
  32.      * @var TargetingStorageInterface
  33.      */
  34.     private $targetingStorage;
  35.     /**
  36.      * @var DataLoaderInterface
  37.      */
  38.     private $dataLoader;
  39.     /**
  40.      * @var SegmentManagerInterface
  41.      */
  42.     private $segmentManager;
  43.     /**
  44.      * @var EventDispatcherInterface
  45.      */
  46.     private $eventDispatcher;
  47.     public function __construct(
  48.         TargetingStorageInterface $targetingStorage,
  49.         DataLoaderInterface $dataLoader,
  50.         SegmentManagerInterface $segmentManager,
  51.         EventDispatcherInterface $eventDispatcher
  52.     ) {
  53.         $this->targetingStorage $targetingStorage;
  54.         $this->dataLoader $dataLoader;
  55.         $this->segmentManager $segmentManager;
  56.         $this->eventDispatcher $eventDispatcher;
  57.     }
  58.     public function trackSegment(VisitorInfo $visitorInfoCustomerSegmentInterface $segment)
  59.     {
  60.         $this->trackSegments($visitorInfo, [$segment]);
  61.     }
  62.     /**
  63.      * @param VisitorInfo $visitorInfo
  64.      * @param CustomerSegmentInterface[] $segments
  65.      */
  66.     public function trackSegments(VisitorInfo $visitorInfo, array $segments)
  67.     {
  68.         $assignments = [];
  69.         foreach ($segments as $segment) {
  70.             if (!$segment instanceof CustomerSegmentInterface) {
  71.                 throw new \InvalidArgumentException(sprintf(
  72.                     'Segments is expected to be an array of CustomerSegmentInterface instances, but got a %s',
  73.                     get_debug_type($segment)
  74.                 ));
  75.             }
  76.             $assignments[$segment->getId()] = 1;
  77.         }
  78.         $this->trackAssignments($visitorInfo$assignments);
  79.     }
  80.     /**
  81.      * Raw method to track ID to count assignments. Use trackSegment(s) if possible.
  82.      *
  83.      * @param VisitorInfo $visitorInfo
  84.      * @param array $assignments Segment ID as key, count as value
  85.      */
  86.     public function trackAssignments(VisitorInfo $visitorInfo, array $assignments)
  87.     {
  88.         $eventData = [];
  89.         $segments $this->getAssignments($visitorInfo);
  90.         foreach ($assignments as $segmentId => $count) {
  91.             if (!isset($segments[$segmentId])) {
  92.                 $segments[$segmentId] = 0;
  93.             }
  94.             $segments[$segmentId] += $count;
  95.             $eventData[$segmentId] = $segments[$segmentId];
  96.         }
  97.         $this->targetingStorage->set(
  98.             $visitorInfo,
  99.             TargetingStorageInterface::SCOPE_VISITOR,
  100.             self::KEY_SEGMENTS,
  101.             $segments
  102.         );
  103.         foreach ($eventData as $segmentId => $count) {
  104.             $this->dispatchTrackEvent($visitorInfo$segmentId$count);
  105.         }
  106.     }
  107.     /**
  108.      * Read ID <-> count assignment mapping from storage
  109.      *
  110.      * @param VisitorInfo $visitorInfo
  111.      *
  112.      * @return array
  113.      */
  114.     public function getAssignments(VisitorInfo $visitorInfo): array
  115.     {
  116.         return $this->targetingStorage->get(
  117.             $visitorInfo,
  118.             TargetingStorageInterface::SCOPE_VISITOR,
  119.             self::KEY_SEGMENTS,
  120.             []
  121.         );
  122.     }
  123.     /**
  124.      * Returns assigned segments filtered for $allowedSegmentGroupReferences grouped by segment groups
  125.      *
  126.      * @param VisitorInfo $visitorInfo
  127.      * @param array $allowedSegmentGroupReferences
  128.      * @param int $limitSegmentCountPerGroup
  129.      *
  130.      * @return array
  131.      */
  132.     public function getFilteredAssignments(VisitorInfo $visitorInfo, array $allowedSegmentGroupReferencesint $limitSegmentCountPerGroup): array
  133.     {
  134.         $trackedSegments $this->getAssignments($visitorInfo);
  135.         //get relevant segments
  136.         $segmentCollection = [];
  137.         foreach ($trackedSegments as $segmentId => $count) {
  138.             $segment $this->segmentManager->getSegmentById($segmentId);
  139.             if ($segment) {
  140.                 $reference $segment->getGroup()->getReference();
  141.                 if (in_array($reference$allowedSegmentGroupReferences)) {
  142.                     $segmentCollection[$reference][] = [
  143.                         'segment' => $segment,
  144.                         'count' => $count
  145.                     ];
  146.                 }
  147.             }
  148.         }
  149.         if (empty($segmentCollection)) {
  150.             return [];
  151.         }
  152.         //order segments by count, pick $limitSegmentCountPerGroup top segments
  153.         foreach ($segmentCollection as $group => $groupCollection) {
  154.             usort($groupCollection, function ($left$right) {
  155.                 if ($left['count'] === $right['count']) {
  156.                     return 0;
  157.                 }
  158.                 return ($left['count'] < $right['count']) ? : -1;
  159.             });
  160.             $segmentCollection[$group] = array_slice($groupCollection0$limitSegmentCountPerGroup);
  161.         }
  162.         return $segmentCollection;
  163.     }
  164.     private function dispatchTrackEvent(VisitorInfo $visitorInfoint $segmentIdint $count)
  165.     {
  166.         $this->dataLoader->loadDataFromProviders($visitorInfo, [Customer::PROVIDER_KEY]);
  167.         /** @var CustomerInterface|null $customer */
  168.         $customer $visitorInfo->get(Customer::PROVIDER_KEY);
  169.         if (null === $customer) {
  170.             return;
  171.         }
  172.         $segment $this->segmentManager->getSegmentById($segmentId);
  173.         if (null === $segment) {
  174.             return;
  175.         }
  176.         $event SegmentTracked::create($customer$segment$count);
  177.         $this->eventDispatcher->dispatch($event$event->getName());
  178.     }
  179. }