Ejemplo n.º 1
0
 /**
  * Create/update lead from form submit.
  *
  * @param       $form
  * @param array $leadFieldMatches
  *
  * @return Lead
  */
 protected function createLeadFromSubmit($form, array $leadFieldMatches, $leadFields)
 {
     //set the mapped data
     $inKioskMode = $form->isInKioskMode();
     if (!$inKioskMode) {
         // Default to currently tracked lead
         $lead = $this->leadModel->getCurrentLead();
         $leadId = $lead->getId();
         $currentFields = $this->leadModel->flattenFields($lead->getFields());
         $this->logger->debug('FORM: Not in kiosk mode so using current contact ID #' . $lead->getId());
     } else {
         // Default to a new lead in kiosk mode
         $lead = new Lead();
         $lead->setNewlyCreated(true);
         $currentFields = $leadFieldMatches;
         $leadId = null;
         $this->logger->debug('FORM: In kiosk mode so assuming a new contact');
     }
     $uniqueLeadFields = $this->leadFieldModel->getUniqueIdentiferFields();
     // Closure to get data and unique fields
     $getData = function ($currentFields, $uniqueOnly = false) use($leadFields, $uniqueLeadFields) {
         $uniqueFieldsWithData = $data = [];
         foreach ($leadFields as $alias => $properties) {
             $data[$alias] = '';
             if (isset($currentFields[$alias])) {
                 $value = $currentFields[$alias];
                 $data[$alias] = $value;
                 // make sure the value is actually there and the field is one of our uniques
                 if (!empty($value) && array_key_exists($alias, $uniqueLeadFields)) {
                     $uniqueFieldsWithData[$alias] = $value;
                 }
             }
         }
         return $uniqueOnly ? $uniqueFieldsWithData : [$data, $uniqueFieldsWithData];
     };
     // Closure to help search for a conflict
     $checkForIdentifierConflict = function ($fieldSet1, $fieldSet2) {
         // Find fields in both sets
         $potentialConflicts = array_keys(array_intersect_key($fieldSet1, $fieldSet2));
         $this->logger->debug('FORM: Potential conflicts ' . implode(', ', array_keys($potentialConflicts)) . ' = ' . implode(', ', $potentialConflicts));
         $conflicts = [];
         foreach ($potentialConflicts as $field) {
             if (!empty($fieldSet1[$field]) && !empty($fieldSet2[$field])) {
                 if (strtolower($fieldSet1[$field]) !== strtolower($fieldSet2[$field])) {
                     $conflicts[] = $field;
                 }
             }
         }
         return [count($conflicts), $conflicts];
     };
     // Get data for the form submission
     list($data, $uniqueFieldsWithData) = $getData($leadFieldMatches);
     $this->logger->debug('FORM: Unique fields submitted include ' . implode(', ', $uniqueFieldsWithData));
     // Check for duplicate lead
     /** @var \Mautic\LeadBundle\Entity\Lead[] $leads */
     $leads = !empty($uniqueFieldsWithData) ? $this->em->getRepository('MauticLeadBundle:Lead')->getLeadsByUniqueFields($uniqueFieldsWithData, $leadId) : [];
     $uniqueFieldsCurrent = $getData($currentFields, true);
     if (count($leads)) {
         $this->logger->debug(count($leads) . ' found based on unique identifiers');
         /** @var \Mautic\LeadBundle\Entity\Lead $foundLead */
         $foundLead = $leads[0];
         $this->logger->debug('FORM: Testing contact ID# ' . $foundLead->getId() . ' for conflicts');
         // Check for a conflict with the currently tracked lead
         $foundLeadFields = $this->leadModel->flattenFields($foundLead->getFields());
         // Get unique identifier fields for the found lead then compare with the lead currently tracked
         $uniqueFieldsFound = $getData($foundLeadFields, true);
         list($hasConflict, $conflicts) = $checkForIdentifierConflict($uniqueFieldsFound, $uniqueFieldsCurrent);
         if ($inKioskMode || $hasConflict) {
             // Use the found lead without merging because there is some sort of conflict with unique identifiers or in kiosk mode and thus should not merge
             $lead = $foundLead;
             if ($hasConflict) {
                 $this->logger->debug('FORM: Conflicts found in ' . implode(', ', $conflicts) . ' so not merging');
             } else {
                 $this->logger->debug('FORM: In kiosk mode so not merging');
             }
         } else {
             $this->logger->debug('FORM: Merging contacts ' . $lead->getId() . ' and ' . $foundLead->getId());
             // Merge the found lead with currently tracked lead
             $lead = $this->leadModel->mergeLeads($lead, $foundLead);
         }
         // Update unique fields data for comparison with submitted data
         $currentFields = $this->leadModel->flattenFields($lead->getFields());
         $uniqueFieldsCurrent = $getData($currentFields, true);
     }
     if (!$inKioskMode) {
         // Check for conflicts with the submitted data and the currently tracked lead
         list($hasConflict, $conflicts) = $checkForIdentifierConflict($uniqueFieldsWithData, $uniqueFieldsCurrent);
         $this->logger->debug('FORM: Current unique contact fields ' . implode(', ', array_keys($uniqueFieldsCurrent)) . ' = ' . implode(', ', $uniqueFieldsCurrent));
         $this->logger->debug('FORM: Submitted unique contact fields ' . implode(', ', array_keys($uniqueFieldsWithData)) . ' = ' . implode(', ', $uniqueFieldsWithData));
         if ($hasConflict) {
             // There's a conflict so create a new lead
             $lead = new Lead();
             $lead->setNewlyCreated(true);
             $this->logger->debug('FORM: Conflicts found in ' . implode(', ', $conflicts) . ' between current tracked contact and submitted data so assuming a new contact');
         }
     }
     //check for existing IP address
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     //no lead was found by a mapped email field so create a new one
     if ($lead->isNewlyCreated()) {
         if (!$inKioskMode) {
             $lead->addIpAddress($ipAddress);
             $this->logger->debug('FORM: Associating ' . $ipAddress->getIpAddress() . ' to contact');
         }
     } elseif (!$inKioskMode) {
         $leadIpAddresses = $lead->getIpAddresses();
         if (!$leadIpAddresses->contains($ipAddress)) {
             $lead->addIpAddress($ipAddress);
             $this->logger->debug('FORM: Associating ' . $ipAddress->getIpAddress() . ' to contact');
         }
     }
     //set the mapped fields
     $this->leadModel->setFieldValues($lead, $data, false);
     if (!empty($event)) {
         $event->setIpAddress($ipAddress);
         $lead->addPointsChangeLog($event);
     }
     // last active time
     $lead->setLastActive(new \DateTime());
     //create a new lead
     $this->leadModel->saveEntity($lead, false);
     if (!$inKioskMode) {
         // Set the current lead which will generate tracking cookies
         $this->leadModel->setCurrentLead($lead);
     } else {
         // Set system current lead which will still allow execution of events without generating tracking cookies
         $this->leadModel->setSystemCurrentLead($lead);
     }
     return $lead;
 }
Ejemplo n.º 2
0
 /**
  * @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();
 }
Ejemplo n.º 3
0
 /**
  * @param $asset
  * @param null   $request
  * @param string $code
  * @param array  $systemEntry
  *
  * @throws \Doctrine\ORM\ORMException
  * @throws \Exception
  */
 public function trackDownload($asset, $request = null, $code = '200', $systemEntry = [])
 {
     // Don't skew results with in-house downloads
     if (empty($systemEntry) && !$this->security->isAnonymous()) {
         return;
     }
     if ($request == null) {
         $request = $this->request;
     }
     $download = new Download();
     $download->setDateDownload(new \Datetime());
     // Download triggered by lead
     if (empty($systemEntry)) {
         //check for any clickthrough info
         $clickthrough = $request->get('ct', false);
         if (!empty($clickthrough)) {
             $clickthrough = $this->decodeArrayFromUrl($clickthrough);
             if (!empty($clickthrough['lead'])) {
                 $lead = $this->leadModel->getEntity($clickthrough['lead']);
                 if ($lead !== null) {
                     $this->leadModel->setLeadCookie($clickthrough['lead']);
                     list($trackingId, $trackingNewlyGenerated) = $this->leadModel->getTrackingCookie();
                     $leadClickthrough = true;
                     $this->leadModel->setCurrentLead($lead);
                 }
             }
             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];
                 }
                 $download->setSource($channel);
                 $download->setSourceId($channelId);
             } elseif (!empty($clickthrough['source'])) {
                 $download->setSource($clickthrough['source'][0]);
                 $download->setSourceId($clickthrough['source'][1]);
             }
             if (!empty($clickthrough['email'])) {
                 $emailRepo = $this->em->getRepository('MauticEmailBundle:Email');
                 if ($emailEntity = $emailRepo->getEntity($clickthrough['email'])) {
                     $download->setEmail($emailEntity);
                 }
             }
         }
         if (empty($leadClickthrough)) {
             list($lead, $trackingId, $trackingNewlyGenerated) = $this->leadModel->getCurrentLead(true);
         }
         $download->setLead($lead);
     } else {
         $trackingId = '';
         if (isset($systemEntry['lead'])) {
             $lead = $systemEntry['lead'];
             if (!$lead instanceof Lead) {
                 $leadId = is_array($lead) ? $lead['id'] : $lead;
                 $lead = $this->em->getReference('MauticLeadBundle:Lead', $leadId);
             }
             $download->setLead($lead);
         }
         if (!empty($systemEntry['source'])) {
             $download->setSource($systemEntry['source'][0]);
             $download->setSourceId($systemEntry['source'][1]);
         }
         if (isset($systemEntry['email'])) {
             $email = $systemEntry['email'];
             if (!$email instanceof Email) {
                 $emailId = is_array($email) ? $email['id'] : $email;
                 $email = $this->em->getReference('MauticEmailBundle:Email', $emailId);
             }
             $download->setEmail($email);
         }
         if (isset($systemEntry['tracking_id'])) {
             $trackingId = $systemEntry['tracking_id'];
             $trackingNewlyGenerated = false;
         } elseif ($this->security->isAnonymous() && !defined('IN_MAUTIC_CONSOLE')) {
             // If the session is anonymous and not triggered via CLI, assume the lead did something to trigger the
             // system forced download such as an email
             list($trackingId, $trackingNewlyGenerated) = $this->leadModel->getTrackingCookie();
         }
     }
     $isUnique = true;
     if (!empty($trackingNewlyGenerated)) {
         // Cookie was just generated so this is definitely a unique download
         $isUnique = $trackingNewlyGenerated;
     } elseif (!empty($trackingId)) {
         // Determine if this is a unique download
         $isUnique = $this->getDownloadRepository()->isUniqueDownload($asset->getId(), $trackingId);
     }
     $download->setTrackingId($trackingId);
     if (!empty($asset) && empty($systemEntry)) {
         $download->setAsset($asset);
         $this->getRepository()->upDownloadCount($asset->getId(), 1, $isUnique);
     }
     //check for existing IP
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     $download->setCode($code);
     $download->setIpAddress($ipAddress);
     if ($request !== null) {
         $download->setReferer($request->server->get('HTTP_REFERER'));
     }
     // Dispatch event
     if ($this->dispatcher->hasListeners(AssetEvents::ASSET_ON_LOAD)) {
         $event = new AssetLoadEvent($download, $isUnique);
         $this->dispatcher->dispatch(AssetEvents::ASSET_ON_LOAD, $event);
     }
     // Wrap in a try/catch to prevent deadlock errors on busy servers
     try {
         $this->em->persist($download);
         $this->em->flush($download);
     } catch (\Exception $e) {
         if (MAUTIC_ENV === 'dev') {
             throw $e;
         } else {
             error_log($e);
         }
     }
     $this->em->detach($download);
 }