src/Services/TrackingManager.php line 760

Open in your IDE?
  1. <?php
  2. namespace App\Services;
  3. use App\Entity\Main\Affiliate;
  4. use App\Entity\Main\Site;
  5. use App\Entity\Main\SiteABTest;
  6. use App\Entity\Main\Tracking;
  7. use App\Entity\Main\TrackingHasABTest;
  8. use App\Entity\Main\TrackingHasReferrer;
  9. use App\Entity\Main\User;
  10. use App\EventListener\Main\DebugListener;
  11. use DateInterval;
  12. use Doctrine\ORM\EntityManagerInterface;
  13. use Doctrine\ORM\NonUniqueResultException;
  14. use Mobile_Detect;
  15. use Psr\Cache\InvalidArgumentException;
  16. use Psr\Log\LoggerInterface;
  17. use Symfony\Component\Cache\Adapter\FilesystemAdapter;
  18. use Symfony\Component\HttpFoundation\Cookie;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpFoundation\RequestStack;
  21. use Symfony\Component\Serializer\SerializerInterface;
  22. use Symfony\Contracts\Service\Attribute\Required;
  23. final class TrackingManager
  24. {
  25.     const
  26.         SESSION_ID 'actualTracking',
  27.         ALREADY_PAID_COOKIE_NAME 'adasns',
  28.         ALREADY_PAID_CACHE_IP_PREFIX 'ip_paid.',
  29.         SESSION_MUST_SETUP_ALREADY_PAID_COOKIE_KEY 'already_paid_cookie_to_setup',
  30.         CACHE_IP_INFO_PREFIX 'ip_infos.',
  31.         DEFAULT_TRACKING_O1 'deftrack'
  32.     ;
  33. //    private $request;
  34.     private $cache;
  35.     /**
  36.      * @var string[]
  37.      */
  38.     private array $params = ['o1''o2''o3''o4''o5''t''aff''rmkg'];
  39.     // the value of 'aecid' is stored on 'o5', to avoid an additional column in the DB
  40.     private array $additionalParams = ['aecid'];
  41.     /**
  42.      * @var Mobile_Detect
  43.      */
  44.     private $detector;
  45.     private ?Tracking $currentTracking null;
  46.     private string $trackingOrigin 'undefined';
  47.     private ?Request $request;
  48.     /**
  49.      * New Instance
  50.      *
  51.      * @param EntityManagerInterface $em
  52.      * @param RequestStack $request_stack
  53.      * @param SerializerInterface $serializer
  54.      * @param string $trackingCookieName
  55.      * @param string $trackingCookieExpiration
  56.      * @param string $trackingCookieSecret
  57.      * @param LoggerInterface $logger
  58.      * @param $environment
  59.      * @param \App\Services\ABTestManager $ABTestManager
  60.      * @param  $cacheItemPool
  61.      * @param \App\Services\SiteManager $siteManager
  62.      * @throws InvalidArgumentException
  63.      */
  64.     public function __construct(
  65.         private EntityManagerInterface $em,
  66.         private RequestStack $request_stack,
  67.         private SerializerInterface $serializer,
  68.         private string $trackingCookieName,
  69.         private string $trackingCookieExpiration,
  70.         private string $trackingCookieSecret,
  71.         private LoggerInterface $logger,
  72.         private $environment,
  73.         private ABTestManager $ABTestManager,
  74.         private SiteManager $siteManager,
  75.         private ReferralProgramManager $referralProgramManager
  76.     ) {
  77.         $this->request $this->request_stack->getCurrentRequest();
  78.         $this->cache = new FilesystemAdapter('tracking.cache');
  79.         // The same is for the mobile detector.
  80. //        $this->detector = $this->container->get('mobile_detect.mobile_detector');
  81.     }
  82.     public function setDetector(Mobile_Detect $detector): self
  83.     {
  84. //        $this->detector = $detector;
  85.         return $this;
  86.     }
  87.     /**
  88.      * @return Mobile_Detect|null
  89.      */
  90.     public function getDetector()
  91.     {
  92.         return $this->detector;
  93.     }
  94.     /**
  95.      * @throws InvalidArgumentException
  96.      */
  97.     public function clearCacheFromIp($client_ip): bool
  98.     {
  99.         $infosCacheItem $this->cache->getItem(self::CACHE_IP_INFO_PREFIX $client_ip);
  100.         if (!$infosCacheItem->isHit()) {
  101.             return true;
  102.         }
  103.         return $this->cache->deleteItem(self::CACHE_IP_INFO_PREFIX $client_ip);
  104.     }
  105.     /**
  106.      * Return the Affiliate according to the Traking object
  107.      *
  108.      * @param Tracking $tracking
  109.      * @deprecated You should get directly affiliate from tracking now.
  110.      *
  111.      * @return Affiliate
  112.      */
  113.     public function resolveAffiliate(Tracking $tracking): Affiliate
  114.     {
  115.         return $tracking->getAff();
  116.     }
  117.     /**
  118.      * Return the generated Cookie from the Tracking
  119.      *
  120.      * @param Tracking $tracking
  121.      *
  122.      * @return Cookie
  123.      */
  124.     public function resolveCookie(Tracking $tracking): Cookie
  125.     {
  126.         $cookieData $tracking->getDataForCookie();
  127.         $cookieData['tracking_hash'] = $this->makeTrackingHash($cookieData['tracking_id']);
  128.         return new Cookie(
  129.             $this->trackingCookieName,
  130.             $this->serializer->serialize($cookieData'json'),
  131.             time() + $this->trackingCookieExpiration
  132.         );
  133.     }
  134.     /**
  135.      * @return Cookie
  136.      */
  137.     public function generateAlreadyPaidCookie()
  138.     {
  139.         return new Cookie(
  140.             self::ALREADY_PAID_COOKIE_NAME,
  141.             1,
  142.             time() + $this->trackingCookieExpiration
  143.         );
  144.     }
  145.     /**
  146.      * Return the Tracking according to the Site object
  147.      *
  148.      * @param Site $site
  149.      *
  150.      * @return Tracking
  151.      * @throws NonUniqueResultException
  152.      * @throws InvalidArgumentException
  153.      */
  154.     public function resolveTracking(): Tracking
  155.     {
  156.         // If we are in cli and we don't have a request, there is no way to build a pertinent tracking.
  157.         if ('cli' === php_sapi_name() && !$this->request instanceof Request) {
  158.             $this->trackingOrigin 'cli';
  159.             return new Tracking();
  160.         }
  161.         $site $this->siteManager->getCurrentSite();
  162.         $rmkg $this->request->get('rmkg'0);
  163.         $oldTracking null;
  164.         // check if we force to create a new tracking.
  165.         if ((in_array($this->environment, ["dev""test"]) || $this->request->getSession()->get(DebugListener::DEBUG_ALLOWED_SESSION)) && $this->request->get('fnt'0)) {
  166.             $forceCreateNewTracking true;
  167.             // remove the request attribute to not recreate tracking on each call :)
  168.             $this->request->attributes->set('fnt'0);
  169.             $this->clearAlreadyPaidInCache();
  170.         } else {
  171.             $forceCreateNewTracking false;
  172.         }
  173.         $hasAlreadyPaidInfo $this->getAlreadyPaidInfo();
  174.         if (!$forceCreateNewTracking) {
  175.             // we get data from the sessions
  176.             $infos $this->getTrackingInfoFromSession();
  177.             if (!$this->isValidTrackingInfo($infos)) {
  178.                 //get data from the cookie
  179.                 $infos $this->getTrackingInfoFromCookie();
  180.             } else {
  181.                 // if infos from sessions are valid, we can't use rmkg.
  182.                 $rmkg 0;
  183.             }
  184. //            if (!$this->isValidTrackingInfo($infos)) {
  185. //                //get data from cache with user IP
  186. //                $infos = $this->getTrackingInfoFromCache();
  187. //            }
  188.             // from here we need to define if rmkg is allowed (only if we have an existing affiliate before).
  189.             if ($rmkg && $this->isValidTrackingInfo($infos) && (isset($infos['aff']) && $infos['aff'] instanceof Affiliate && Affiliate::FORBIDDEN_RMKG == $infos['aff']->getAffiliateRmkg())) {
  190.                 $rmkg 0;
  191.             }
  192.             // If data are empty or rmkg = 1, we get the data from the _GET
  193.             if (!$this->isValidTrackingInfo($infos) || == $rmkg) {
  194.                 // we keep the old tracking info to put in parent
  195.                 if ($this->isValidTrackingInfo($infos)) {
  196.                     $oldTracking $infos['tracking'];
  197.                 }
  198.                 $infos $this->getTrackingInfoFromRequest();
  199.                 $infos['origin'] = 'request';
  200.             }
  201.             // if the info comes from the get, it's an integer, not an affiliate we have to check it exists
  202.             if (!$infos['aff'] instanceof Affiliate) {
  203.                 $infos['aff'] = $this->em
  204.                     ->getRepository(Affiliate::class)
  205.                     ->loadAffiliateById($infos['aff'], "prod" == $this->environment);
  206.             }
  207.             // If still no affiliate found, we put the default one for this site.
  208.             if (!$infos['aff'] instanceof Affiliate) {
  209.                 $infos['aff'] = $site->getSiteDefaultAffiliateId();
  210.             }
  211.             // Get the tracking
  212.             $tracking $infos['tracking'] ?? null;
  213.         } else {
  214.             $tracking null;
  215.             $infos $this->getTrackingInfoFromRequest();
  216.             $infos['origin'] = 'request';
  217.             if (!isset($infos['aff']) or !$infos['aff'] instanceof Affiliate) {
  218.                 $infos['aff'] = $this->em
  219.                     ->getRepository(Affiliate::class)
  220.                     ->loadAffiliateById($infos['aff'], "prod" == $this->environment);
  221.             }
  222.             if (!$infos['aff'] instanceof Affiliate) {
  223.                 $infos['aff'] = $site->getSiteDefaultAffiliateId();
  224.             }
  225.         }
  226.         if (!$tracking instanceof Tracking) {
  227.             // if there is a $oldTracking then it is a rmkg.
  228.             $tracking $this->newTracking($infos$site$oldTracking);
  229.             $tracking->setUserAgent($this->request->headers->get('User-Agent''N/A'));
  230.             if ('' === $tracking->getO1()) {
  231.                 $tracking->setO1('def');
  232.             }
  233.             if ('' == $tracking->getDevice()) {
  234.                 $tracking $this->addDevice($tracking);
  235.             }
  236.             $this->em->flush();
  237.             $infos['origin'] = 'created';
  238.         }
  239.         $infos['tracking_id'] = $tracking->getTrackingId();
  240.         $infos['tracking_hash'] = $this->makeTrackingHash($infos['tracking_id']);
  241.         unset($infos['tracking']);
  242.         // we sae the infos by IP in the cache
  243.         $this->saveTrackingInfoToCache($infos);
  244.         $this->saveTrackingInfoToSession($infos);
  245.         $this->currentTracking $tracking;
  246.         $this->setTrackingOrigin($infos['origin']);
  247.         $this->attachReferrerUserToTracking($tracking);
  248.         // we dynamically inject this info in the tracking.
  249.         // we don't want to insert it in the cookie of the tracking or in the db.
  250.         if ($hasAlreadyPaidInfo) {
  251.             $tracking->setAlreadyPurchasedBefore($hasAlreadyPaidInfo);
  252.             $this->setAlreadyPaidInCache();
  253.         }
  254.         return $tracking;
  255.     }
  256.     /**
  257.      * @param $origin
  258.      */
  259.     public function setTrackingOrigin($origin)
  260.     {
  261.         if ('undefined' == $this->getTrackingOrigin()) {
  262.             $this->trackingOrigin $origin;
  263.         }
  264.     }
  265.     /**
  266.      * @return Tracking
  267.      */
  268.     public function getCurrentTracking()
  269.     {
  270.         return $this->currentTracking ?? $this->resolveTracking();
  271.     }
  272.     /**
  273.      * @return string
  274.      */
  275.     public function getTrackingOrigin()
  276.     {
  277.         return $this->trackingOrigin;
  278.     }
  279.     /**
  280.      * This function is supposed to be user when we detect that the user already had a tracking and we get rid of
  281.      * the new one we just generated for him.
  282.      */
  283.     public function updateCurrentTracking(Tracking $tracking)
  284.     {
  285.         $this->currentTracking $tracking;
  286.         $infosToSave $tracking->getDataForCookie();
  287.         $infosToSave['tracking_hash'] = $this->makeTrackingHash($infosToSave['tracking_id']);
  288.         $this->saveTrackingInfoToCache($infosToSave);
  289.         $this->saveTrackingInfoToSession($infosToSave);
  290.     }
  291.     /**
  292.      * @param Tracking $tracking
  293.      * @param Tracking $originalTracking
  294.      */
  295.     public function addParentTracking(Tracking $trackingTracking $originalTracking)
  296.     {
  297.         $tracking->setParent($originalTracking);
  298.         if (count($originalTracking->getAbTests())) {
  299.             /** @var TrackingHasABTest $oldAbTest */
  300.             foreach ($originalTracking->getAbTests() as $oldAbTest) {
  301.                 // if he already have this AB test, don't add it twice.
  302.                 if ($tracking->alreadyHaveABTest($oldAbTest->getSiteABTest())) {
  303.                     continue;
  304.                 }
  305.                 $newAbTest = new TrackingHasABTest();
  306.                 $newAbTest->setTracking($tracking);
  307.                 $newAbTest->setVersion($oldAbTest->getVersion());
  308.                 $newAbTest->setSiteAbTest($oldAbTest->getSiteABTest());
  309.                 $this->em->persist($newAbTest);
  310.                 $tracking->addAbTest($newAbTest);
  311.             }
  312.         }
  313.     }
  314.     /**
  315.      * @return string
  316.      * @throws NonUniqueResultException
  317.      * @throws InvalidArgumentException
  318.      */
  319.     public function getTemplateDir()
  320.     {
  321.         $tracking $this->resolveTracking();
  322.         $hasDiffDesignVersions $this->siteManager->getYamlConfigParameter('frontend')['hasDiffDesignVersions'];
  323.         $templateDir 'main/views';
  324.         if ($hasDiffDesignVersions) {
  325.             $templateDir 'main/site/views';
  326.             if ($tracking instanceof Tracking
  327.                 && $this->ABTestManager->hasTest($trackingSiteABTest::BRU_DESIGN_V_OLD)
  328.             ) {
  329.                 $templateDir 'main/views';
  330.             }
  331.         }
  332.         return $templateDir;
  333.     }
  334.     /**
  335.      * Returns the tracking info from the Cookie
  336.      *
  337.      * @return array
  338.      * @throws NonUniqueResultException
  339.      */
  340.     private function getTrackingInfoFromCookie(): array
  341.     {
  342.         $cookies $this->request->cookies;
  343.         if (!$cookies->has($this->trackingCookieName)) {
  344.             return [];
  345.         }
  346.         $infos json_decode($cookies->get($this->trackingCookieName), true);
  347.         if (json_last_error() != JSON_ERROR_NONE) {
  348.             return [];
  349.         }
  350.         if (!isset($infos['tracking_id'], $infos['tracking_hash'])
  351.             || !$this->isTrackingHashValid($infos['tracking_hash'], $infos['tracking_id'])
  352.         ) {
  353.             return [];
  354.         }
  355.         $tracking $this->em
  356.             ->getRepository(Tracking::class)
  357.             ->loadTrackingById($infos['tracking_id']);
  358.         if (!$tracking instanceof Tracking) {
  359.             return [];
  360.         }
  361.         $infos['tracking'] = $tracking;
  362.         $infos['aff'] = $tracking->getAff();
  363.         $infos['origin'] = 'cookie';
  364.         return $infos;
  365.     }
  366.     /**
  367.      * @return bool
  368.      * @throws InvalidArgumentException
  369.      */
  370.     private function getAlreadyPaidInfo(): bool
  371.     {
  372.         // first we check in the cache.
  373.         $clientIp $this->getFormatedIpForCache($this->request->getClientIp()) ;
  374.         $cacheKey self::ALREADY_PAID_CACHE_IP_PREFIX $clientIp;
  375.         if ($this->cache->hasItem($cacheKey) && true === $this->cache->getItem($cacheKey)) {
  376.             return true;
  377.         }
  378.         if ($this->getAlreadyPaidInfoFromCookie()) {
  379.             return true;
  380.         }
  381.         return false;
  382.     }
  383.     /**
  384.      * @return array|bool
  385.      */
  386.     private function getAlreadyPaidInfoFromCookie(): bool
  387.     {
  388.         $cookies $this->request->cookies;
  389.         if (!$cookies->has(self::ALREADY_PAID_COOKIE_NAME)) {
  390.             return false;
  391.         }
  392.         return true;
  393.     }
  394.     /**
  395.      * Returns the tracking info from the Session
  396.      * Everything from session is considered ok. No check to do.
  397.      *
  398.      * @return array
  399.      * @throws NonUniqueResultException
  400.      */
  401.     private function getTrackingInfoFromSession(): array
  402.     {
  403.         $trackingInfo $this->request->getSession()->get(self::SESSION_ID);
  404.         $infos = [];
  405.         if (!$trackingInfo) {
  406.             return [];
  407.         }
  408.         $tracking $this->em
  409.             ->getRepository(Tracking::class)
  410.             ->loadTrackingById($trackingInfotrue$this->environment);
  411.         if (!$tracking instanceof Tracking) {
  412.             return [];
  413.         }
  414.         $infos['aff'] = $tracking->getAff();
  415.         $infos['tracking'] = $tracking;
  416.         $infos['origin'] = 'session';
  417.         return $infos;
  418.     }
  419.     /**
  420.      * Returns whether the infos array contains valid value
  421.      *
  422.      * @param array $infos
  423.      *
  424.      * @return bool
  425.      */
  426.     private function isValidTrackingInfo(array $infos): bool
  427.     {
  428.         $filter = function ($value): bool {
  429.             return '' !== $value;
  430.         };
  431.         return !empty(array_filter($infos$filter));
  432.     }
  433.     /**
  434.      * Returns the tracking info from the request GET
  435.      *
  436.      * @return array
  437.      */
  438.     private function getTrackingInfoFromRequest(): array
  439.     {
  440.         $reducer = function (array $carrystring $name): array {
  441.             $carry[$name] = $this->request->get($name'');
  442.             return $carry;
  443.         };
  444.         return array_reduce($this->params$reducer, []);
  445.     }
  446.     /**
  447.      * Returns the tracking info from the request GET
  448.      *
  449.      * @return array
  450.      */
  451.     private function getAdditionalTrackingInfoFromRequest(): array
  452.     {
  453.         $reducer = function (array $carrystring $name): array {
  454.             $carry[$name] = $this->request->get($name'');
  455.             return $carry;
  456.         };
  457.         return array_reduce($this->additionalParams$reducer, []);
  458.     }
  459.     /**
  460.      * Tell whether the hash is valid
  461.      *
  462.      * @param string $hash
  463.      * @param string $str
  464.      *
  465.      * @return bool
  466.      */
  467.     private function isTrackingHashValid(string $hashstring $str): bool
  468.     {
  469.         return hash_equals($hash$this->makeTrackingHash($str));
  470.     }
  471.     /**
  472.      * @param array $additionalTrackingInfoArray
  473.      * @param Tracking $tracking
  474.      */
  475.     private function saveAdditionalTrackingValues(array $additionalTrackingInfoArrayTracking $tracking)
  476.     {
  477.         foreach ($this->additionalParams as $additionalParam) {
  478.             if (array_search($additionalTrackingInfoArray[$additionalParam], $additionalTrackingInfoArray) === 'aecid') {
  479.                 if ($tracking->getO5() == '') {
  480.                     $tracking->setO5($additionalTrackingInfoArray[$additionalParam]);
  481.                 } else {
  482.                     $message 'aecid value of tracking could not be stored on o5';
  483.                     $this->logger->warning($message);
  484.                 }
  485.             }
  486.         }
  487.     }
  488.     /**
  489.      * Create a new Tracking object from an array
  490.      *
  491.      * @param array $resolvedArr
  492.      * @param Site $site
  493.      *
  494.      * @return Tracking
  495.      * @throws \Exception
  496.      */
  497.     private function newTracking(array $resolvedArrSite $siteTracking $oldTracking null): Tracking
  498.     {
  499.         $resolvedArr['o1'] = $resolvedArr['o1'] ?? '';
  500.         $resolvedArr['o1'] = trim($resolvedArr['o1']);
  501.         if ('' === $resolvedArr['o1']) {
  502.             $siteProps $site->getProperties();
  503.             $resolvedArr['o1'] = $siteProps['default-tracking-params']['o1'] ?? self::DEFAULT_TRACKING_O1;
  504.         }
  505.         $tracking = new Tracking();
  506.         foreach ($this->params as $p) {
  507.             if (isset($resolvedArr[$p]) && $resolvedArr[$p] != '') {
  508.                 $methodName 'set' strtoupper($p);
  509.                 $tracking->{$methodName}($resolvedArr[$p]);
  510.             }
  511.         }
  512.         $additionalTrackingInfoArray $this->getAdditionalTrackingInfoFromRequest();
  513.         if (count($additionalTrackingInfoArray)) {
  514.             $this->saveAdditionalTrackingValues($additionalTrackingInfoArray$tracking);
  515.         }
  516.         if (!$tracking->getAff() instanceof Affiliate) {
  517.             $tracking->setAff($site->getSiteDefaultAffiliateId());
  518.         }
  519.         $this->em->persist($tracking);
  520.         if ($oldTracking instanceof Tracking) {
  521.             $originalTracking $oldTracking->getParent() ?? $oldTracking;
  522.             $this->addParentTracking($tracking$originalTracking);
  523.             $tracking->setRmkg(1);
  524.         } else {
  525.             // if it is a real new tracking we create new tests for it.
  526.             $this->ABTestManager->generateTestsForTracking($tracking$site);
  527.         }
  528.         return $this->addDevice($tracking);
  529.     }
  530.     /**
  531.      * @param Tracking $tracking
  532.      * @return Tracking
  533.      */
  534.     private function addDevice(Tracking $tracking): Tracking
  535.     {
  536.         if (null === $this->detector) {
  537.             return $tracking;
  538.         }
  539.         if ($this->detector->isTablet()) {
  540.             return $tracking->setDevice(Tracking::DEVICE_TABLET);
  541.         }
  542.         if ($this->detector->isMobile()) {
  543.             return $tracking->setDevice(Tracking::DEVICE_MOBILE);
  544.         }
  545.         return $tracking->setDevice(Tracking::DEVICE_DESKTOP);
  546.     }
  547.     /**
  548.      * @param Tracking $tracking
  549.      */
  550.     private function attachReferrerUserToTracking(Tracking $tracking)
  551.     {
  552.         $referralCode $this->request->query->get(ReferralProgramManager::USER_REFERRAL_KEY) ?? null;
  553.         if (null == $referralCode) {
  554.             return;
  555.         }
  556.         //if this tracking already has referrer we keep the old one and dont create new.
  557.         $trHasReferrer $this->em->getRepository(TrackingHasReferrer::class)
  558.             ->findOneBy(['trackingId' => $tracking->getTrackingId()]);
  559.         if ($trHasReferrer instanceof TrackingHasReferrer) {
  560.             return;
  561.         }
  562.         // check if user exists
  563.         $userReferrerId substr($referralCodestrlen(ReferralProgramManager::USER_REFERRAL_PREFIX));
  564.         $userReferrer $this->em->getRepository(User::class)->findOneBy(['id' => $userReferrerId]);
  565.         if (!$userReferrer instanceof User) {
  566.             return;
  567.         }
  568.         //check if program is enabled for the user
  569.         if (!$this->referralProgramManager->isReferralProgramEnabled($userReferrernull)) {
  570.             return;
  571.         }
  572.         //create tracking has referrer.
  573.         $trackingHasReferrer = new TrackingHasReferrer();
  574.         $trackingHasReferrer->setTrackingId($tracking->getTrackingId());
  575.         $trackingHasReferrer->setReferrerUser($userReferrer);
  576.         $this->em->persist($trackingHasReferrer);
  577.         $this->em->flush();
  578.     }
  579.     /**
  580.      * Generate a tracking hash for a given string
  581.      *
  582.      * @param string $str
  583.      *
  584.      * @return string
  585.      */
  586.     private function makeTrackingHash(string $str): string
  587.     {
  588.         return hash_hmac('sha256'$str$this->trackingCookieSecretfalse);
  589.     }
  590.     /**
  591.      * Returns the tracking info from the Cache
  592.      *
  593.      * @param null|mixed $client_ip
  594.      * @return array
  595.      * @throws InvalidArgumentException
  596.      */
  597.     public function getTrackingInfoFromCache($client_ip null): array
  598.     {
  599.         $client_ip $client_ip ?? $this->request->getClientIp();
  600.         $infosCacheItem $this->cache->getItem(self::CACHE_IP_INFO_PREFIX $this->getFormatedIpForCache($client_ip));
  601.         if (!$infosCacheItem->isHit()) {
  602.             return [];
  603.         }
  604.         $infos $infosCacheItem->get();
  605.         $tracking $this->em
  606.             ->getRepository(Tracking::class)
  607.             ->loadTrackingById($infos['tracking_id']);
  608.         if (!$tracking instanceof Tracking) {
  609.             return [];
  610.         }
  611.         $infos['tracking'] = $tracking;
  612.         $infos['aff'] = $tracking->getAff();
  613.         $infos['origin'] = 'cache';
  614.         return $infos;
  615.     }
  616.     /**
  617.      * Save tracking info to the Cache
  618.      *
  619.      * @param array $infos
  620.      *
  621.      * @return bool
  622.      * @throws InvalidArgumentException
  623.      */
  624.     private function saveTrackingInfoToCache(array $infos): bool
  625.     {
  626.         // we don't want to save an object into the cache, so transform it to id
  627.         if ($infos['aff'] instanceof Affiliate) {
  628.             $infos['aff'] = $infos['aff']->getAffiliateId();
  629.         }
  630.         $infosCacheItem $this->cache->getItem(self::CACHE_IP_INFO_PREFIX $this->getFormatedIpForCache($this->request->getClientIp()));
  631.         $infosCacheItem->set($infos);
  632.         $infosCacheItem->expiresAfter(new DateInterval('P15D'));
  633.         return $this->cache->save($infosCacheItem);
  634.     }
  635.     /**
  636.      * @param $infos
  637.      */
  638.     private function saveTrackingInfoToSession($infos)
  639.     {
  640.         $this->request->getSession()->set(self::SESSION_ID$infos['tracking_id']);
  641.     }
  642.     /**
  643.      * @param null $ip
  644.      * @return bool
  645.      * @throws InvalidArgumentException
  646.      */
  647.     public function setAlreadyPaidInCache($ip null)
  648.     {
  649.         if (null === $ip) {
  650.             $ip $this->request->getClientIp();
  651.         }
  652.         $infosCacheItem $this->cache->getItem(self::ALREADY_PAID_CACHE_IP_PREFIX $this->getFormatedIpForCache($ip));
  653.         $infosCacheItem->set(true);
  654.         $infosCacheItem->expiresAfter(new DateInterval('PT12H'));
  655.         return $this->cache->save($infosCacheItem);
  656.     }
  657.     /**
  658.      * @param null $ip
  659.      * @return bool
  660.      * @throws InvalidArgumentException
  661.      */
  662.     public function clearAlreadyPaidInCache($ip null)
  663.     {
  664.         if (null === $ip) {
  665.             $ip $this->request->getClientIp();
  666.         }
  667.         $this->cache->deleteItem(self::ALREADY_PAID_CACHE_IP_PREFIX $this->getFormatedIpForCache($ip));
  668.     }
  669.     /**
  670.      * @param $ip
  671.      * @return string|string[]
  672.      */
  673.     private function getFormatedIpForCache($ip)
  674.     {
  675.         return str_replace(':''.'$ip);
  676.     }
  677. }