getCurrentRequest(); if ($request && $request->cookies->get('Blocked-Tracking')) { return null; } $ipAddress = $this->ipLookupHelper->getIpAddress(); if (!$ipAddress->isTrackable()) { return null; } $dateTime = new \DateTime(); $userAgent = $request ? $request->server->get('HTTP_USER_AGENT') : ''; if (!empty($queryFields['ct'])) { $queryFields['ct'] = (is_array($queryFields['ct'])) ? $queryFields['ct'] : ClickthroughHelper::decodeArrayFromUrl($queryFields['ct']); } if (isset($queryFields['ct']['stat'])) { /** @var Stat $stat */ $stat = $this->statRepository->findOneBy(['trackingHash' => $queryFields['ct']['stat']]); if (null !== $stat && $this->botRatioHelper->isHitByBot($stat, $dateTime, $ipAddress, (string) $userAgent)) { return null; } } unset($queryFields['page_url']); // This is set now automatically by PageModel $this->queryFields = $queryFields; try { $foundContact = $this->getContactFromUrl(); $this->trackedContact = $foundContact; $this->contactTracker->setTrackedContact($this->trackedContact); } catch (ContactNotFoundException) { } if (!$this->trackedContact) { $this->trackedContact = $this->contactTracker->getContact(); } if (!$this->trackedContact) { return null; } $this->prepareContactFromRequest(); return $this->trackedContact; } /** * @throws ContactNotFoundException */ private function getContactFromUrl(): Lead { $request = $this->getCurrentRequest(); if ($request && $request->cookies->get('Blocked-Tracking')) { throw new ContactNotFoundException(); } // Check for a lead requested through clickthrough query parameter if (isset($this->queryFields['ct'])) { $clickthrough = (is_array($this->queryFields['ct'])) ? $this->queryFields['ct'] : ClickthroughHelper::decodeArrayFromUrl($this->queryFields['ct']); } elseif ($request && $clickthrough = $request->get('ct', [])) { $clickthrough = ClickthroughHelper::decodeArrayFromUrl($clickthrough); } if (!is_array($clickthrough)) { throw new ContactNotFoundException(); } try { return $this->getContactFromClickthrough($clickthrough); } catch (ContactNotFoundException) { } /* @var Lead $foundContact */ if (!empty($this->queryFields)) { [$foundContact, $this->publiclyUpdatableFieldValues] = $this->leadModel->checkForDuplicateContact( $this->queryFields, true, true ); if ($this->trackedContact && $this->trackedContact->getId() && $foundContact->getId()) { try { $foundContact = $this->contactMerger->merge($this->trackedContact, $foundContact); } catch (SameContactException) { } } if (is_null($this->trackedContact) or $foundContact->getId() !== $this->trackedContact->getId()) { // A contact was found by a publicly updatable field if (!$foundContact->isNew()) { return $foundContact; } } } throw new ContactNotFoundException(); } /** * Identify a contact through a clickthrough URL. * * @return Lead * * @throws ContactNotFoundException */ private function getContactFromClickthrough(array $clickthrough) { $event = new ContactIdentificationEvent($clickthrough); $this->eventDispatcher->dispatch($event, LeadEvents::ON_CLICKTHROUGH_IDENTIFICATION); if ($contact = $event->getIdentifiedContact()) { $this->logger->debug("LEAD: Contact ID# {$contact->getId()} tracked through clickthrough query by the ".$event->getIdentifier().' channel'); // Merge tracked visitor into the clickthrough contact return $this->mergeWithTrackedContact($contact); } throw new ContactNotFoundException(); } private function prepareContactFromRequest(): void { $ipAddress = $this->ipLookupHelper->getIpAddress(); $contactIpAddresses = $this->trackedContact->getIpAddresses(); if (!$contactIpAddresses->contains($ipAddress)) { $this->trackedContact->addIpAddress($ipAddress); } if (!empty($this->publiclyUpdatableFieldValues)) { $this->leadModel->setFieldValues( $this->trackedContact, $this->publiclyUpdatableFieldValues, false, true, true ); } // Assume a web request as this is likely a tracking request from DWC or tracking code $this->trackedContact->setManipulator( new LeadManipulator( 'page', 'hit', null, $this->queryFields['page_url'] ?? '' ) ); if (isset($this->queryFields['tags'])) { $this->leadModel->modifyTags($this->trackedContact, $this->queryFields['tags']); } } /** * @return Lead */ private function mergeWithTrackedContact(Lead $foundContact) { if ($this->trackedContact && $this->trackedContact->getId() && $this->trackedContact->isAnonymous()) { try { return $this->contactMerger->merge($this->trackedContact, $foundContact); } catch (SameContactException) { } } return $foundContact; } private function getCurrentRequest(): ?Request { return $this->requestStack->getCurrentRequest(); } }