Spaces:
No application file
No application file
declare(strict_types=1); | |
namespace Mautic\CampaignBundle\Model; | |
use Mautic\CampaignBundle\Entity\LeadEventLog; | |
use Mautic\CampaignBundle\Entity\LeadEventLogRepository; | |
use Mautic\CampaignBundle\Entity\Summary; | |
use Mautic\CampaignBundle\Entity\SummaryRepository; | |
use Mautic\CoreBundle\Helper\ProgressBarHelper; | |
use Mautic\CoreBundle\Model\AbstractCommonModel; | |
use Symfony\Component\Console\Output\OutputInterface; | |
/** | |
* @extends AbstractCommonModel<Summary> | |
*/ | |
class SummaryModel extends AbstractCommonModel | |
{ | |
private array $logData = []; | |
/** | |
* Collapse Event Log entities into insert/update queries for the campaign summary. | |
* | |
* @throws \Doctrine\DBAL\Exception | |
*/ | |
public function updateSummary(iterable $logs): void | |
{ | |
$now = new \DateTime(); | |
/** @var LeadEventLog $log */ | |
foreach ($logs as $log) { | |
if (!$log->getDateTriggered()) { | |
// This shouldn't normally happen but it's possible to have a log without a date triggered | |
// as it is a nullable field and it can be created without date triggered for example via API. | |
continue; | |
} | |
$timestamp = $log->getDateTriggered()->getTimestamp(); | |
$timestamp -= ($timestamp % 3600); | |
$dateFrom = $now->setTimestamp($timestamp); | |
$dateTo = (clone $dateFrom)->modify('+1 hour -1 second'); | |
$campaign = $log->getCampaign(); | |
$event = $log->getEvent(); | |
$key = $campaign->getId().'.'.$event->getId().'.'.$timestamp; | |
$this->logData[$key] = [ | |
'campaignId' => $campaign->getId(), | |
'eventId' => $event->getId(), | |
'dateFrom' => $dateFrom, | |
'dateTo' => $dateTo, | |
]; | |
} | |
if (count($this->logData) >= 100) { | |
$this->persistSummaries(); | |
} | |
} | |
public function getRepository(): SummaryRepository | |
{ | |
return $this->em->getRepository(Summary::class); | |
} | |
public function getPermissionBase(): string | |
{ | |
return 'campaign:campaigns'; | |
} | |
/** | |
* Summarize all of history. | |
* | |
* @throws \Doctrine\DBAL\Exception | |
*/ | |
public function summarize(OutputInterface $output, int $hoursPerBatch = 1, int $maxHours = null, bool $rebuild = false): void | |
{ | |
$start = null; | |
if (!$rebuild) { | |
$start = $this->getRepository()->getOldestTriggeredDate(); | |
} | |
// Start with the current hour. | |
$start ??= new \DateTime('+1 hour'); | |
$start->setTimestamp($start->getTimestamp() - ($start->getTimestamp() % 3600)); | |
$end = $this->getCampaignLeadEventLogRepository()->getOldestTriggeredDate(); | |
if (!$end) { | |
$output->writeln('There are no records in the campaign lead event log table. Nothing to summarize.'); | |
return; | |
} | |
$end = $end->setTimestamp($end->getTimestamp() - ($end->getTimestamp() % 3600)); | |
$startedAt = new \DateTime(); | |
$output->writeln('<comment>Started at: '.$startedAt->format('Y-m-d H:i:s').'</comment>'); | |
if ($end <= $start) { | |
$hours = ($end->diff($start)->days * 24) + $end->diff($start)->h; | |
if ($maxHours && $hours > $maxHours) { | |
$end = clone $start; | |
$end = $end->sub(new \DateInterval('PT'.$maxHours.'H')); | |
} | |
$progressBar = ProgressBarHelper::init($output, $hours); | |
$progressBar->start(); | |
$interval = new \DateInterval('PT'.$hoursPerBatch.'H'); | |
$dateFrom = clone $start; | |
$dateTo = (clone $start)->modify('-1 second'); | |
do { | |
$dateFrom = $dateFrom->sub($interval); | |
$dateFromFormatted = $dateFrom->format('Y-m-d H:i:s'); | |
$dateToFormatted = $dateTo->format('Y-m-d H:i:s'); | |
$output->write("\t".$dateFromFormatted.' - '.$dateToFormatted); | |
$this->getRepository()->summarize($dateFrom, $dateTo); | |
$progressBar->advance($hoursPerBatch); | |
$dateTo = $dateTo->sub($interval); | |
} while ($end < $dateFrom); | |
$progressBar->finish(); | |
$output->writeln("\n".'<info>Updating summary for log counts processed</info>'); | |
} | |
$this->outputProcessTime($startedAt, $output); | |
} | |
public function getCampaignLeadEventLogRepository(): LeadEventLogRepository | |
{ | |
return $this->em->getRepository(LeadEventLog::class); | |
} | |
/** | |
* @throws \Doctrine\DBAL\Exception | |
*/ | |
public function persistSummaries(): void | |
{ | |
foreach ($this->logData as $log) { | |
$dateFrom = $log['dateFrom']; | |
$dateTo = $log['dateTo']; | |
$campaignId = $log['campaignId']; | |
$eventId = $log['eventId']; | |
$this->getRepository()->summarize($dateFrom, $dateTo, $campaignId, $eventId); | |
} | |
} | |
private function outputProcessTime(\DateTime $startedAt, OutputInterface $output): void | |
{ | |
$endedAt = new \DateTime(); | |
$output->writeln("\n".'<comment>Ended at: '.$endedAt->format('Y-m-d H:i:s').'</comment>'); | |
$completedInterval = $startedAt->diff($endedAt); | |
$output->writeln('<info>Summary completed in: '.$completedInterval->format('%H:%I:%S').'</info>'); | |
} | |
} | |