/** * Parses content for URLs and tokens. * * @param EmailSendEvent $event * @param $emailId * * @return mixed */ protected function parseContentForUrls(EmailSendEvent $event, $emailId) { static $convertedContent = []; // Prevent parsing the exact same content over and over if (!isset($convertedContent[$event->getContentHash()])) { $html = $event->getContent(); $text = $event->getPlainText(); $contentTokens = $event->getTokens(); list($content, $trackables) = $this->pageTrackableModel->parseContentForTrackables([$html, $text], $contentTokens, $emailId ? 'email' : null, $emailId); list($html, $text) = $content; unset($content); if ($html) { $event->setContent($html); } if ($text) { $event->setPlainText($text); } $convertedContent[$event->getContentHash()] = $trackables; // Don't need to preserve Trackable or Redirect entities in memory $this->em->clear('Mautic\\PageBundle\\Entity\\Redirect'); $this->em->clear('Mautic\\PageBundle\\Entity\\Trackable'); unset($html, $text, $trackables); } return $convertedContent[$event->getContentHash()]; }
/** * @param $focus * @param bool $preview * @param bool $ignoreMinify * * @return string */ public function generateJavascript($focus, $preview = false, $ignoreMinify = false) { if ($focus instanceof Focus) { $focus = $focus->toArray(); } if (!empty($focus['form'])) { $form = $this->formModel->getEntity($focus['form']); } else { $form = null; } if ($preview) { $content = ['style' => '', 'html' => $this->templating->getTemplating()->render('MauticFocusBundle:Builder:content.html.php', ['focus' => $focus, 'form' => $form, 'preview' => $preview])]; } else { // Generate link if applicable $url = ''; if ($focus['type'] == 'link') { $trackable = $this->trackableModel->getTrackableByUrl($focus['properties']['content']['link_url'], 'focus', $focus['id']); $url = $this->trackableModel->generateTrackableUrl($trackable, ['channel' => ['focus', $focus['id']]]); } $content = $this->templating->getTemplating()->render('MauticFocusBundle:Builder:generate.js.php', ['focus' => $focus, 'form' => $form, 'preview' => $preview, 'ignoreMinify' => $ignoreMinify, 'clickUrl' => $url]); if (!$ignoreMinify) { $content = \JSMin::minify($content); } } return $content; }
/** * PreParse the twitter message and replace placeholders with values. * * @param $tweet * @param $lead * * @return mixed */ protected function parseTweetText($tweet, $lead) { $tweetHandle = $lead['twitter']; $tokens = ['{twitter_handle}' => strpos($tweetHandle, '@') !== false ? $tweetHandle : "@{$tweetHandle}"]; $tokens = array_merge($tokens, TokenHelper::findLeadTokens($tweet, $lead), $this->pageTokenHelper->findPageTokens($tweet, $this->clickthrough), $this->assetTokenHelper->findAssetTokens($tweet, $this->clickthrough)); list($tweet, $trackables) = $this->trackableModel->parseContentForTrackables($tweet, $tokens, 'social_twitter', -1); /** * @var string $token * @var Trackable $trackable */ foreach ($trackables as $token => $trackable) { $tokens[$token] = $this->trackableModel->generateTrackableUrl($trackable, $this->clickthrough); } return str_replace(array_keys($tokens), array_values($tokens), $tweet); }
/** * @param TokenReplacementEvent $event */ public function onTokenReplacement(TokenReplacementEvent $event) { /** @var Lead $lead */ $lead = $event->getLead(); $content = $event->getContent(); $clickthrough = $event->getClickthrough(); if ($content) { $tokens = array_merge(TokenHelper::findLeadTokens($content, $lead->getProfileFields()), $this->pageTokenHelper->findPageTokens($content, $clickthrough), $this->assetTokenHelper->findAssetTokens($content, $clickthrough)); list($content, $trackables) = $this->trackableModel->parseContentForTrackables($content, $tokens, 'sms', $clickthrough['channel'][1]); /** * @var string * @var Trackable $trackable */ foreach ($trackables as $token => $trackable) { $tokens[$token] = $this->trackableModel->generateTrackableUrl($trackable, $clickthrough, true); } $content = str_replace(array_keys($tokens), array_values($tokens), $content); $event->setContent($content); } }
/** * Get an array of tracked links * * @param $emailId * * @return array */ public function getEmailClickStats($emailId) { return $this->pageTrackableModel->getTrackableList('email', $emailId); }
/** * 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; }
/** * Get an array of tracked links. * * @param $notificationId * * @return array */ public function getNotificationClickStats($notificationId) { return $this->pageTrackableModel->getTrackableList('notification', $notificationId); }
/** * Get an array of tracked links. * * @param $smsId * * @return array */ public function getSmsClickStats($smsId) { return $this->pageTrackableModel->getTrackableList('sms', $smsId); }