Files
piratepoet/mailpoet/lib/Subscribers/Statistics/SubscriberStatisticsRepository.php
John Oleksowicz 62ac4d5e27 Make stats consistent with engagement score
This makes SubscriberStatisticsRepository the source of truth for
engagement score data instead of having separate queries.

As part of this change, we will now only be displaying the last year's
worth of data when viewing a report for an individual subscriber.

It also updates engagement score calculation to only count human opens,
not machine opens.

MAILPOET-5410
2023-08-11 16:39:57 +02:00

124 lines
4.4 KiB
PHP

<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Subscribers\Statistics;
use MailPoet\Doctrine\Repository;
use MailPoet\Entities\StatisticsClickEntity;
use MailPoet\Entities\StatisticsNewsletterEntity;
use MailPoet\Entities\StatisticsOpenEntity;
use MailPoet\Entities\StatisticsWooCommercePurchaseEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\UserAgentEntity;
use MailPoet\Newsletter\Statistics\WooCommerceRevenue;
use MailPoet\WooCommerce\Helper as WCHelper;
use MailPoetVendor\Carbon\Carbon;
use MailPoetVendor\Doctrine\ORM\EntityManager;
use MailPoetVendor\Doctrine\ORM\QueryBuilder;
/**
* @extends Repository<SubscriberEntity>
*/
class SubscriberStatisticsRepository extends Repository {
/** @var WCHelper */
private $wcHelper;
public function __construct(
EntityManager $entityManager,
WCHelper $wcHelper
) {
parent::__construct($entityManager);
$this->wcHelper = $wcHelper;
}
protected function getEntityClassName() {
return SubscriberEntity::class;
}
public function getStatistics(SubscriberEntity $subscriber) {
return new SubscriberStatistics(
$this->getStatisticsClickCount($subscriber),
$this->getStatisticsOpenCount($subscriber),
$this->getStatisticsMachineOpenCount($subscriber),
$this->getTotalSentCount($subscriber),
$this->getWooCommerceRevenue($subscriber)
);
}
public function getStatisticsClickCount(SubscriberEntity $subscriber): int {
$dateTime = (new Carbon())->subYear();
return (int)$this->getStatisticsCountQuery(StatisticsClickEntity::class, $subscriber)
->andWhere('stats.createdAt > :dateTime')
->setParameter('dateTime', $dateTime)
->getQuery()
->getSingleScalarResult();
}
public function getStatisticsOpenCountQuery(SubscriberEntity $subscriber): QueryBuilder {
$dateTime = (new Carbon())->subYear();
return $this->getStatisticsCountQuery(StatisticsOpenEntity::class, $subscriber)
->join('stats.newsletter', 'newsletter')
->andWhere('(newsletter.sentAt > :dateTime OR newsletter.sentAt IS NULL)')
->andWhere('stats.createdAt > :dateTime')
->setParameter('dateTime', $dateTime);
}
public function getStatisticsOpenCount(SubscriberEntity $subscriber): int {
return (int)$this->getStatisticsOpenCountQuery($subscriber)
->andWhere('(stats.userAgentType = :userAgentType)')
->setParameter('userAgentType', UserAgentEntity::USER_AGENT_TYPE_HUMAN)
->getQuery()
->getSingleScalarResult();
}
public function getStatisticsMachineOpenCount(SubscriberEntity $subscriber): int {
return (int)$this->getStatisticsOpenCountQuery($subscriber)
->andWhere('(stats.userAgentType = :userAgentType)')
->setParameter('userAgentType', UserAgentEntity::USER_AGENT_TYPE_MACHINE)
->getQuery()
->getSingleScalarResult();
}
public function getTotalSentCount(SubscriberEntity $subscriber): int {
$dateTime = (new Carbon())->subYear();
return $this->getStatisticsCountQuery(StatisticsNewsletterEntity::class, $subscriber)
->andWhere('stats.sentAt > :dateTime')
->setParameter('dateTime', $dateTime)
->getQuery()
->getSingleScalarResult();
}
public function getStatisticsCountQuery(string $entityName, SubscriberEntity $subscriber): QueryBuilder {
return $this->entityManager->createQueryBuilder()
->select('COUNT(DISTINCT stats.newsletter) as cnt')
->from($entityName, 'stats')
->where('stats.subscriber = :subscriber')
->setParameter('subscriber', $subscriber);
}
public function getWooCommerceRevenue(SubscriberEntity $subscriber) {
if (!$this->wcHelper->isWooCommerceActive()) {
return null;
}
$currency = $this->wcHelper->getWoocommerceCurrency();
$purchases = $this->entityManager->createQueryBuilder()
->select('stats.orderPriceTotal')
->from(StatisticsWooCommercePurchaseEntity::class, 'stats')
->where('stats.subscriber = :subscriber')
->andWhere('stats.orderCurrency = :currency')
->setParameter('subscriber', $subscriber)
->setParameter('currency', $currency)
->groupBy('stats.orderId, stats.orderPriceTotal')
->getQuery()
->getResult();
$sum = array_sum(array_column($purchases, 'orderPriceTotal'));
return new WooCommerceRevenue(
$currency,
(float)$sum,
count($purchases),
$this->wcHelper
);
}
}