/** * @param string|Stat $stat * @param $request * @param bool $viaBrowser */ public function hitEmail($stat, $request, $viaBrowser = false) { if (!$stat instanceof Stat) { $stat = $this->getEmailStatus($stat); } if (!$stat) { return; } $email = $stat->getEmail(); if ((int) $stat->isRead()) { if ($viaBrowser && !$stat->getViewedInBrowser()) { //opened via browser so note it $stat->setViewedInBrowser($viaBrowser); } } $readDateTime = new DateTimeHelper(); $stat->setLastOpened($readDateTime->getDateTime()); $lead = $stat->getLead(); if ($lead !== null) { // Set the lead as current lead $this->leadModel->setCurrentLead($lead); } $firstTime = false; if (!$stat->getIsRead()) { $firstTime = true; $stat->setIsRead(true); $stat->setDateRead($readDateTime->getDateTime()); // Only up counts if associated with both an email and lead if ($email && $lead) { try { $this->getRepository()->upCount($email->getId(), 'read', 1, $email->isVariant()); } catch (\Exception $exception) { error_log($exception); } } } if ($viaBrowser) { $stat->setViewedInBrowser($viaBrowser); } $stat->addOpenDetails(['datetime' => $readDateTime->toUtcString(), 'useragent' => $request->server->get('HTTP_USER_AGENT'), 'inBrowser' => $viaBrowser]); //check for existing IP $ipAddress = $this->ipLookupHelper->getIpAddress(); $stat->setIpAddress($ipAddress); if ($this->dispatcher->hasListeners(EmailEvents::EMAIL_ON_OPEN)) { $event = new EmailOpenEvent($stat, $request, $firstTime); $this->dispatcher->dispatch(EmailEvents::EMAIL_ON_OPEN, $event); } //device granularity $dd = new DeviceDetector($request->server->get('HTTP_USER_AGENT')); $dd->parse(); $deviceRepo = $this->leadModel->getDeviceRepository(); $emailOpenDevice = $deviceRepo->getDevice(null, $lead, $dd->getDeviceName(), $dd->getBrand(), $dd->getModel()); if (empty($emailOpenDevice)) { $emailOpenDevice = new LeadDevice(); $emailOpenDevice->setClientInfo($dd->getClient()); $emailOpenDevice->setDevice($dd->getDeviceName()); $emailOpenDevice->setDeviceBrand($dd->getBrand()); $emailOpenDevice->setDeviceModel($dd->getModel()); $emailOpenDevice->setDeviceOs($dd->getOs()); $emailOpenDevice->setDateOpen($readDateTime->toUtcString()); $emailOpenDevice->setLead($lead); try { $this->em->persist($emailOpenDevice); $this->em->flush($emailOpenDevice); } catch (\Exception $exception) { if (MAUTIC_ENV === 'dev') { throw $exception; } else { $this->logger->addError($exception->getMessage(), ['exception' => $exception]); } } } else { $emailOpenDevice = $deviceRepo->getEntity($emailOpenDevice['id']); } if ($email) { $this->em->persist($email); $this->em->flush($email); } if (isset($emailOpenDevice) and is_object($emailOpenDevice)) { $emailOpenStat = new StatDevice(); $emailOpenStat->setIpAddress($ipAddress); $emailOpenStat->setDevice($emailOpenDevice); $emailOpenStat->setDateOpened($readDateTime->toUtcString()); $emailOpenStat->setStat($stat); $this->em->persist($emailOpenStat); $this->em->flush($emailOpenStat); } $this->em->persist($stat); $this->em->flush(); }
/** * Record page hit. * * @param $page * @param Request $request * @param string $code * @param Lead|null $lead * @param array $query * * @return Hit $hit * * @throws \Exception */ public function hitPage($page, Request $request, $code = '200', Lead $lead = null, $query = []) { // Don't skew results with user hits if (!$this->security->isAnonymous()) { return; } // Process the query if (empty($query)) { $query = $this->getHitQuery($request, $page); } $hit = new Hit(); $hit->setDateHit(new \Datetime()); // Check for existing IP $ipAddress = $this->ipLookupHelper->getIpAddress(); $hit->setIpAddress($ipAddress); // Check for any clickthrough info $clickthrough = []; if (!empty($query['ct'])) { $clickthrough = $query['ct']; if (!is_array($clickthrough)) { $clickthrough = $this->decodeArrayFromUrl($clickthrough); } if (!empty($clickthrough['channel'])) { if (count($clickthrough['channel']) === 1) { $channelId = reset($clickthrough['channel']); $channel = key($clickthrough['channel']); } else { $channel = $clickthrough['channel'][0]; $channelId = (int) $clickthrough['channel'][1]; } $hit->setSource($channel); $hit->setSourceId($channelId); } elseif (!empty($clickthrough['source'])) { $hit->setSource($clickthrough['source'][0]); $hit->setSourceId($clickthrough['source'][1]); } if (!empty($clickthrough['email'])) { $emailRepo = $this->em->getRepository('MauticEmailBundle:Email'); if ($emailEntity = $emailRepo->getEntity($clickthrough['email'])) { $hit->setEmail($emailEntity); } } } // Get lead if required if (null == $lead) { $lead = $this->leadModel->getContactFromRequest($query); } $this->leadModel->saveEntity($lead); // Set info from request $hit->setQuery($query); $hit->setUrl(isset($query['page_url']) ? $query['page_url'] : $request->getRequestUri()); if (isset($query['page_referrer'])) { $hit->setReferer($query['page_referrer']); } if (isset($query['page_language'])) { $hit->setPageLanguage($query['page_language']); } if (isset($query['page_title'])) { $hit->setUrlTitle($query['page_title']); } // Store tracking ID list($trackingId, $trackingNewlyGenerated) = $this->leadModel->getTrackingCookie(); $hit->setTrackingId($trackingId); $hit->setLead($lead); $isUnique = $trackingNewlyGenerated; if (!$trackingNewlyGenerated) { $lastHit = $request->cookies->get('mautic_referer_id'); if (!empty($lastHit)) { //this is not a new session so update the last hit if applicable with the date/time the user left $this->getHitRepository()->updateHitDateLeft($lastHit); } // Check if this is a unique page hit $isUnique = $this->getHitRepository()->isUniquePageHit($page, $trackingId); } if (!empty($page)) { if ($page instanceof Page) { $hit->setPage($page); $hit->setPageLanguage($page->getLanguage()); $isVariant = $isUnique ? $page->getVariantStartDate() : false; try { $this->getRepository()->upHitCount($page->getId(), 1, $isUnique, !empty($isVariant)); } catch (\Exception $exception) { $this->logger->addError($exception->getMessage(), ['exception' => $exception]); } } elseif ($page instanceof Redirect) { $hit->setRedirect($page); try { $this->pageRedirectModel->getRepository()->upHitCount($page->getId(), 1, $isUnique); // If this is a trackable, up the trackable counts as well if (!empty($clickthrough['channel'])) { $channelId = reset($clickthrough['channel']); $channel = key($clickthrough['channel']); $this->pageTrackableModel->getRepository()->upHitCount($page->getId(), $channel, $channelId, 1, $isUnique); } } catch (\Exception $exception) { if (MAUTIC_ENV === 'dev') { throw $exception; } else { $this->logger->addError($exception->getMessage(), ['exception' => $exception]); } } } } //glean info from the IP address if ($details = $ipAddress->getIpDetails()) { $hit->setCountry($details['country']); $hit->setRegion($details['region']); $hit->setCity($details['city']); $hit->setIsp($details['isp']); $hit->setOrganization($details['organization']); } $hit->setCode($code); if (!$hit->getReferer()) { $hit->setReferer($request->server->get('HTTP_REFERER')); } $hit->setUserAgent($request->server->get('HTTP_USER_AGENT')); $hit->setRemoteHost($request->server->get('REMOTE_HOST')); if ($isUnique) { // Add UTM tags entry if a UTM tag exist $queryHasUtmTags = false; if (!is_array($query)) { parse_str($query, $query); } foreach ($query as $key => $value) { if (strpos($key, 'utm_') !== false) { $queryHasUtmTags = true; break; } } if ($queryHasUtmTags) { $utmTags = new UtmTag(); $utmTags->setDateAdded($hit->getDateHit()); $utmTags->setUrl($hit->getUrl()); $utmTags->setReferer($hit->getReferer()); $utmTags->setQuery($hit->getQuery()); $utmTags->setUserAgent($hit->getUserAgent()); $utmTags->setRemoteHost($hit->getRemoteHost()); $utmTags->setLead($lead); if (key_exists('utm_campaign', $query)) { $utmTags->setUtmCampaign($query['utm_campaign']); } if (key_exists('utm_term', $query)) { $utmTags->setUtmTerm($query['utm_term']); } if (key_exists('utm_content', $query)) { $utmTags->setUtmConent($query['utm_content']); } if (key_exists('utm_medium', $query)) { $utmTags->setUtmMedium($query['utm_medium']); } if (key_exists('utm_source', $query)) { $utmTags->setUtmSource($query['utm_source']); } $repo = $this->em->getRepository('MauticLeadBundle:UtmTag'); $repo->saveEntity($utmTags); $this->leadModel->setUtmTags($lead, $utmTags); } } //get a list of the languages the user prefers $browserLanguages = $request->server->get('HTTP_ACCEPT_LANGUAGE'); if (!empty($browserLanguages)) { $languages = explode(',', $browserLanguages); foreach ($languages as $k => $l) { if ($pos = strpos(';q=', $l) !== false) { //remove weights $languages[$k] = substr($l, 0, $pos); } } $hit->setBrowserLanguages($languages); } //device granularity $dd = new DeviceDetector($request->server->get('HTTP_USER_AGENT')); $dd->parse(); $deviceRepo = $this->leadModel->getDeviceRepository(); $device = $deviceRepo->getDevice(null, $lead, $dd->getDeviceName(), $dd->getBrand(), $dd->getModel()); if (empty($device)) { $device = new LeadDevice(); $device->setClientInfo($dd->getClient()); $device->setDevice($dd->getDeviceName()); $device->setDeviceBrand($dd->getBrand()); $device->setDeviceModel($dd->getModel()); $device->setDeviceOs($dd->getOs()); $device->setDateOpen($hit->getDateHit()); $device->setLead($lead); $this->em->persist($device); } else { $device = $deviceRepo->getEntity($device['id']); } $hit->setDeviceStat($device); // Wrap in a try/catch to prevent deadlock errors on busy servers try { $this->em->persist($hit); $this->em->flush($hit); } catch (\Exception $exception) { if (MAUTIC_ENV === 'dev') { throw $exception; } else { $this->logger->addError($exception->getMessage(), ['exception' => $exception]); } } if ($this->dispatcher->hasListeners(PageEvents::PAGE_ON_HIT)) { $event = new PageHitEvent($hit, $request, $code, $clickthrough, $isUnique); $this->dispatcher->dispatch(PageEvents::PAGE_ON_HIT, $event); } //save hit to the cookie to use to update the exit time $this->cookieHelper->setCookie('mautic_referer_id', $hit->getId()); return $hit; }