Ejemplo n.º 1
0
 /**
  * @param CampaignExecutionEvent $event
  */
 public function onCampaignTriggerActionChangeStage(CampaignExecutionEvent $event)
 {
     $stageChange = false;
     $lead = $event->getLead();
     $leadStage = null;
     if ($lead instanceof Lead) {
         $leadStage = $lead->getStage();
     }
     $stageId = (int) $event->getConfig()['stage'];
     $stageToChangeTo = $this->stageModel->getEntity($stageId);
     if ($stageToChangeTo != null && $stageToChangeTo->isPublished()) {
         if ($leadStage && $leadStage->getWeight() <= $stageToChangeTo->getWeight()) {
             $stageChange = true;
         } elseif (!$leadStage) {
             $stageChange = true;
         }
     }
     if ($stageChange) {
         $parsed = explode('.', $stageToChangeTo->getName());
         $lead->stageChangeLogEntry($parsed[0], $stageToChangeTo->getId() . ": " . $stageToChangeTo->getName(), $event->getName());
         $lead->setStage($stageToChangeTo);
         $this->leadModel->saveEntity($lead);
     }
     return $event->setResult($stageChange);
 }
Ejemplo n.º 2
0
 /**
  * @param CampaignExecutionEvent $event
  */
 public function onCampaignTriggerActionUpdateLead(CampaignExecutionEvent $event)
 {
     if (!$event->checkContext('lead.updatelead')) {
         return;
     }
     $lead = $event->getLead();
     $this->leadModel->setFieldValues($lead, $event->getConfig(), false);
     $this->leadModel->saveEntity($lead);
     return $event->setResult(true);
 }
Ejemplo n.º 3
0
 /**
  * Triggers a specific stage change (this function is not being used any more but leaving it in case we do want to move stages through different actions)
  *
  * @param $type
  * @param mixed $eventDetails passthrough from function triggering action to the callback function
  * @param mixed $typeId Something unique to the triggering event to prevent  unnecessary duplicate calls
  * @param Lead  $lead
  *
  * @return void
  */
 public function triggerAction($type, $eventDetails = null, $typeId = null, Lead $lead = null)
 {
     //only trigger actions for anonymous users
     if (!$this->security->isAnonymous()) {
         return;
     }
     if ($typeId !== null && MAUTIC_ENV === 'prod') {
         $triggeredEvents = $this->session->get('mautic.triggered.stage.actions', array());
         if (in_array($typeId, $triggeredEvents)) {
             return;
         }
         $triggeredEvents[] = $typeId;
         $this->session->set('mautic.triggered.stage.actions', $triggeredEvents);
     }
     //find all the actions for published stages
     /** @var \Mautic\StageBundle\Entity\StageRepository $repo */
     $repo = $this->getRepository();
     $availableStages = $repo->getPublishedByType($type);
     if (null === $lead) {
         $lead = $this->leadModel->getCurrentLead();
         if (null === $lead || !$lead->getId()) {
             return;
         }
     }
     //get available actions
     $availableActions = $this->getStageActions();
     //get a list of actions that has already been performed on this lead
     $completedActions = $repo->getCompletedLeadActions($type, $lead->getId());
     $persist = array();
     foreach ($availableStages as $action) {
         //if it's already been done, then skip it
         if (isset($completedActions[$action->getId()])) {
             continue;
         }
         //make sure the action still exists
         if (!isset($availableActions['actions'][$action->getName()])) {
             continue;
         }
         $parsed = explode('.', $action->getName());
         $lead->stageChangeLogEntry($parsed[0], $action->getId() . ": " . $action->getName(), 'Moved by an action');
         $lead->setStage($action);
         $log = new LeadStageLog();
         $log->setStage($action);
         $log->setLead($lead);
         $log->setDateFired(new \DateTime());
         $persist[] = $log;
     }
     if (!empty($persist)) {
         $this->leadModel->saveEntity($lead);
         $this->getRepository()->saveEntities($persist);
         // Detach logs to reserve memory
         $this->em->clear('Mautic\\StageBundle\\Entity\\LeadStageLog');
     }
 }
Ejemplo n.º 4
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.º 5
0
 /**
  * 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;
 }
Ejemplo n.º 6
0
 /**
  * Triggers a specific point change
  *
  * @param $type
  * @param mixed $eventDetails passthrough from function triggering action to the callback function
  * @param mixed $typeId Something unique to the triggering event to prevent  unnecessary duplicate calls
  * @param Lead  $lead
  *25
  * @return void
  */
 public function triggerAction($type, $eventDetails = null, $typeId = null, Lead $lead = null)
 {
     //only trigger actions for anonymous users
     if (!$this->security->isAnonymous()) {
         return;
     }
     if ($typeId !== null && MAUTIC_ENV === 'prod') {
         //let's prevent some unnecessary DB calls
         $triggeredEvents = $this->session->get('mautic.triggered.point.actions', array());
         if (in_array($typeId, $triggeredEvents)) {
             return;
         }
         $triggeredEvents[] = $typeId;
         $this->session->set('mautic.triggered.point.actions', $triggeredEvents);
     }
     //find all the actions for published points
     /** @var \Mautic\PointBundle\Entity\PointRepository $repo */
     $repo = $this->getRepository();
     $availablePoints = $repo->getPublishedByType($type);
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     if (null === $lead) {
         $lead = $this->leadModel->getCurrentLead();
         if (null === $lead || !$lead->getId()) {
             return;
         }
     }
     //get available actions
     $availableActions = $this->getPointActions();
     //get a list of actions that has already been performed on this lead
     $completedActions = $repo->getCompletedLeadActions($type, $lead->getId());
     $persist = array();
     foreach ($availablePoints as $action) {
         //if it's already been done, then skip it
         if (isset($completedActions[$action->getId()])) {
             continue;
         }
         //make sure the action still exists
         if (!isset($availableActions['actions'][$action->getType()])) {
             continue;
         }
         $settings = $availableActions['actions'][$action->getType()];
         $args = array('action' => array('id' => $action->getId(), 'type' => $action->getType(), 'name' => $action->getName(), 'properties' => $action->getProperties(), 'points' => $action->getDelta()), 'lead' => $lead, 'factory' => $this->factory, 'eventDetails' => $eventDetails);
         $callback = isset($settings['callback']) ? $settings['callback'] : array('\\Mautic\\PointBundle\\Helper\\EventHelper', 'engagePointAction');
         if (is_callable($callback)) {
             if (is_array($callback)) {
                 $reflection = new \ReflectionMethod($callback[0], $callback[1]);
             } elseif (strpos($callback, '::') !== false) {
                 $parts = explode('::', $callback);
                 $reflection = new \ReflectionMethod($parts[0], $parts[1]);
             } else {
                 $reflection = new \ReflectionMethod(null, $callback);
             }
             $pass = array();
             foreach ($reflection->getParameters() as $param) {
                 if (isset($args[$param->getName()])) {
                     $pass[] = $args[$param->getName()];
                 } else {
                     $pass[] = null;
                 }
             }
             $pointsChange = $reflection->invokeArgs($this, $pass);
             if ($pointsChange) {
                 $delta = $action->getDelta();
                 $lead->adjustPoints($delta);
                 $parsed = explode('.', $action->getType());
                 $lead->addPointsChangeLogEntry($parsed[0], $action->getId() . ": " . $action->getName(), $parsed[1], $delta, $ipAddress);
                 $event = new PointActionEvent($action, $lead);
                 $this->dispatcher->dispatch(PointEvents::POINT_ON_ACTION, $event);
                 $log = new LeadPointLog();
                 $log->setIpAddress($ipAddress);
                 $log->setPoint($action);
                 $log->setLead($lead);
                 $log->setDateFired(new \DateTime());
                 $persist[] = $log;
             }
         }
     }
     if (!empty($persist)) {
         $this->leadModel->saveEntity($lead);
         $this->getRepository()->saveEntities($persist);
         // Detach logs to reserve memory
         $this->em->clear('Mautic\\PointBundle\\Entity\\LeadPointLog');
     }
 }
Ejemplo n.º 7
0
 /**
  * Triggers an event.
  *
  * @param      $type
  * @param null $eventDetails
  * @param null $channel
  * @param null $channelId
  *
  * @return array|bool
  */
 public function triggerEvent($type, $eventDetails = null, $channel = null, $channelId = null)
 {
     static $leadCampaigns = [], $eventList = [], $availableEventSettings = [], $leadsEvents = [], $examinedEvents = [];
     $this->logger->debug('CAMPAIGN: Campaign triggered for event type ' . $type . '(' . $channel . ' / ' . $channelId . ')');
     // Skip the anonymous check to force actions to fire for subsequent triggers
     $systemTriggered = defined('MAUTIC_CAMPAIGN_SYSTEM_TRIGGERED');
     if (!$systemTriggered) {
         defined('MAUTIC_CAMPAIGN_NOT_SYSTEM_TRIGGERED') or define('MAUTIC_CAMPAIGN_NOT_SYSTEM_TRIGGERED', 1);
     }
     //only trigger events for anonymous users (to prevent populating full of user/company data)
     if (!$systemTriggered && !$this->security->isAnonymous()) {
         $this->logger->debug('CAMPAIGN: contact not anonymous; abort');
         return false;
     }
     //get the current lead
     $lead = $this->leadModel->getCurrentLead();
     $leadId = $lead->getId();
     $this->logger->debug('CAMPAIGN: Current Lead ID# ' . $leadId);
     //get the lead's campaigns so we have when the lead was added
     if (empty($leadCampaigns[$leadId])) {
         $leadCampaigns[$leadId] = $this->campaignModel->getLeadCampaigns($lead, true);
     }
     if (empty($leadCampaigns[$leadId])) {
         $this->logger->debug('CAMPAIGN: no campaigns found so abort');
         return false;
     }
     //get the list of events that match the triggering event and is in the campaigns this lead belongs to
     /** @var \Mautic\CampaignBundle\Entity\EventRepository $eventRepo */
     $eventRepo = $this->getRepository();
     if (empty($eventList[$leadId][$type])) {
         $eventList[$leadId][$type] = $eventRepo->getPublishedByType($type, $leadCampaigns[$leadId], $lead->getId());
     }
     $events = $eventList[$leadId][$type];
     //get event settings from the bundles
     if (empty($availableEventSettings)) {
         $availableEventSettings = $this->campaignModel->getEvents();
     }
     //make sure there are events before continuing
     if (!count($availableEventSettings) || empty($events)) {
         $this->logger->debug('CAMPAIGN: no events found so abort');
         return false;
     }
     //get campaign list
     $campaigns = $this->campaignModel->getEntities(['force' => ['filter' => [['column' => 'c.id', 'expr' => 'in', 'value' => array_keys($events)]]], 'ignore_paginator' => true]);
     //get a list of events that has already been executed for this lead
     if (empty($leadsEvents[$leadId])) {
         $leadsEvents[$leadId] = $eventRepo->getLeadTriggeredEvents($leadId);
     }
     if (!isset($examinedEvents[$leadId])) {
         $examinedEvents[$leadId] = [];
     }
     $this->triggeredResponses = [];
     foreach ($events as $campaignId => $campaignEvents) {
         if (empty($campaigns[$campaignId])) {
             $this->logger->debug('CAMPAIGN: Campaign entity for ID# ' . $campaignId . ' not found');
             continue;
         }
         foreach ($campaignEvents as $k => $event) {
             //has this event already been examined via a parent's children?
             //all events of this triggering type has to be queried since this particular event could be anywhere in the dripflow
             if (in_array($event['id'], $examinedEvents[$leadId])) {
                 $this->logger->debug('CAMPAIGN: ' . ucfirst($event['eventType']) . ' ID# ' . $event['id'] . ' already processed this round');
                 continue;
             }
             $examinedEvents[$leadId][] = $event['id'];
             //check to see if this has been fired sequentially
             if (!empty($event['parent'])) {
                 if (!isset($leadsEvents[$leadId][$event['parent']['id']])) {
                     //this event has a parent that has not been triggered for this lead so break out
                     $this->logger->debug('CAMPAIGN: parent (ID# ' . $event['parent']['id'] . ') for ID# ' . $event['id'] . ' has not been triggered yet or was triggered with this batch');
                     continue;
                 }
                 $parentLog = $leadsEvents[$leadId][$event['parent']['id']]['log'][0];
                 if ($parentLog['isScheduled']) {
                     //this event has a parent that is scheduled and thus not triggered
                     $this->logger->debug('CAMPAIGN: parent (ID# ' . $event['parent']['id'] . ') for ID# ' . $event['id'] . ' has not been triggered yet because it\'s scheduled');
                     continue;
                 } else {
                     $parentTriggeredDate = $parentLog['dateTriggered'];
                 }
             } else {
                 $parentTriggeredDate = new \DateTime();
             }
             if (isset($availableEventSettings[$event['eventType']][$type])) {
                 $decisionEventSettings = $availableEventSettings[$event['eventType']][$type];
             } else {
                 // Not found maybe it's no longer available?
                 $this->logger->debug('CAMPAIGN: ' . $type . ' does not exist. (#' . $event['id'] . ')');
                 continue;
             }
             //check the callback function for the event to make sure it even applies based on its settings
             if (!($response = $this->invokeEventCallback($event, $decisionEventSettings, $lead, $eventDetails, $systemTriggered))) {
                 $this->logger->debug('CAMPAIGN: ' . ucfirst($event['eventType']) . ' ID# ' . $event['id'] . ' callback check failed with a response of ' . var_export($response, true));
                 continue;
             }
             if (!empty($event['children'])) {
                 $this->logger->debug('CAMPAIGN: ' . ucfirst($event['eventType']) . ' ID# ' . $event['id'] . ' has children');
                 $childrenTriggered = false;
                 foreach ($event['children'] as $child) {
                     if (isset($leadsEvents[$leadId][$child['id']])) {
                         //this child event has already been fired for this lead so move on to the next event
                         $this->logger->debug('CAMPAIGN: ' . ucfirst($child['eventType']) . ' ID# ' . $child['id'] . ' already triggered');
                         continue;
                     } elseif ($child['eventType'] == 'decision') {
                         //hit a triggering type event so move on
                         $this->logger->debug('CAMPAIGN: ID# ' . $child['id'] . ' is a decision');
                         continue;
                     } elseif ($child['decisionPath'] == 'no') {
                         // non-action paths should not be processed by this because the contact already took action in order to get here
                         $childrenTriggered = true;
                     } else {
                         $this->logger->debug('CAMPAIGN: ' . ucfirst($child['eventType']) . ' ID# ' . $child['id'] . ' is being processed');
                     }
                     //store in case a child was pulled with events
                     $examinedEvents[$leadId][] = $child['id'];
                     if ($this->executeEvent($child, $campaigns[$campaignId], $lead, $availableEventSettings, false, $parentTriggeredDate)) {
                         $childrenTriggered = true;
                     }
                 }
                 if ($childrenTriggered) {
                     $this->logger->debug('CAMPAIGN: Decision ID# ' . $event['id'] . ' successfully executed and logged.');
                     //a child of this event was triggered or scheduled so make not of the triggering event in the log
                     $log = $this->getLogEntity($event['id'], $campaigns[$campaignId], $lead, null, $systemTriggered);
                     $log->setChannel($channel)->setChannelId($channelId);
                     $this->getRepository()->saveEntity($log);
                 } else {
                     $this->logger->debug('CAMPAIGN: Decision not logged');
                 }
             } else {
                 $this->logger->debug('CAMPAIGN: No children for this event.');
             }
         }
     }
     if ($lead->getChanges()) {
         $this->leadModel->saveEntity($lead, false);
     }
     if ($this->dispatcher->hasListeners(CampaignEvents::ON_EVENT_DECISION_TRIGGER)) {
         $this->dispatcher->dispatch(CampaignEvents::ON_EVENT_DECISION_TRIGGER, new CampaignDecisionEvent($lead, $type, $eventDetails, $events, $availableEventSettings));
     }
     $actionResponses = $this->triggeredResponses;
     $this->triggeredResponses = false;
     return $actionResponses;
 }