Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Doctrine\DBAL\ArrayParameterType;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use Mautic\CoreBundle\Doctrine\Provider\GeneratedColumnsProviderInterface;
|
||||
use Mautic\CoreBundle\Helper\Chart\ChartQuery;
|
||||
use Mautic\CoreBundle\Helper\Chart\DateRangeUnitTrait;
|
||||
use Mautic\CoreBundle\Helper\UserHelper;
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
use Mautic\StatsBundle\Aggregate\Collector;
|
||||
|
||||
abstract class AbstractHelper implements StatHelperInterface
|
||||
{
|
||||
use FilterTrait;
|
||||
use DateRangeUnitTrait;
|
||||
|
||||
public function __construct(
|
||||
private Collector $collector,
|
||||
Connection $connection,
|
||||
protected GeneratedColumnsProviderInterface $generatedColumnsProvider,
|
||||
private UserHelper $userHelper,
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetchStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options)
|
||||
{
|
||||
$statCollection = $this->collector->fetchStats($this->getName(), $fromDateTime, $toDateTime, $options);
|
||||
$calculator = $statCollection->getCalculator($fromDateTime, $toDateTime);
|
||||
|
||||
$stats = match ($this->getTimeUnitFromDateRange($fromDateTime, $toDateTime)) {
|
||||
'Y' => $calculator->getSumsByYear(),
|
||||
'm' => $calculator->getSumsByMonth(),
|
||||
'W' => $calculator->getSumsByWeek(),
|
||||
'd' => $calculator->getSumsByDay(),
|
||||
default => $calculator->getCountsByHour(),
|
||||
};
|
||||
|
||||
// Chart.js only care about the values
|
||||
return array_values($stats->getStats());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChartQuery
|
||||
*/
|
||||
protected function getQuery(\DateTime $fromDateTime, \DateTime $toDateTime)
|
||||
{
|
||||
$unit = $this->getTimeUnitFromDateRange($fromDateTime, $toDateTime);
|
||||
|
||||
if ('W' == $unit) { // We won't support week storage, we will store it by date
|
||||
$unit = 'd';
|
||||
}
|
||||
$query = new ChartQuery($this->connection, $fromDateTime, $toDateTime, $unit);
|
||||
|
||||
$query->setGeneratedColumnProvider($this->generatedColumnsProvider);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the email table and limits created_by to currently logged in user.
|
||||
*
|
||||
* @param string $emailIdColumn
|
||||
*/
|
||||
protected function limitQueryToCreator(QueryBuilder $q, $emailIdColumn = 't.email_id')
|
||||
{
|
||||
$q->join('t', MAUTIC_TABLE_PREFIX.'emails', 'e', 'e.id = '.$emailIdColumn)
|
||||
->andWhere('e.created_by = :userId')
|
||||
->setParameter('userId', $this->userHelper->getUser()->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $prefix
|
||||
*/
|
||||
protected function limitQueryToEmailIds(QueryBuilder $q, array $ids, $column, $prefix)
|
||||
{
|
||||
if (0 === count($ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (1 === count($ids)) {
|
||||
$q->andWhere("$prefix.$column = :email_id");
|
||||
$q->setParameter('email_id', $ids[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$q->andWhere("$prefix.$column IN (:email_ids)");
|
||||
$q->setParameter('email_ids', $ids, ArrayParameterType::INTEGER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function fetchAndBindToCollection(QueryBuilder $q, StatCollection $statCollection)
|
||||
{
|
||||
$results = $q->executeQuery()->fetchAllAssociative();
|
||||
foreach ($results as $result) {
|
||||
$statCollection->addStatByDateTimeStringInUTC($result['date'], $result['count']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\LeadBundle\Entity\DoNotContact;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
class BouncedHelper extends AbstractHelper
|
||||
{
|
||||
public const NAME = 'email-bounced';
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection): void
|
||||
{
|
||||
$query = $this->getQuery($fromDateTime, $toDateTime);
|
||||
$q = $query->prepareTimeDataQuery('lead_donotcontact', 'date_added');
|
||||
|
||||
$q->andWhere('t.channel = :channel')
|
||||
->setParameter('channel', 'email')
|
||||
->andWhere($q->expr()->eq('t.reason', ':reason'))
|
||||
->setParameter('reason', DoNotContact::BOUNCED);
|
||||
|
||||
$this->limitQueryToEmailIds($q, $options->getEmailIds(), 'channel_id', 't');
|
||||
|
||||
$q->join('t', MAUTIC_TABLE_PREFIX.'email_stats', 'es', 't.channel_id = es.email_id AND t.channel = \'email\' AND t.lead_id = es.lead_id');
|
||||
|
||||
if (!$options->canViewOthers()) {
|
||||
$this->limitQueryToCreator($q, 'es.email_id');
|
||||
}
|
||||
$this->addCompanyFilter($q, $options->getCompanyId());
|
||||
$this->addCampaignFilter($q, $options->getCampaignId(), 'es');
|
||||
$this->addSegmentFilter($q, $options->getSegmentId(), 'es');
|
||||
|
||||
$this->fetchAndBindToCollection($q, $statCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
class ClickedHelper extends AbstractHelper
|
||||
{
|
||||
public const NAME = 'email-clicked';
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection): void
|
||||
{
|
||||
$query = $this->getQuery($fromDateTime, $toDateTime);
|
||||
$q = $query->prepareTimeDataQuery('page_hits', 'date_hit', [], 'DISTINCT t.email_id, t.redirect_id, t.lead_id');
|
||||
|
||||
if ($segmentId = $options->getSegmentId()) {
|
||||
$q->innerJoin(
|
||||
't',
|
||||
'(SELECT DISTINCT email_id, lead_id FROM '.MAUTIC_TABLE_PREFIX.'email_stats WHERE list_id = :segmentId)',
|
||||
'es',
|
||||
't.source_id = es.email_id'
|
||||
);
|
||||
$q->setParameter('segmentId', $segmentId);
|
||||
}
|
||||
|
||||
$q->andWhere('t.source = :source');
|
||||
$q->setParameter('source', 'email');
|
||||
|
||||
$this->limitQueryToEmailIds($q, $options->getEmailIds(), 'source_id', 't');
|
||||
|
||||
if (!$options->canViewOthers()) {
|
||||
$this->limitQueryToCreator($q);
|
||||
}
|
||||
|
||||
$this->addCompanyFilter($q, $options->getCompanyId());
|
||||
$this->addCampaignFilterForEmailSource($q, $options->getCampaignId());
|
||||
$this->addSegmentFilter($q, $segmentId, 'es');
|
||||
|
||||
$this->fetchAndBindToCollection($q, $statCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
class FailedHelper extends AbstractHelper
|
||||
{
|
||||
public const NAME = 'email-failed';
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection): void
|
||||
{
|
||||
$query = $this->getQuery($fromDateTime, $toDateTime);
|
||||
$q = $query->prepareTimeDataQuery('email_stats', 'date_sent', $options->getFilters());
|
||||
|
||||
$this->limitQueryToEmailIds($q, $options->getEmailIds(), 'email_id', 't');
|
||||
|
||||
if (!$options->canViewOthers()) {
|
||||
$this->limitQueryToCreator($q);
|
||||
}
|
||||
|
||||
$q->andWhere($q->expr()->eq('t.is_failed', ':true'))
|
||||
->setParameter('true', true, 'boolean');
|
||||
|
||||
$this->addCompanyFilter($q, $options->getCompanyId());
|
||||
$this->addCampaignFilter($q, $options->getCampaignId());
|
||||
$this->addSegmentFilter($q, $options->getSegmentId());
|
||||
|
||||
$this->fetchAndBindToCollection($q, $statCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
|
||||
trait FilterTrait
|
||||
{
|
||||
/**
|
||||
* @var Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @param int|null $companyId
|
||||
* @param string $fromAlias
|
||||
*/
|
||||
protected function addCompanyFilter(QueryBuilder $q, $companyId = null, $fromAlias = 't')
|
||||
{
|
||||
if (null !== $companyId && intval($companyId)) {
|
||||
$sb = $this->connection->createQueryBuilder();
|
||||
|
||||
$sb->select('null')
|
||||
->from(MAUTIC_TABLE_PREFIX.'companies_leads', 'cl')
|
||||
->where(
|
||||
$sb->expr()->and(
|
||||
$sb->expr()->eq('cl.company_id', ':companyId'),
|
||||
$sb->expr()->eq('cl.lead_id', $fromAlias.'.lead_id')
|
||||
)
|
||||
);
|
||||
|
||||
$q->andWhere(
|
||||
sprintf('EXISTS (%s)', $sb->getSql())
|
||||
)->setParameter('companyId', $companyId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $campaignId
|
||||
* @param string $fromAlias
|
||||
*/
|
||||
protected function addCampaignFilter(QueryBuilder $q, $campaignId = null, $fromAlias = 't')
|
||||
{
|
||||
if (null !== $campaignId && intval($campaignId)) {
|
||||
$q->innerJoin($fromAlias, '(SELECT DISTINCT event_id, lead_id FROM '.MAUTIC_TABLE_PREFIX.'campaign_lead_event_log WHERE campaign_id = :campaignId)', 'clel', $fromAlias.'.source_id = clel.event_id AND '.$fromAlias.'.source = "campaign.event" AND '.$fromAlias.'.lead_id = clel.lead_id')
|
||||
->setParameter('campaignId', $campaignId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $campaignId
|
||||
* @param string $fromAlias
|
||||
*/
|
||||
protected function addCampaignFilterForEmailSource(QueryBuilder $q, $campaignId = null, $fromAlias = 't')
|
||||
{
|
||||
if (null !== $campaignId && intval($campaignId)) {
|
||||
$q->innerJoin($fromAlias, '(SELECT DISTINCT channel_id, lead_id FROM '.MAUTIC_TABLE_PREFIX.'campaign_lead_event_log WHERE campaign_id = :campaignId AND channel = "email")', 'clel', $fromAlias.'.source_id = clel.channel_id AND '.$fromAlias.'.source = "email" AND '.$fromAlias.'.lead_id = clel.lead_id')
|
||||
->setParameter('campaignId', $campaignId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $segmentId
|
||||
* @param string $fromAlias
|
||||
*/
|
||||
protected function addSegmentFilter(QueryBuilder $q, $segmentId = null, $fromAlias = 't')
|
||||
{
|
||||
if (null !== $segmentId && intval($segmentId)) {
|
||||
$sb = $this->connection->createQueryBuilder();
|
||||
|
||||
$sb->select('null')
|
||||
->from(MAUTIC_TABLE_PREFIX.'lead_lists_leads', 'lll')
|
||||
->where(
|
||||
$sb->expr()->and(
|
||||
$sb->expr()->eq('lll.leadlist_id', ':segmentId'),
|
||||
$sb->expr()->eq('lll.lead_id', $fromAlias.'.lead_id'),
|
||||
$sb->expr()->eq('lll.manually_removed', 0)
|
||||
)
|
||||
);
|
||||
|
||||
$q->andWhere(
|
||||
sprintf('EXISTS (%s)', $sb->getSql())
|
||||
)->setParameter('segmentId', $segmentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
class OpenedHelper extends AbstractHelper
|
||||
{
|
||||
public const NAME = 'email-opened';
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection): void
|
||||
{
|
||||
$query = $this->getQuery($fromDateTime, $toDateTime);
|
||||
$q = $query->prepareTimeDataQuery('email_stats', 'date_read', $options->getFilters());
|
||||
|
||||
$this->limitQueryToEmailIds($q, $options->getEmailIds(), 'email_id', 't');
|
||||
|
||||
if (!$options->canViewOthers()) {
|
||||
$this->limitQueryToCreator($q);
|
||||
}
|
||||
|
||||
$this->addCompanyFilter($q, $options->getCompanyId());
|
||||
$this->addCampaignFilter($q, $options->getCampaignId());
|
||||
$this->addSegmentFilter($q, $options->getSegmentId());
|
||||
|
||||
$this->fetchAndBindToCollection($q, $statCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
class SentHelper extends AbstractHelper
|
||||
{
|
||||
public const NAME = 'email-sent';
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection): void
|
||||
{
|
||||
$useGeneratedColumn = $this->generatedColumnsProvider->generatedColumnsAreSupported() && 'd' == $options->getUnit();
|
||||
$column = $useGeneratedColumn ? 'generated_sent_date' : 'date_sent';
|
||||
$query = $this->getQuery($fromDateTime, $toDateTime);
|
||||
$q = $query->prepareTimeDataQuery('email_stats', $column, $options->getFilters());
|
||||
|
||||
$this->limitQueryToEmailIds($q, $options->getEmailIds(), 'email_id', 't');
|
||||
|
||||
if (!$options->canViewOthers()) {
|
||||
$this->limitQueryToCreator($q);
|
||||
}
|
||||
|
||||
$this->addCompanyFilter($q, $options->getCompanyId());
|
||||
$this->addCampaignFilter($q, $options->getCampaignId());
|
||||
$this->addSegmentFilter($q, $options->getSegmentId());
|
||||
|
||||
$this->fetchAndBindToCollection($q, $statCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
interface StatHelperInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
public function fetchStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options);
|
||||
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Stats\Helper;
|
||||
|
||||
use Mautic\EmailBundle\Stats\FetchOptions\EmailStatOptions;
|
||||
use Mautic\LeadBundle\Entity\DoNotContact;
|
||||
use Mautic\StatsBundle\Aggregate\Collection\StatCollection;
|
||||
|
||||
class UnsubscribedHelper extends AbstractHelper
|
||||
{
|
||||
public const NAME = 'email-unsubscribed';
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateStats(\DateTime $fromDateTime, \DateTime $toDateTime, EmailStatOptions $options, StatCollection $statCollection): void
|
||||
{
|
||||
$query = $this->getQuery($fromDateTime, $toDateTime);
|
||||
$q = $query->prepareTimeDataQuery('lead_donotcontact', 'date_added');
|
||||
|
||||
$q->andWhere('t.channel = :channel')
|
||||
->setParameter('channel', 'email')
|
||||
->andWhere($q->expr()->eq('t.reason', ':reason'))
|
||||
->setParameter('reason', DoNotContact::UNSUBSCRIBED);
|
||||
|
||||
$this->limitQueryToEmailIds($q, $options->getEmailIds(), 'channel_id', 't');
|
||||
|
||||
$q->join('t', MAUTIC_TABLE_PREFIX.'email_stats', 'es', 't.channel_id = es.email_id AND t.channel = \'email\' AND t.lead_id = es.lead_id');
|
||||
|
||||
if (!$options->canViewOthers()) {
|
||||
$this->limitQueryToCreator($q, 'es.email_id');
|
||||
}
|
||||
$this->addCompanyFilter($q, $options->getCompanyId());
|
||||
$this->addCampaignFilter($q, $options->getCampaignId(), 'es');
|
||||
$this->addSegmentFilter($q, $options->getSegmentId(), 'es');
|
||||
|
||||
$this->fetchAndBindToCollection($q, $statCollection);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user