Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\SmsBundle\Broadcast;
|
||||
|
||||
use Mautic\CampaignBundle\Executioner\ContactFinder\Limiter\ContactLimiter;
|
||||
use Mautic\ChannelBundle\Event\ChannelBroadcastEvent;
|
||||
use Mautic\LeadBundle\Entity\LeadRepository;
|
||||
use Mautic\SmsBundle\Entity\Sms;
|
||||
use Mautic\SmsBundle\Model\SmsModel;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class BroadcastExecutioner
|
||||
{
|
||||
private ?ContactLimiter $contactLimiter = null;
|
||||
|
||||
private ?BroadcastResult $result = null;
|
||||
|
||||
public function __construct(
|
||||
private SmsModel $smsModel,
|
||||
private BroadcastQuery $broadcastQuery,
|
||||
private TranslatorInterface $translator,
|
||||
private LeadRepository $leadRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(ChannelBroadcastEvent $event): void
|
||||
{
|
||||
// Get list of published broadcasts or broadcast if there is only a single ID
|
||||
$smses = $this->smsModel->getRepository()->getPublishedBroadcastsIterable($event->getId());
|
||||
foreach ($smses as $sms) {
|
||||
$this->contactLimiter = new ContactLimiter($event->getBatch(), null, $event->getMinContactIdFilter(), $event->getMaxContactIdFilter(), [], $event->getThreadId(), $event->getMaxThreads(), $event->getLimit());
|
||||
$this->result = new BroadcastResult();
|
||||
try {
|
||||
$this->send($sms);
|
||||
} catch (\Exception) {
|
||||
}
|
||||
$event->setResults(
|
||||
sprintf('%s: %s', $this->translator->trans('mautic.sms.sms'), $sms->getName()),
|
||||
$this->result->getSentCount(),
|
||||
$this->result->getFailedCount()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LimitQuotaException
|
||||
* @throws \Mautic\CampaignBundle\Executioner\Exception\NoContactsFoundException
|
||||
*/
|
||||
private function send(Sms $sms): void
|
||||
{
|
||||
$contacts = $this->broadcastQuery->getPendingContacts($sms, $this->contactLimiter);
|
||||
while (!empty($contacts)) {
|
||||
$reduction = 0;
|
||||
$leads = [];
|
||||
foreach ($contacts as $contact) {
|
||||
$contactId = $contact['id'];
|
||||
$results = $this->smsModel->sendSms($sms, $contactId, [
|
||||
'channel'=> [
|
||||
'sms', $sms->getId(),
|
||||
],
|
||||
'listId'=> $contact['listId'],
|
||||
], $leads);
|
||||
$this->result->process($results);
|
||||
$reduction += count($results);
|
||||
}
|
||||
|
||||
$this->contactLimiter->setBatchMinContactId($contactId + 1);
|
||||
|
||||
if ($this->contactLimiter->hasCampaignLimit()) {
|
||||
$this->contactLimiter->reduceCampaignLimitRemaining($reduction);
|
||||
}
|
||||
|
||||
$this->leadRepository->detachEntities($leads);
|
||||
|
||||
// Next batch
|
||||
$contacts = $this->broadcastQuery->getPendingContacts($sms, $this->contactLimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\SmsBundle\Broadcast;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Mautic\CampaignBundle\Entity\ContactLimiterTrait;
|
||||
use Mautic\CampaignBundle\Executioner\ContactFinder\Limiter\ContactLimiter;
|
||||
use Mautic\ChannelBundle\Entity\MessageQueue;
|
||||
use Mautic\SmsBundle\Entity\Sms;
|
||||
use Mautic\SmsBundle\Model\SmsModel;
|
||||
|
||||
class BroadcastQuery
|
||||
{
|
||||
use ContactLimiterTrait;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\DBAL\Query\QueryBuilder
|
||||
*/
|
||||
private $query;
|
||||
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private SmsModel $smsModel,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getPendingContacts(Sms $sms, ContactLimiter $contactLimiter): array
|
||||
{
|
||||
$query = $this->getBasicQuery($sms);
|
||||
$query->select('DISTINCT l.id, ll.id as listId');
|
||||
$this->updateQueryFromContactLimiter('lll', $query, $contactLimiter);
|
||||
|
||||
return $query->executeQuery()->fetchAllAssociative();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
public function getPendingCount(Sms $sms)
|
||||
{
|
||||
$query = $this->getBasicQuery($sms);
|
||||
$query->select('COUNT(DISTINCT l.id)');
|
||||
|
||||
return $query->executeQuery()->fetchOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\DBAL\Query\QueryBuilder
|
||||
*/
|
||||
private function getBasicQuery(Sms $sms)
|
||||
{
|
||||
$this->query = $this->smsModel->getRepository()->getSegmentsContactsQuery($sms->getId());
|
||||
$this->query->andWhere(
|
||||
$this->query->expr()->or(
|
||||
$this->query->expr()->or(
|
||||
$this->query->expr()->isNotNull('l.mobile'),
|
||||
$this->query->expr()->neq('l.mobile', $this->query->expr()->literal(''))
|
||||
),
|
||||
$this->query->expr()->or(
|
||||
$this->query->expr()->isNotNull('l.phone'),
|
||||
$this->query->expr()->neq('l.phone', $this->query->expr()->literal(''))
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->excludeStatsRecords($sms->getId());
|
||||
$this->excludeDnc();
|
||||
$this->excludeQueue();
|
||||
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
private function excludeStatsRecords(int $smsId): void
|
||||
{
|
||||
// Do not include leads that have already received text message
|
||||
$statQb = $this->entityManager->getConnection()->createQueryBuilder();
|
||||
$statQb->select('null')
|
||||
->from(MAUTIC_TABLE_PREFIX.'sms_message_stats', 'stat')
|
||||
->where(
|
||||
$statQb->expr()->and(
|
||||
$statQb->expr()->eq('stat.lead_id', 'l.id'),
|
||||
$statQb->expr()->eq('stat.sms_id', $smsId)
|
||||
)
|
||||
);
|
||||
|
||||
$this->query->andWhere(sprintf('NOT EXISTS (%s)', $statQb->getSQL()));
|
||||
}
|
||||
|
||||
private function excludeDnc(): void
|
||||
{
|
||||
// Do not include leads in the do not contact table
|
||||
$dncQb = $this->entityManager->getConnection()->createQueryBuilder();
|
||||
$dncQb->select('null')
|
||||
->from(MAUTIC_TABLE_PREFIX.'lead_donotcontact', 'dnc')
|
||||
->where(
|
||||
$dncQb->expr()->and(
|
||||
$dncQb->expr()->eq('dnc.lead_id', 'l.id'),
|
||||
$dncQb->expr()->eq('dnc.channel', $dncQb->expr()->literal('sms'))
|
||||
)
|
||||
);
|
||||
$this->query->andWhere(sprintf('NOT EXISTS (%s)', $dncQb->getSQL()));
|
||||
}
|
||||
|
||||
private function excludeQueue(): void
|
||||
{
|
||||
// Do not include contacts where the message is pending in the message queue
|
||||
$mqQb = $this->entityManager->getConnection()->createQueryBuilder();
|
||||
$mqQb->select('null')
|
||||
->from(MAUTIC_TABLE_PREFIX.'message_queue', 'mq')
|
||||
->where(
|
||||
$mqQb->expr()->and(
|
||||
$mqQb->expr()->eq('mq.lead_id', 'l.id'),
|
||||
$mqQb->expr()->neq('mq.status', $mqQb->expr()->literal(MessageQueue::STATUS_SENT)),
|
||||
$mqQb->expr()->eq('mq.channel', $mqQb->expr()->literal('sms'))
|
||||
)
|
||||
);
|
||||
$this->query->andWhere(sprintf('NOT EXISTS (%s)', $mqQb->getSQL()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\SmsBundle\Broadcast;
|
||||
|
||||
class BroadcastResult
|
||||
{
|
||||
private int $sentCount = 0;
|
||||
|
||||
private int $failedCount = 0;
|
||||
|
||||
public function process(array $results): void
|
||||
{
|
||||
foreach ($results as $result) {
|
||||
if (isset($result['sent']) && true === $result['sent']) {
|
||||
$this->sent();
|
||||
} else {
|
||||
$this->failed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function sent(): void
|
||||
{
|
||||
++$this->sentCount;
|
||||
}
|
||||
|
||||
public function failed(): void
|
||||
{
|
||||
++$this->failedCount;
|
||||
}
|
||||
|
||||
public function getSentCount(): int
|
||||
{
|
||||
return $this->sentCount;
|
||||
}
|
||||
|
||||
public function getFailedCount(): int
|
||||
{
|
||||
return $this->failedCount;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user