/**
  * @param array $data
  */
 protected function onStatus(array $data)
 {
     if (isset($data['current'])) {
         $this->progress->setCurrent((int) $data['current']);
         unset($data['current']);
     } else {
         $this->progress->advance();
     }
     foreach ($data as $key => $value) {
         $this->progress->setMessage($value, $key);
     }
 }
 private function getNotificationCallback($filename)
 {
     $notificationCallback = function ($notification_code, $severity, $message, $messageCode, $bytesTransferred, $bytesMax) use($filename) {
         switch ($notification_code) {
             case STREAM_NOTIFY_FILE_SIZE_IS:
                 $this->progress = new ProgressBar($this->output, $bytesMax);
                 $this->progress->setFormat('%message% %final_report%' . "\n" . '%percent:3s%% of %photo_size% [%bar%] %downloaded_bytes% eta %estimated:6s%');
                 $this->progress->setMessage($filename);
                 $this->progress->setMessage('', 'final_report');
                 $this->progress->start();
                 break;
             case STREAM_NOTIFY_PROGRESS:
                 $this->progress->setCurrent($bytesTransferred);
                 break;
         }
     };
     return $notificationCallback;
 }
 /**
  * @param OutputInterface $output
  *
  * @return resource
  */
 protected function createStreamContext(OutputInterface $output)
 {
     $ctx = stream_context_create([], ['notification' => function ($code, $severity, $message, $message_code, $bytesTransferred, $bytesMax) use($output) {
         switch ($code) {
             case STREAM_NOTIFY_FILE_SIZE_IS:
                 $this->progress = new ProgressBar($output, $bytesMax);
                 $this->progress->setBarWidth(75);
                 $this->progress->start();
                 break;
             case STREAM_NOTIFY_PROGRESS:
                 $this->progress->setCurrent($bytesTransferred);
                 if ($bytesTransferred == $bytesMax) {
                     $this->progress->finish();
                     $output->writeln('');
                 }
                 break;
             case STREAM_NOTIFY_COMPLETED:
                 $this->progress->finish();
                 break;
         }
     }]);
     return $ctx;
 }
Beispiel #4
0
 /**
  * Find and trigger the negative events, i.e. the events with a no decision path
  *
  * @param                 $campaign
  * @param int             $totalEventCount
  * @param int             $limit
  * @param bool            $max
  * @param OutputInterface $output
  *
  * @return int
  */
 public function triggerNegativeEvents($campaign, $totalEventCount = 0, $limit = 100, $max = false, OutputInterface $output = null)
 {
     defined('MAUTIC_CAMPAIGN_SYSTEM_TRIGGERED') or define('MAUTIC_CAMPAIGN_SYSTEM_TRIGGERED', 1);
     $logger = $this->factory->getLogger();
     $logger->debug('CAMPAIGN: Triggering negative events');
     $campaignId = $campaign->getId();
     $campaignName = $campaign->getName();
     $repo = $this->getRepository();
     $campaignRepo = $this->getCampaignRepository();
     /** @var \Mautic\CampaignBundle\Model\CampaignModel $campaignModel */
     $campaignModel = $this->factory->getModel('campaign');
     /** @var \Mautic\LeadBundle\Model\LeadModel $leadModel */
     $leadModel = $this->factory->getModel('lead');
     // Get events to avoid large number of joins
     $campaignEvents = $repo->getCampaignEvents($campaignId);
     // Get an array of events that are non-action based
     $nonActionEvents = array();
     foreach ($campaignEvents as $id => $e) {
         if ($e['decisionPath'] == 'no') {
             $nonActionEvents[$e['parent_id']][$id] = $e;
         }
     }
     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', array('%leads%' => $leadCount, '%batch%' => $limit)));
     }
     $start = $eventCount = $leadProcessedCount = $lastRoundPercentage = $processedCount = 0;
     $eventSettings = $campaignModel->getEvents();
     $maxCount = $max ? $max : $leadCount;
     // Try to save some memory
     gc_enable();
     if ($leadCount) {
         if ($output) {
             $progress = new ProgressBar($output, $maxCount);
             $progress->start();
             if ($max) {
                 $progress->advance($totalEventCount);
             }
         }
         $sleepBatchCount = 0;
         while ($start <= $leadCount) {
             // Get batched campaign ids
             $campaignLeads = $campaignRepo->getCampaignLeadIds($campaignId, $start, $limit);
             foreach ($nonActionEvents as $parentId => $events) {
                 // Just a check to ensure this is an appropriate action
                 if ($campaignEvents[$parentId]['eventType'] != 'decision') {
                     $logger->debug('CAMPAIGN: Parent event ID #' . $parentId . ' is not a decision.');
                     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
                 $leadLog = $repo->getEventLog($campaignId, $campaignLeads, array($grandParentId), array_keys($events));
                 $applicableLeads = array_keys($leadLog);
                 if (empty($applicableLeads)) {
                     $logger->debug('CAMPAIGN: No events are applicable');
                     continue;
                 }
                 // Get the leads
                 $leads = $leadModel->getEntities(array('filter' => array('force' => array(array('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
                     continue;
                 }
                 // Loop over the non-actions and determine if it has been processed for this lead
                 foreach ($leads as $l) {
                     // Set lead for listeners
                     $leadModel->setSystemCurrentLead($l);
                     $logger->debug('CAMPAIGN: Lead ID #' . $l->getId());
                     // Prevent path if lead has already gone down this path
                     if (!array_key_exists($parentId, $leadLog[$l->getId()])) {
                         // Get date to compare against
                         $utcDateString = $leadLog[$l->getId()][$grandParentId]['date_triggered'];
                         // Convert to local DateTime
                         $grandParentDate = $this->factory->getDate($utcDateString, 'Y-m-d H:i:s', 'UTC')->getLocalDateTime();
                         // Non-decision has not taken place yet, so cycle over each associated action to see if timing is right
                         $eventTiming = array();
                         $executeAction = false;
                         foreach ($events as $id => $e) {
                             if ($sleepBatchCount == $limit) {
                                 // Keep CPU down
                                 sleep($this->batchSleepTime);
                                 $sleepBatchCount = 0;
                             } else {
                                 $sleepBatchCount++;
                             }
                             if (array_key_exists($id, $leadLog[$l->getId()])) {
                                 $logger->debug('CAMPAIGN: Event (ID #' . $id . ') has already been executed');
                                 unset($e);
                                 continue;
                             }
                             if (!isset($eventSettings['action'][$e['type']])) {
                                 $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) {
                             // Timing is not appropriate so move on to next lead
                             unset($eventTiming);
                             continue;
                         }
                         $logDecision = $decisionLogged = false;
                         // Execute or schedule events
                         foreach ($eventTiming as $id => $timing) {
                             // Set event
                             $e = $events[$id];
                             $e['campaign'] = array('id' => $campaignId, 'name' => $campaignName);
                             // Set lead in case this is triggered by the system
                             $leadModel->setSystemCurrentLead($l);
                             if ($timing instanceof \DateTime) {
                                 $processedCount++;
                                 // Schedule the action
                                 $logger->debug('CAMPAIGN: ID# ' . $e['id'] . ' timing is not appropriate and thus scheduled for ' . $timing->format('Y-m-d H:m:i T') . '');
                                 $log = $this->getLogEntity($e['id'], $campaign, $l, null, true);
                                 $log->setLead($l);
                                 $log->setIsScheduled(true);
                                 $log->setTriggerDate($timing);
                                 $repo->saveEntity($log);
                                 $logDecision = true;
                             } else {
                                 $processedCount++;
                                 // Save log first to prevent subsequent triggers from duplicating
                                 $log = $this->getLogEntity($e['id'], $campaign, $l, null, true);
                                 $log->setDateTriggered(new \DateTime());
                                 $repo->saveEntity($log);
                                 $response = $this->invokeEventCallback($e, $eventSettings['action'][$e['type']], $l, null, true);
                                 if ($response === false) {
                                     $repo->deleteEntity($log);
                                     $logger->debug('CAMPAIGN: ID# ' . $e['id'] . ' execution failed.');
                                     $logDecision = true;
                                 } else {
                                     $logger->debug('CAMPAIGN: ID# ' . $e['id'] . ' successfully executed and logged.');
                                     if ($response !== true) {
                                         $log->setMetadata($response);
                                         $repo->saveEntity($log);
                                     }
                                 }
                             }
                             if (!empty($log)) {
                                 $this->em->detach($log);
                             }
                             unset($e, $log);
                             if ($logDecision && !$decisionLogged) {
                                 // Log the decision
                                 $log = $this->getLogEntity($parentId, $campaign, $l, null, true);
                                 $log->setDateTriggered(new \DateTime());
                                 $log->setNonActionPathTaken(true);
                                 $repo->saveEntity($log);
                                 $this->em->detach($log);
                                 unset($log);
                                 $decisionLogged = true;
                             }
                             if ($max && $totalEventCount >= $max) {
                                 // Hit the max
                                 if ($output) {
                                     $progress->finish();
                                     $output->writeln('');
                                 }
                                 return $eventCount;
                             }
                             $eventCount++;
                             $totalEventCount++;
                             unset($utcDateString, $grandParentDate);
                         }
                     } else {
                         $logger->debug('CAMPAIGN: Decision has already been executed.');
                     }
                     $currentCount = $max ? $totalEventCount : $leadProcessedCount;
                     if ($output && $currentCount < $maxCount) {
                         $progress->setCurrent($currentCount);
                     }
                 }
                 // Save RAM
                 $this->em->detach($l);
                 unset($l);
             }
             // Next batch
             $start += $limit;
             $leadProcessedCount += count($campaignLeads);
             // Save RAM
             $this->em->clear('MauticLeadBundle:Lead');
             $this->em->clear('MauticUserBundle:User');
             unset($leads, $campaignLeads, $leadLog);
             $currentCount = $max ? $eventCount : $leadProcessedCount;
             if ($output && $currentCount < $maxCount) {
                 $progress->setCurrent($currentCount);
             }
             // Free some memory
             gc_collect_cycles();
         }
         if ($output) {
             $progress->finish();
             $output->writeln('');
         }
     }
     return $processedCount;
 }
Beispiel #5
0
 /**
  * Rebuild lead lists
  *
  * @param LeadList        $entity
  * @param int             $limit
  * @param bool            $maxLeads
  * @param OutputInterface $output
  *
  * @return int
  */
 public function rebuildListLeads(LeadList $entity, $limit = 1000, $maxLeads = false, OutputInterface $output = null)
 {
     defined('MAUTIC_REBUILDING_LEAD_LISTS') or define('MAUTIC_REBUILDING_LEAD_LISTS', 1);
     $id = $entity->getId();
     $list = array('id' => $id, 'filters' => $entity->getFilters());
     $dtHelper = $this->factory->getDate();
     $batchLimiters = array('dateTime' => $dtHelper->toUtcString());
     $localDateTime = $dtHelper->getLocalDateTime();
     // Get a count of leads to add
     $newLeadsCount = $this->getLeadsByList($list, true, array('countOnly' => true, 'newOnly' => true, 'dynamic' => true, 'includeManual' => false, 'batchLimiters' => $batchLimiters));
     // Ensure the same list is used each batch
     $batchLimiters['maxId'] = (int) $newLeadsCount[$id]['maxId'];
     // Number of total leads to process
     $leadCount = (int) $newLeadsCount[$id]['count'];
     if ($output) {
         $output->writeln($this->translator->trans('mautic.lead.list.rebuild.to_be_added', array('%leads%' => $leadCount, '%batch%' => $limit)));
     }
     // Handle by batches
     $start = $lastRoundPercentage = $leadsProcessed = 0;
     // Try to save some memory
     gc_enable();
     if ($leadCount) {
         $maxCount = $maxLeads ? $maxLeads : $leadCount;
         if ($output) {
             $progress = new ProgressBar($output, $maxCount);
             $progress->start();
         }
         // Add leads
         while ($start < $leadCount) {
             // Keep CPU down for large lists; sleep per $limit batch
             sleep($this->batchSleepTime);
             $newLeadList = $this->getLeadsByList($list, true, array('dynamic' => true, 'newOnly' => true, 'includeManual' => false, 'limit' => $limit, 'batchLimiters' => $batchLimiters));
             if (empty($newLeadList[$id])) {
                 // Somehow ran out of leads so break out
                 break;
             }
             foreach ($newLeadList[$id] as $l) {
                 $this->addLead($l, $entity, false, true, -1, $localDateTime);
                 unset($l);
                 $leadsProcessed++;
                 if ($output && $leadsProcessed < $maxCount) {
                     $progress->setCurrent($leadsProcessed);
                 }
                 if ($maxLeads && $leadsProcessed >= $maxLeads) {
                     break;
                 }
             }
             $start += $limit;
             // Dispatch batch event
             if ($this->dispatcher->hasListeners(LeadEvents::LEAD_LIST_BATCH_CHANGE)) {
                 $event = new ListChangeEvent($newLeadList[$id], $entity, true);
                 $this->dispatcher->dispatch(LeadEvents::LEAD_LIST_BATCH_CHANGE, $event);
                 unset($event);
             }
             unset($newLeadList);
             // Free some memory
             gc_collect_cycles();
             if ($maxLeads && $leadsProcessed >= $maxLeads) {
                 if ($output) {
                     $progress->finish();
                     $output->writeln('');
                 }
                 return $leadsProcessed;
             }
         }
         if ($output) {
             $progress->finish();
             $output->writeln('');
         }
     }
     $fullList = $this->getLeadsByList($list, true, array('dynamic' => true, 'existingOnly' => true, 'includeManual' => false, 'batchLimiters' => $batchLimiters));
     // Get a count of leads to be removed
     $removeLeadCount = $this->getLeadsByList($list, true, array('countOnly' => true, 'includeManual' => false, 'filterOutIds' => $fullList[$id], 'batchLimiters' => $batchLimiters));
     // Restart batching
     $start = $lastRoundPercentage = 0;
     $leadCount = $removeLeadCount[$id]['count'];
     if ($output) {
         $output->writeln($this->translator->trans('mautic.lead.list.rebuild.to_be_removed', array('%leads%' => $leadCount, '%batch%' => $limit)));
     }
     if ($leadCount) {
         $maxCount = $maxLeads ? $maxLeads : $leadCount;
         if ($output) {
             $progress = new ProgressBar($output, $maxCount);
             $progress->start();
         }
         // Remove leads
         while ($start < $leadCount) {
             // Keep CPU down for large lists; sleep per $limit batch
             sleep($this->batchSleepTime);
             $removeLeadList = $this->getLeadsByList($list, true, array('limit' => $limit, 'filterOutIds' => $fullList[$id], 'batchLimiters' => $batchLimiters));
             if (empty($removeLeadList[$id])) {
                 // Somehow ran out of leads so break out
                 break;
             }
             foreach ($removeLeadList[$id] as $l) {
                 $this->removeLead($l, $entity, false, true, true);
                 $leadsProcessed++;
                 if ($output && $leadsProcessed < $maxCount) {
                     $progress->setCurrent($leadsProcessed);
                 }
                 if ($maxLeads && $leadsProcessed >= $maxLeads) {
                     break;
                 }
             }
             // Dispatch batch event
             if ($this->dispatcher->hasListeners(LeadEvents::LEAD_LIST_BATCH_CHANGE)) {
                 $event = new ListChangeEvent($removeLeadList[$id], $entity, false);
                 $this->dispatcher->dispatch(LeadEvents::LEAD_LIST_BATCH_CHANGE, $event);
                 unset($event);
             }
             $start += $limit;
             unset($removeLeadList);
             // Free some memory
             gc_collect_cycles();
             if ($maxLeads && $leadsProcessed >= $maxLeads) {
                 if ($output) {
                     $progress->finish();
                     $output->writeln('');
                 }
                 return $leadsProcessed;
             }
         }
         if ($output) {
             $progress->finish();
             $output->writeln('');
         }
     }
     return $leadsProcessed;
 }
Beispiel #6
0
 /**
  * @param Driver   $sourceDriver The source driver.
  * @param callable $output       A function to call with every SQL statement.
  * @param string   $message      The message going next to the progress bar.
  *
  * @return void
  */
 private function doDumpDatabase(Driver $sourceDriver, callable $output, string $message)
 {
     $dumper = new Dumper($sourceDriver);
     $progress = new ProgressBar($this->output);
     $progress->setMessage('Counting objects');
     $progress->setFormat('%message% [%bar%] %current%');
     $progress->start();
     $objectCount = 0;
     $dumper->countObjects(function ($count) use($progress, &$objectCount) {
         $objectCount += $count;
         $progress->setCurrent($objectCount);
     });
     $progress->finish();
     $this->output->writeln('');
     $progress = new ProgressBar($this->output, $objectCount);
     $progress->setMessage($message);
     $progress->setFormat('%message% [%bar%] %current%/%max% %percent:3s%%');
     $progress->start();
     $dumper->dumpDatabase(function ($query) use($output, $progress) {
         $output($query);
         $progress->advance();
     });
     $progress->finish();
     $this->output->writeln('');
 }
 /**
  * @param Campaign        $campaign
  * @param int             $limit
  * @param bool            $maxLeads
  * @param OutputInterface $output
  *
  * @return int
  */
 public function rebuildCampaignLeads(Campaign $campaign, $limit = 1000, $maxLeads = false, OutputInterface $output = null)
 {
     defined('MAUTIC_REBUILDING_CAMPAIGNS') or define('MAUTIC_REBUILDING_CAMPAIGNS', 1);
     $repo = $this->getRepository();
     // Get a list of leads for all lists associated with the campaign
     $lists = $this->getCampaignListIds($campaign->getId());
     if (empty($lists)) {
         if ($output) {
             $output->writeln($this->translator->trans('mautic.campaign.rebuild.no_lists'));
         }
         return 0;
     }
     $batchLimiters = array('dateTime' => $this->factory->getDate()->toUtcString());
     // Get a count of new leads
     $newLeadsCount = $repo->getCampaignLeadsFromLists($campaign->getId(), $lists, array('newOnly' => true, 'countOnly' => true, 'batchLimiters' => $batchLimiters));
     // Ensure the same list is used each batch
     $batchLimiters['maxId'] = (int) $newLeadsCount['maxId'];
     // Number of total leads to process
     $leadCount = (int) $newLeadsCount['count'];
     if ($output) {
         $output->writeln($this->translator->trans('mautic.campaign.rebuild.to_be_added', array('%leads%' => $leadCount, '%batch%' => $limit)));
     }
     // Handle by batches
     $start = $leadsProcessed = 0;
     // Try to save some memory
     gc_enable();
     if ($leadCount) {
         $maxCount = $maxLeads ? $maxLeads : $leadCount;
         if ($output) {
             $progress = new ProgressBar($output, $maxCount);
             $progress->start();
         }
         // Add leads
         while ($start < $leadCount) {
             // Keep CPU down for large lists; sleep per $limit batch
             sleep($this->batchSleepTime);
             // Get a count of new leads
             $newLeadList = $repo->getCampaignLeadsFromLists($campaign->getId(), $lists, array('newOnly' => true, 'limit' => $limit, 'batchLimiters' => $batchLimiters));
             $start += $limit;
             foreach ($newLeadList as $l) {
                 $this->addLeads($campaign, array($l), false, true, -1);
                 $leadsProcessed++;
                 if ($output && $leadsProcessed < $maxCount) {
                     $progress->setCurrent($leadsProcessed);
                 }
                 unset($l);
                 if ($maxLeads && $leadsProcessed >= $maxLeads) {
                     // done for this round, bye bye
                     if ($output) {
                         $progress->finish();
                     }
                     return $leadsProcessed;
                 }
             }
             unset($newLeadList);
             // Free some memory
             gc_collect_cycles();
         }
         if ($output) {
             $progress->finish();
             $output->writeln('');
         }
     }
     // Get a count of leads to be removed
     $removeLeadCount = $repo->getCampaignOrphanLeads($campaign->getId(), $lists, array('notInLists' => true, 'countOnly' => true, 'batchLimiters' => $batchLimiters));
     // Restart batching
     $start = $lastRoundPercentage = 0;
     $leadCount = $removeLeadCount['count'];
     if ($output) {
         $output->writeln($this->translator->trans('mautic.lead.list.rebuild.to_be_removed', array('%leads%' => $leadCount, '%batch%' => $limit)));
     }
     if ($leadCount) {
         $maxCount = $maxLeads ? $maxLeads : $leadCount;
         if ($output) {
             $progress = new ProgressBar($output, $maxCount);
             $progress->start();
         }
         // Remove leads
         while ($start < $leadCount) {
             // Keep CPU down for large lists; sleep per $limit batch
             sleep($this->batchSleepTime);
             $removeLeadList = $repo->getCampaignOrphanLeads($campaign->getId(), $lists, array('limit' => $limit, 'batchLimiters' => $batchLimiters));
             foreach ($removeLeadList as $l) {
                 $this->removeLeads($campaign, array($l), false, true, true);
                 $leadsProcessed++;
                 if ($output && $leadsProcessed < $maxCount) {
                     $progress->setCurrent($leadsProcessed);
                 }
                 if ($maxLeads && $leadsProcessed >= $maxLeads) {
                     // done for this round, bye bye
                     $progress->finish();
                     return $leadsProcessed;
                 }
             }
             $start += $limit;
             unset($removeLeadList);
             // Free some memory
             gc_collect_cycles();
         }
         if ($output) {
             $progress->finish();
         }
     }
     return $leadsProcessed;
 }
 public function testClear()
 {
     $bar = new ProgressBar($output = $this->getOutputStream(), 50);
     $bar->start();
     $bar->setCurrent(25);
     $bar->clear();
     rewind($output->getStream());
     $this->assertEquals($this->generateOutput('  0/50 [>---------------------------]   0%') . $this->generateOutput(' 25/50 [==============>-------------]  50%') . $this->generateOutput('                                          '), stream_get_contents($output->getStream()));
 }