/** * @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); }
/** * @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); }
/** * 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'); } }
/** * 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; }
/** * 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; }
/** * 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'); } }
/** * 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; }