コード例 #1
0
 /**
  * @param MauticEvents\CommandListEvent $event
  */
 public function onBuildCommandList(MauticEvents\CommandListEvent $event)
 {
     $security = $this->security;
     if ($security->isGranted('campaign:campaigns:view')) {
         $event->addCommands('mautic.campaign.campaigns', $this->campaignModel->getCommandList());
     }
 }
コード例 #2
0
ファイル: LeadSubscriber.php プロジェクト: Yame-/mautic
 /**
  * Compile events for the lead timeline
  *
  * @param LeadTimelineEvent $event
  */
 public function onTimelineGenerate(LeadTimelineEvent $event)
 {
     // Set available event types
     $eventTypeKey = 'campaign.event';
     $eventTypeName = $this->translator->trans('mautic.campaign.triggered');
     $event->addEventType($eventTypeKey, $eventTypeName);
     // Decide if those events are filtered
     if (!$event->isApplicable($eventTypeKey)) {
         return;
     }
     $lead = $event->getLead();
     /** @var \Mautic\CampaignBundle\Entity\LeadEventLogRepository $logRepository */
     $logRepository = $this->em->getRepository('MauticCampaignBundle:LeadEventLog');
     $logs = $logRepository->getLeadLogs($lead->getId(), $event->getQueryOptions());
     $eventSettings = $this->campaignModel->getEvents();
     // Add total number to counter
     $event->addToCounter($eventTypeKey, $logs);
     if (!$event->isEngagementCount()) {
         foreach ($logs['results'] as $log) {
             // Hide this from the time line all together
             if (!empty($log['metadata']['failed'])) {
                 $event->subtractFromCounter($eventTypeKey);
                 continue;
             }
             $template = !empty($eventSettings['action'][$log['type']]['timelineTemplate']) ? $eventSettings['action'][$log['type']]['timelineTemplate'] : 'MauticCampaignBundle:SubscribedEvents\\Timeline:index.html.php';
             $event->addEvent(['event' => $eventTypeKey, 'eventLabel' => ['label' => $log['event_name'] . ' / ' . $log['campaign_name'], 'href' => $this->router->generate('mautic_campaign_action', ['objectAction' => 'view', 'objectId' => $log['campaign_id']])], 'eventType' => $eventTypeName, 'timestamp' => $log['dateTriggered'], 'extra' => ['log' => $log], 'contentTemplate' => $template, 'icon' => 'fa-clock-o']);
         }
     }
 }
コード例 #3
0
 /**
  * Set a widget detail when needed.
  *
  * @param WidgetDetailEvent $event
  */
 public function onWidgetDetailGenerate(WidgetDetailEvent $event)
 {
     $this->checkPermissions($event);
     $canViewOthers = $event->hasPermission('campaign:campaigns:viewother');
     if ($event->getType() == 'events.in.time') {
         $widget = $event->getWidget();
         $params = $widget->getParams();
         if (!$event->isCached()) {
             $event->setTemplateData(['chartType' => 'line', 'chartHeight' => $widget->getHeight() - 80, 'chartData' => $this->campaignEventModel->getEventLineChartData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $canViewOthers)]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:chart.html.php');
         $event->stopPropagation();
     }
     if ($event->getType() == 'leads.added.in.time') {
         $widget = $event->getWidget();
         $params = $widget->getParams();
         if (!$event->isCached()) {
             $event->setTemplateData(['chartType' => 'line', 'chartHeight' => $widget->getHeight() - 80, 'chartData' => $this->campaignModel->getLeadsAddedLineChartData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $canViewOthers)]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:chart.html.php');
         $event->stopPropagation();
     }
 }
コード例 #4
0
 /**
  * @param ReportBuilderEvent $event
  * @param array              $columns
  */
 private function injectAttributionReportData(ReportBuilderEvent $event, array $columns, $type)
 {
     $attributionColumns = ['log.campaign_id' => ['label' => 'mautic.lead.report.attribution.campaign_id', 'type' => 'int', 'link' => 'mautic_campaign_action'], 'log.date_triggered' => ['label' => 'mautic.lead.report.attribution.action_date', 'type' => 'datetime'], 'c.name' => ['alias' => 'campaign_name', 'label' => 'mautic.lead.report.attribution.campaign_name', 'type' => 'string'], 'l.stage_id' => ['label' => 'mautic.lead.report.attribution.stage_id', 'type' => 'int', 'link' => 'mautic_stage_action'], 's.name' => ['alias' => 'stage_name', 'label' => 'mautic.lead.report.attribution.stage_name', 'type' => 'string'], 'channel' => ['alias' => 'channel', 'formula' => 'SUBSTRING_INDEX(e.type, \'.\', 1)', 'label' => 'mautic.lead.report.attribution.channel', 'type' => 'string'], 'channel_action' => ['alias' => 'channel_action', 'formula' => 'SUBSTRING_INDEX(e.type, \'.\', -1)', 'label' => 'mautic.lead.report.attribution.channel_action', 'type' => 'string'], 'e.name' => ['alias' => 'action_name', 'label' => 'mautic.lead.report.attribution.action_name', 'type' => 'string']];
     $filters = $columns = array_merge($columns, $event->getCategoryColumns('cat.'), $attributionColumns);
     // Setup available channels
     $availableChannels = $this->campaignModel->getEvents();
     $channels = [];
     $channelActions = [];
     foreach ($availableChannels['decision'] as $channel => $decision) {
         $parts = explode('.', $channel);
         $channelName = $parts[0];
         $channels[$channelName] = $this->translator->hasId('mautic.channel.' . $channelName) ? $this->translator->trans('mautic.channel.' . $channelName) : ucfirst($channelName);
         unset($parts[0]);
         $actionValue = implode('.', $parts);
         if ($this->translator->hasId('mautic.channel.action.' . $channel)) {
             $actionName = $this->translator->trans('mautic.channel.action.' . $channel);
         } elseif ($this->translator->hasId('mautic.campaign.' . $channel)) {
             $actionName = $this->translator->trans('mautic.campaign.' . $channel);
         } else {
             $actionName = $channelName . ': ' . $actionValue;
         }
         $channelActions[$actionValue] = $actionName;
     }
     $filters['channel'] = ['label' => 'mautic.lead.report.attribution.channel', 'type' => 'select', 'list' => $channels];
     $filters['channel_action'] = ['label' => 'mautic.lead.report.attribution.channel_action', 'type' => 'select', 'list' => $channelActions];
     $this->channelActions = $channelActions;
     $this->channels = $channels;
     unset($channelActions, $channels);
     // Setup available channels
     $campaigns = $this->campaignModel->getRepository()->getSimpleList();
     $filters['log.campaign_id'] = ['label' => 'mautic.lead.report.attribution.filter.campaign', 'type' => 'select', 'list' => $campaigns];
     unset($campaigns);
     // Setup stages list
     $userStages = $this->stageModel->getUserStages();
     $stages = [];
     foreach ($userStages as $stage) {
         $stages[$stage['id']] = $stage['name'];
     }
     $filters['l.stage_id'] = ['label' => 'mautic.lead.report.attribution.filter.stage', 'type' => 'select', 'list' => $stages];
     unset($stages);
     $context = "contact.attribution.{$type}";
     $event->addGraph($context, 'pie', 'mautic.lead.graph.pie.attribution_stages')->addGraph($context, 'pie', 'mautic.lead.graph.pie.attribution_campaigns')->addGraph($context, 'pie', 'mautic.lead.graph.pie.attribution_actions')->addGraph($context, 'pie', 'mautic.lead.graph.pie.attribution_channels');
     $data = ['display_name' => 'mautic.lead.report.attribution.' . $type, 'columns' => $columns, 'filters' => $filters];
     $event->addTable($context, $data, 'contacts');
 }
コード例 #5
0
ファイル: SubmissionModel.php プロジェクト: dongilbert/mautic
 /**
  * @param      $post
  * @param      $server
  * @param Form $form
  *
  * @return bool|array
  */
 public function saveSubmission($post, $server, Form $form, Request $request = null, $returnEvent = false)
 {
     $leadFields = $this->leadFieldModel->getFieldListWithProperties(false);
     //everything matches up so let's save the results
     $submission = new Submission();
     $submission->setDateSubmitted(new \DateTime());
     $submission->setForm($form);
     //set the landing page the form was submitted from if applicable
     if (!empty($post['mauticpage'])) {
         $page = $this->pageModel->getEntity((int) $post['mauticpage']);
         if ($page != null) {
             $submission->setPage($page);
         }
     }
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     $submission->setIpAddress($ipAddress);
     if (!empty($post['return'])) {
         $referer = $post['return'];
     } elseif (!empty($server['HTTP_REFERER'])) {
         $referer = $server['HTTP_REFERER'];
     } else {
         $referer = '';
     }
     //clean the referer by removing mauticError and mauticMessage
     $referer = InputHelper::url($referer, null, null, ['mauticError', 'mauticMessage']);
     $submission->setReferer($referer);
     // Create an event to be dispatched through the processes
     $submissionEvent = new SubmissionEvent($submission, $post, $server, $request);
     // Get a list of components to build custom fields from
     $components = $this->formModel->getCustomComponents();
     $fields = $form->getFields();
     $fieldArray = [];
     $results = [];
     $tokens = [];
     $leadFieldMatches = [];
     $validationErrors = [];
     /** @var Field $f */
     foreach ($fields as $f) {
         $id = $f->getId();
         $type = $f->getType();
         $alias = $f->getAlias();
         $value = isset($post[$alias]) ? $post[$alias] : '';
         $fieldArray[$id] = ['id' => $id, 'type' => $type, 'alias' => $alias];
         if ($type == 'captcha') {
             $captcha = $this->fieldHelper->validateFieldValue($type, $value, $f);
             if (!empty($captcha)) {
                 $props = $f->getProperties();
                 //check for a custom message
                 $validationErrors[$alias] = !empty($props['errorMessage']) ? $props['errorMessage'] : implode('<br />', $captcha);
             }
             continue;
         }
         if ($f->isRequired() && empty($value)) {
             //field is required, but hidden from form because of 'ShowWhenValueExists'
             if ($f->getShowWhenValueExists() === false && !isset($post[$alias])) {
                 continue;
             }
             //somehow the user got passed the JS validation
             $msg = $f->getValidationMessage();
             if (empty($msg)) {
                 $msg = $this->translator->trans('mautic.form.field.generic.validationfailed', ['%label%' => $f->getLabel()], 'validators');
             }
             $validationErrors[$alias] = $msg;
             continue;
         }
         if (in_array($type, $components['viewOnlyFields'])) {
             //don't save items that don't have a value associated with it
             continue;
         }
         //clean and validate the input
         if ($f->isCustom()) {
             if (!isset($components['fields'][$f->getType()])) {
                 continue;
             }
             $params = $components['fields'][$f->getType()];
             if (!empty($value)) {
                 if (isset($params['valueFilter'])) {
                     if (is_string($params['valueFilter']) && is_callable(['\\Mautic\\CoreBundle\\Helper\\InputHelper', $params['valueFilter']])) {
                         $value = InputHelper::_($value, $params['valueFilter']);
                     } elseif (is_callable($params['valueFilter'])) {
                         $value = call_user_func_array($params['valueFilter'], [$f, $value]);
                     } else {
                         $value = InputHelper::_($value, 'clean');
                     }
                 } else {
                     $value = InputHelper::_($value, 'clean');
                 }
             }
             // @deprecated - BC support; to be removed in 3.0 - be sure to remove support in FormBuilderEvent as well
             if (isset($params['valueConstraints']) && is_callable($params['valueConstraints'])) {
                 $customErrors = call_user_func_array($params['valueConstraints'], [$f, $value]);
                 if (!empty($customErrors)) {
                     $validationErrors[$alias] = is_array($customErrors) ? implode('<br />', $customErrors) : $customErrors;
                 }
             }
         } elseif (!empty($value)) {
             $filter = $this->fieldHelper->getFieldFilter($type);
             $value = InputHelper::_($value, $filter);
             $isValid = $this->validateFieldValue($f, $value);
             if (true !== $isValid) {
                 $validationErrors[$alias] = is_array($isValid) ? implode('<br />', $isValid) : $isValid;
             }
         }
         // Check for custom validators
         $isValid = $this->validateFieldValue($f, $value);
         if (true !== $isValid) {
             $validationErrors[$alias] = $isValid;
         }
         $leadField = $f->getLeadField();
         if (!empty($leadField)) {
             $leadValue = $value;
             if (is_array($leadValue)) {
                 // Multiselect lead fields store the values with bars
                 $delimeter = 'multiselect' === $leadFields[$leadField]['type'] ? '|' : ', ';
                 $leadValue = implode($delimeter, $leadValue);
             }
             $leadFieldMatches[$leadField] = $leadValue;
         }
         //convert array from checkbox groups and multiple selects
         if (is_array($value)) {
             $value = implode(', ', $value);
         }
         $tokens["{formfield={$alias}}"] = $value;
         //save the result
         if ($f->getSaveResult() !== false) {
             $results[$alias] = $value;
         }
     }
     // Set the results
     $submission->setResults($results);
     // Update the event
     $submissionEvent->setFields($fieldArray)->setTokens($tokens)->setResults($results)->setContactFieldMatches($leadFieldMatches);
     // @deprecated - BC support; to be removed in 3.0 - be sure to remove the validator option from addSubmitAction as well
     $this->validateActionCallbacks($submissionEvent, $validationErrors, $alias);
     //return errors if there any - this should be moved to right after foreach($fields) once validateActionCallbacks support is dropped
     if (!empty($validationErrors)) {
         return ['errors' => $validationErrors];
     }
     // Create/update lead
     if (!empty($leadFieldMatches)) {
         $lead = $this->createLeadFromSubmit($form, $leadFieldMatches, $leadFields);
         $submission->setLead($lead);
     }
     // Get updated lead if applicable with tracking ID
     if ($form->isInKioskMode()) {
         $lead = $this->leadModel->getCurrentLead();
     } else {
         list($lead, $trackingId, $generated) = $this->leadModel->getCurrentLead(true);
         //set tracking ID for stats purposes to determine unique hits
         $submission->setTrackingId($trackingId);
     }
     $submission->setLead($lead);
     // Save the submission
     $this->saveEntity($submission);
     // Now handle post submission actions
     try {
         $this->executeFormActions($submissionEvent);
     } catch (ValidationException $exception) {
         // The action invalidated the form for whatever reason
         $this->deleteEntity($submission);
         if ($validationErrors = $exception->getViolations()) {
             return ['errors' => $validationErrors];
         }
         return ['errors' => [$exception->getMessage()]];
     }
     if (!$form->isStandalone()) {
         // Find and add the lead to the associated campaigns
         $campaigns = $this->campaignModel->getCampaignsByForm($form);
         if (!empty($campaigns)) {
             foreach ($campaigns as $campaign) {
                 $this->campaignModel->addLead($campaign, $lead);
             }
         }
     }
     if ($this->dispatcher->hasListeners(FormEvents::FORM_ON_SUBMIT)) {
         // Reset action config from executeFormActions()
         $submissionEvent->setActionConfig(null, []);
         // Dispatch to on submit listeners
         $this->dispatcher->dispatch(FormEvents::FORM_ON_SUBMIT, $submissionEvent);
     }
     //get callback commands from the submit action
     if ($submissionEvent->hasPostSubmitCallbacks()) {
         return ['callback' => $submissionEvent];
     }
     // made it to the end so return the submission event to give the calling method access to tokens, results, etc
     // otherwise return false that no errors were encountered (to keep BC really)
     return $returnEvent ? ['submission' => $submissionEvent] : false;
 }
コード例 #6
0
ファイル: EventModel.php プロジェクト: dongilbert/mautic
 /**
  * Find and trigger the negative events, i.e. the events with a no decision path.
  *
  * @param Campaign        $campaign
  * @param int             $totalEventCount
  * @param int             $limit
  * @param bool            $max
  * @param OutputInterface $output
  * @param bool|false      $returnCounts    If true, returns array of counters
  *
  * @return int
  */
 public function triggerNegativeEvents($campaign, &$totalEventCount = 0, $limit = 100, $max = false, OutputInterface $output = null, $returnCounts = false)
 {
     defined('MAUTIC_CAMPAIGN_SYSTEM_TRIGGERED') or define('MAUTIC_CAMPAIGN_SYSTEM_TRIGGERED', 1);
     $this->logger->debug('CAMPAIGN: Triggering negative events');
     $campaignId = $campaign->getId();
     $campaignName = $campaign->getName();
     $repo = $this->getRepository();
     $campaignRepo = $this->getCampaignRepository();
     // Get events to avoid large number of joins
     $campaignEvents = $repo->getCampaignEvents($campaignId);
     // Get an array of events that are non-action based
     $nonActionEvents = [];
     $actionEvents = [];
     foreach ($campaignEvents as $id => $e) {
         if (!empty($e['decisionPath']) && !empty($e['parent_id']) && $campaignEvents[$e['parent_id']]['eventType'] != 'condition') {
             if ($e['decisionPath'] == 'no') {
                 $nonActionEvents[$e['parent_id']][$id] = $e;
             } elseif ($e['decisionPath'] == 'yes') {
                 $actionEvents[$e['parent_id']][] = $id;
             }
         }
     }
     $this->logger->debug('CAMPAIGN: Processing the children of the following events: ' . implode(', ', array_keys($nonActionEvents)));
     if (empty($nonActionEvents)) {
         // No non-action events associated with this campaign
         unset($campaignEvents);
         return 0;
     }
     // Get a count
     $leadCount = $campaignRepo->getCampaignLeadCount($campaignId);
     if ($output) {
         $output->writeln($this->translator->trans('mautic.campaign.trigger.lead_count_analyzed', ['%leads%' => $leadCount, '%batch%' => $limit]));
     }
     $start = $leadProcessedCount = $lastRoundPercentage = $executedEventCount = $evaluatedEventCount = $negativeExecutedCount = $negativeEvaluatedCount = 0;
     $nonActionEventCount = $leadCount * count($nonActionEvents);
     $eventSettings = $this->campaignModel->getEvents();
     $maxCount = $max ? $max : $nonActionEventCount;
     // Try to save some memory
     gc_enable();
     if ($leadCount) {
         if ($output) {
             $progress = ProgressBarHelper::init($output, $maxCount);
             $progress->start();
             if ($max) {
                 $progress->advance($totalEventCount);
             }
         }
         $sleepBatchCount = 0;
         $batchDebugCounter = 1;
         while ($start <= $leadCount) {
             $this->logger->debug('CAMPAIGN: Batch #' . $batchDebugCounter);
             // Get batched campaign ids
             $campaignLeads = $campaignRepo->getCampaignLeads($campaignId, $start, $limit, ['cl.lead_id, cl.date_added']);
             $campaignLeadIds = [];
             $campaignLeadDates = [];
             foreach ($campaignLeads as $r) {
                 $campaignLeadIds[] = $r['lead_id'];
                 $campaignLeadDates[$r['lead_id']] = $r['date_added'];
             }
             unset($campaignLeads);
             $this->logger->debug('CAMPAIGN: Processing the following contacts: ' . implode(', ', $campaignLeadIds));
             foreach ($nonActionEvents as $parentId => $events) {
                 // Just a check to ensure this is an appropriate action
                 if ($campaignEvents[$parentId]['eventType'] == 'action') {
                     $this->logger->debug('CAMPAIGN: Parent event ID #' . $parentId . ' is an action.');
                     continue;
                 }
                 // Get only leads who have had the action prior to the decision executed
                 $grandParentId = $campaignEvents[$parentId]['parent_id'];
                 // Get the lead log for this batch of leads limiting to those that have already triggered
                 // the decision's parent and haven't executed this level in the path yet
                 if ($grandParentId) {
                     $this->logger->debug('CAMPAIGN: Checking for contacts based on grand parent execution.');
                     $leadLog = $repo->getEventLog($campaignId, $campaignLeadIds, [$grandParentId], array_keys($events), true);
                     $applicableLeads = array_keys($leadLog);
                 } else {
                     $this->logger->debug('CAMPAIGN: Checking for contacts based on exclusion due to being at root level');
                     // The event has no grandparent (likely because the decision is first in the campaign) so find leads that HAVE
                     // already executed the events in the root level and exclude them
                     $havingEvents = isset($actionEvents[$parentId]) ? array_merge($actionEvents[$parentId], array_keys($events)) : array_keys($events);
                     $leadLog = $repo->getEventLog($campaignId, $campaignLeadIds, $havingEvents);
                     $unapplicableLeads = array_keys($leadLog);
                     // Only use leads that are not applicable
                     $applicableLeads = array_diff($campaignLeadIds, $unapplicableLeads);
                     unset($unapplicableLeads);
                 }
                 if (empty($applicableLeads)) {
                     $this->logger->debug('CAMPAIGN: No events are applicable');
                     continue;
                 }
                 $this->logger->debug('CAMPAIGN: These contacts have have not gone down the positive path: ' . implode(', ', $applicableLeads));
                 // Get the leads
                 $leads = $this->leadModel->getEntities(['filter' => ['force' => [['column' => 'l.id', 'expr' => 'in', 'value' => $applicableLeads]]], 'orderBy' => 'l.id', 'orderByDir' => 'asc']);
                 if (!count($leads)) {
                     // Just a precaution in case non-existent leads are lingering in the campaign leads table
                     $this->logger->debug('CAMPAIGN: No contact entities found.');
                     continue;
                 }
                 // Loop over the non-actions and determine if it has been processed for this lead
                 $leadDebugCounter = 1;
                 /** @var \Mautic\LeadBundle\Entity\Lead $lead */
                 foreach ($leads as $lead) {
                     ++$negativeEvaluatedCount;
                     // Set lead for listeners
                     $this->leadModel->setSystemCurrentLead($lead);
                     $this->logger->debug('CAMPAIGN: contact ID #' . $lead->getId() . '; #' . $leadDebugCounter . ' in batch #' . $batchDebugCounter);
                     // Prevent path if lead has already gone down this path
                     if (!isset($leadLog[$lead->getId()]) || !array_key_exists($parentId, $leadLog[$lead->getId()])) {
                         // Get date to compare against
                         $utcDateString = $grandParentId ? $leadLog[$lead->getId()][$grandParentId]['date_triggered'] : $campaignLeadDates[$lead->getId()];
                         // Convert to local DateTime
                         $grandParentDate = (new DateTimeHelper($utcDateString))->getLocalDateTime();
                         // Non-decision has not taken place yet, so cycle over each associated action to see if timing is right
                         $eventTiming = [];
                         $executeAction = false;
                         foreach ($events as $id => $e) {
                             if ($sleepBatchCount == $limit) {
                                 // Keep CPU down
                                 $this->batchSleep();
                                 $sleepBatchCount = 0;
                             } else {
                                 ++$sleepBatchCount;
                             }
                             if (isset($leadLog[$lead->getId()]) && array_key_exists($id, $leadLog[$lead->getId()])) {
                                 $this->logger->debug('CAMPAIGN: Event (ID #' . $id . ') has already been executed');
                                 unset($e);
                                 continue;
                             }
                             if (!isset($eventSettings[$e['eventType']][$e['type']])) {
                                 $this->logger->debug('CAMPAIGN: Event (ID #' . $id . ') no longer exists');
                                 unset($e);
                                 continue;
                             }
                             // First get the timing for all the 'non-decision' actions
                             $eventTiming[$id] = $this->checkEventTiming($e, $grandParentDate, true);
                             if ($eventTiming[$id] === true) {
                                 // Includes events to be executed now then schedule the rest if applicable
                                 $executeAction = true;
                             }
                             unset($e);
                         }
                         if (!$executeAction) {
                             $negativeEvaluatedCount += count($nonActionEvents);
                             // Timing is not appropriate so move on to next lead
                             unset($eventTiming);
                             continue;
                         }
                         if ($max && $totalEventCount + count($nonActionEvents) >= $max) {
                             // Hit the max or will hit the max while mid-process for the lead
                             if ($output) {
                                 $progress->finish();
                                 $output->writeln('');
                             }
                             $counts = ['events' => $nonActionEventCount, 'evaluated' => $negativeEvaluatedCount, 'executed' => $negativeExecutedCount, 'totalEvaluated' => $evaluatedEventCount, 'totalExecuted' => $executedEventCount];
                             $this->logger->debug('CAMPAIGN: Counts - ' . var_export($counts, true));
                             return $returnCounts ? $counts : $executedEventCount;
                         }
                         $decisionLogged = false;
                         // Execute or schedule events
                         $this->logger->debug('CAMPAIGN: Processing the following events for contact ID# ' . $lead->getId() . ': ' . implode(', ', array_keys($eventTiming)));
                         foreach ($eventTiming as $id => $eventTriggerDate) {
                             // Set event
                             $event = $events[$id];
                             $event['campaign'] = ['id' => $campaignId, 'name' => $campaignName];
                             // Set lead in case this is triggered by the system
                             $this->leadModel->setSystemCurrentLead($lead);
                             if ($this->executeEvent($event, $campaign, $lead, $eventSettings, false, null, $eventTriggerDate, false, $evaluatedEventCount, $executedEventCount, $totalEventCount)) {
                                 if (!$decisionLogged) {
                                     // Log the decision
                                     $log = $this->getLogEntity($parentId, $campaign, $lead, null, true);
                                     $log->setDateTriggered(new \DateTime());
                                     $log->setNonActionPathTaken(true);
                                     $repo->saveEntity($log);
                                     $this->em->detach($log);
                                     unset($log);
                                     $decisionLogged = true;
                                 }
                                 ++$negativeExecutedCount;
                             }
                             unset($utcDateString, $grandParentDate);
                         }
                     } else {
                         $this->logger->debug('CAMPAIGN: Decision has already been executed.');
                     }
                     $currentCount = $max ? $totalEventCount : $negativeEvaluatedCount;
                     if ($output && $currentCount < $maxCount) {
                         $progress->setProgress($currentCount);
                     }
                     ++$leadDebugCounter;
                     // Save RAM
                     $this->em->detach($lead);
                     unset($lead);
                 }
             }
             // Next batch
             $start += $limit;
             // Save RAM
             $this->em->clear('Mautic\\LeadBundle\\Entity\\Lead');
             $this->em->clear('Mautic\\UserBundle\\Entity\\User');
             unset($leads, $campaignLeadIds, $leadLog);
             $currentCount = $max ? $totalEventCount : $negativeEvaluatedCount;
             if ($output && $currentCount < $maxCount) {
                 $progress->setProgress($currentCount);
             }
             // Free some memory
             gc_collect_cycles();
             ++$batchDebugCounter;
         }
         if ($output) {
             $progress->finish();
             $output->writeln('');
         }
     }
     $counts = ['events' => $nonActionEventCount, 'evaluated' => $negativeEvaluatedCount, 'executed' => $negativeExecutedCount, 'totalEvaluated' => $evaluatedEventCount, 'totalExecuted' => $executedEventCount];
     $this->logger->debug('CAMPAIGN: Counts - ' . var_export($counts, true));
     return $returnCounts ? $counts : $executedEventCount;
 }
コード例 #7
0
ファイル: SubmissionModel.php プロジェクト: Yame-/mautic
 /**
  * @param $post
  * @param $server
  * @param Form $form
  *
  * @return boolean|string false if no error was encountered; otherwise the error message
  */
 public function saveSubmission($post, $server, Form $form)
 {
     $fieldHelper = new FormFieldHelper($this->translator);
     //everything matches up so let's save the results
     $submission = new Submission();
     $submission->setDateSubmitted(new \DateTime());
     $submission->setForm($form);
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     $submission->setIpAddress($ipAddress);
     if (!empty($post['return'])) {
         $referer = $post['return'];
     } elseif (!empty($server['HTTP_REFERER'])) {
         $referer = $server['HTTP_REFERER'];
     } else {
         $referer = '';
     }
     //clean the referer by removing mauticError and mauticMessage
     $referer = InputHelper::url($referer, null, null, array('mauticError', 'mauticMessage'));
     $submission->setReferer($referer);
     $fields = $form->getFields();
     $fieldArray = array();
     $results = array();
     $tokens = array();
     $leadFieldMatches = array();
     $validationErrors = array();
     foreach ($fields as $f) {
         $id = $f->getId();
         $type = $f->getType();
         $alias = $f->getAlias();
         $value = isset($post[$alias]) ? $post[$alias] : '';
         $fieldArray[$id] = array('id' => $id, 'type' => $type, 'alias' => $alias);
         if (in_array($type, array('button', 'freetext'))) {
             //don't save items that don't have a value associated with it
             continue;
         } elseif ($type == 'captcha') {
             $captcha = $fieldHelper->validateFieldValue($type, $value, $f);
             if (!empty($captcha)) {
                 $props = $f->getProperties();
                 //check for a custom message
                 $validationErrors[$alias] = !empty($props['errorMessage']) ? $props['errorMessage'] : implode('<br />', $captcha);
             }
             continue;
         }
         if ($f->isRequired() && empty($value)) {
             //somehow the user got passed the JS validation
             $msg = $f->getValidationMessage();
             if (empty($msg)) {
                 $msg = $this->translator->trans('mautic.form.field.generic.validationfailed', array('%label%' => $f->getLabel()), 'validators');
             }
             $validationErrors[$alias] = $msg;
             continue;
         }
         //clean and validate the input
         if ($f->isCustom()) {
             $params = $f->getCustomParameters();
             if (!empty($value)) {
                 if (isset($params['valueFilter'])) {
                     if (is_string($params['inputFilter'] && method_exists('\\Mautic\\CoreBundle\\Helper\\InputHelper', $params['valueFilter']))) {
                         $value = InputHelper::_($value, $params['valueFilter']);
                     } elseif (is_callable($params['valueFilter'])) {
                         $value = call_user_func_array($params['valueFilter'], array($f, $value));
                     } else {
                         $value = InputHelper::_($value, 'clean');
                     }
                 } else {
                     $value = InputHelper::_($value, 'clean');
                 }
             }
             if (isset($params['valueConstraints']) && is_callable($params['valueConstraints'])) {
                 $customErrors = call_user_func_array($params['valueConstraints'], array($f, $value));
                 if (!empty($customErrors)) {
                     $validationErrors[$alias] = is_array($customErrors) ? implode('<br />', $customErrors) : $customErrors;
                 }
             }
         } elseif (!empty($value)) {
             $filter = $fieldHelper->getFieldFilter($type);
             $value = InputHelper::_($value, $filter);
             $validation = $fieldHelper->validateFieldValue($type, $value);
             if (!empty($validation)) {
                 $validationErrors[$alias] = is_array($validation) ? implode('<br />', $validation) : $validation;
             }
         }
         //convert array from checkbox groups and multiple selects
         if (is_array($value)) {
             $value = implode(", ", $value);
         }
         $tokens["{formfield={$alias}}"] = $value;
         //save the result
         if ($f->getSaveResult() !== false) {
             $results[$alias] = $value;
         }
         $leadField = $f->getLeadField();
         if (!empty($leadField)) {
             $leadFieldMatches[$leadField] = $value;
         }
     }
     $submission->setResults($results);
     //execute submit actions
     $actions = $form->getActions();
     //get post submit actions to make sure it still exists
     $components = $this->formModel->getCustomComponents();
     $availableActions = $components['actions'];
     $args = array('post' => $post, 'server' => $server, 'factory' => $this->factory, 'submission' => $submission, 'fields' => $fieldArray, 'form' => $form, 'tokens' => $tokens);
     foreach ($actions as $action) {
         $key = $action->getType();
         if (!isset($availableActions[$key])) {
             continue;
         }
         $settings = $availableActions[$key];
         $args['action'] = $action;
         $args['config'] = $action->getProperties();
         if (array_key_exists('validator', $settings)) {
             $callback = $settings['validator'];
             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;
                     }
                 }
                 list($validated, $validatedMessage) = $reflection->invokeArgs($this, $pass);
                 if (!$validated) {
                     $validationErrors[$alias] = $validatedMessage;
                 }
             }
         }
     }
     //return errors
     if (!empty($validationErrors)) {
         return array('errors' => $validationErrors);
     }
     //set the landing page the form was submitted from if applicable
     if (!empty($post['mauticpage'])) {
         $page = $this->pageModel->getEntity((int) $post['mauticpage']);
         if ($page != null) {
             $submission->setPage($page);
         }
     }
     // Add a feedback parameter
     $args['feedback'] = array();
     // Create/update lead
     if (!empty($leadFieldMatches)) {
         $this->createLeadFromSubmit($form, $leadFieldMatches);
     }
     if ($form->isStandalone()) {
         // Now handle post submission actions
         foreach ($actions as $action) {
             $key = $action->getType();
             if (!isset($availableActions[$key])) {
                 continue;
             }
             $settings = $availableActions[$key];
             $args['action'] = $action;
             $args['config'] = $action->getProperties();
             // Set the lead each time in case an action updates it
             $args['lead'] = $this->leadModel->getCurrentLead();
             $callback = $settings['callback'];
             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;
                     }
                 }
                 $returned = $reflection->invokeArgs($this, $pass);
                 $args['feedback'][$key] = $returned;
             }
         }
     }
     // Get updated lead with tracking ID
     if ($form->isInKioskMode()) {
         $lead = $this->leadModel->getCurrentLead();
     } else {
         list($lead, $trackingId, $generated) = $this->leadModel->getCurrentLead(true);
         //set tracking ID for stats purposes to determine unique hits
         $submission->setTrackingId($trackingId);
     }
     $submission->setLead($lead);
     if (!$form->isStandalone()) {
         // Find and add the lead to the associated campaigns
         $campaigns = $this->campaignModel->getCampaignsByForm($form);
         if (!empty($campaigns)) {
             foreach ($campaigns as $campaign) {
                 $this->campaignModel->addLead($campaign, $lead);
             }
         }
     }
     //save entity after the form submission events are fired in case a new lead is created
     $this->saveEntity($submission);
     if ($this->dispatcher->hasListeners(FormEvents::FORM_ON_SUBMIT)) {
         $event = new SubmissionEvent($submission, $post, $server);
         $this->dispatcher->dispatch(FormEvents::FORM_ON_SUBMIT, $event);
     }
     //last round of callback commands from the submit actions; first come first serve
     foreach ($args['feedback'] as $k => $data) {
         if (!empty($data['callback'])) {
             return array('callback' => $data);
         }
     }
     //made it to the end so return false that there was not an error
     return false;
 }