| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- <?php
- namespace MailPoet\Newsletter\Statistics;
- if (!defined('ABSPATH')) exit;
- use MailPoet\Doctrine\Repository;
- use MailPoet\Entities\NewsletterEntity;
- use MailPoet\Entities\ScheduledTaskEntity;
- use MailPoet\Entities\StatisticsBounceEntity;
- use MailPoet\Entities\StatisticsClickEntity;
- use MailPoet\Entities\StatisticsOpenEntity;
- use MailPoet\Entities\StatisticsUnsubscribeEntity;
- use MailPoet\Entities\StatisticsWooCommercePurchaseEntity;
- use MailPoet\Entities\UserAgentEntity;
- use MailPoet\WooCommerce\Helper as WCHelper;
- use MailPoetVendor\Doctrine\ORM\EntityManager;
- use MailPoetVendor\Doctrine\ORM\QueryBuilder;
- use MailPoetVendor\Doctrine\ORM\UnexpectedResultException;
- /**
- * @extends Repository<NewsletterEntity>
- */
- class NewsletterStatisticsRepository extends Repository {
- /** @var WCHelper */
- private $wcHelper;
- public function __construct(
- EntityManager $entityManager,
- WCHelper $wcHelper
- ) {
- parent::__construct($entityManager);
- $this->wcHelper = $wcHelper;
- }
- protected function getEntityClassName() {
- return NewsletterEntity::class;
- }
- public function getStatistics(NewsletterEntity $newsletter): NewsletterStatistics {
- $stats = new NewsletterStatistics(
- $this->getStatisticsClickCount($newsletter),
- $this->getStatisticsOpenCount($newsletter),
- $this->getStatisticsUnsubscribeCount($newsletter),
- $this->getStatisticsBounceCount($newsletter),
- $this->getTotalSentCount($newsletter),
- $this->getWooCommerceRevenue($newsletter)
- );
- $stats->setMachineOpenCount($this->getStatisticsMachineOpenCount($newsletter));
- return $stats;
- }
- /**
- * @param NewsletterEntity[] $newsletters
- * @return NewsletterStatistics[]
- */
- public function getBatchStatistics(array $newsletters): array {
- $totalSentCounts = $this->getTotalSentCounts($newsletters);
- $clickCounts = $this->getStatisticCounts(StatisticsClickEntity::class, $newsletters);
- $openCounts = $this->getStatisticCounts(StatisticsOpenEntity::class, $newsletters);
- $unsubscribeCounts = $this->getStatisticCounts(StatisticsUnsubscribeEntity::class, $newsletters);
- $bounceCounts = $this->getStatisticCounts(StatisticsBounceEntity::class, $newsletters);
- $wooCommerceRevenues = $this->getWooCommerceRevenues($newsletters);
- $statistics = [];
- foreach ($newsletters as $newsletter) {
- $id = $newsletter->getId();
- $statistics[$id] = new NewsletterStatistics(
- $clickCounts[$id] ?? 0,
- $openCounts[$id] ?? 0,
- $unsubscribeCounts[$id] ?? 0,
- $bounceCounts[$id] ?? 0,
- $totalSentCounts[$id] ?? 0,
- $wooCommerceRevenues[$id] ?? null
- );
- }
- return $statistics;
- }
- public function getTotalSentCount(NewsletterEntity $newsletter): int {
- $counts = $this->getTotalSentCounts([$newsletter]);
- return $counts[$newsletter->getId()] ?? 0;
- }
- public function getStatisticsClickCount(NewsletterEntity $newsletter): int {
- $counts = $this->getStatisticCounts(StatisticsClickEntity::class, [$newsletter]);
- return $counts[$newsletter->getId()] ?? 0;
- }
- public function getStatisticsOpenCount(NewsletterEntity $newsletter): int {
- $counts = $this->getStatisticCounts(StatisticsOpenEntity::class, [$newsletter]);
- return $counts[$newsletter->getId()] ?? 0;
- }
- public function getStatisticsMachineOpenCount(NewsletterEntity $newsletter): int {
- $qb = $this->getStatisticsQuery(StatisticsOpenEntity::class, [$newsletter]);
- $result = $qb->andWhere('(stats.userAgentType = :userAgentType)')
- ->setParameter('userAgentType', UserAgentEntity::USER_AGENT_TYPE_MACHINE)
- ->getQuery()
- ->getOneOrNullResult();
- if (empty($result)) return 0;
- return $result['cnt'] ?? 0;
- }
- public function getStatisticsUnsubscribeCount(NewsletterEntity $newsletter): int {
- $counts = $this->getStatisticCounts(StatisticsUnsubscribeEntity::class, [$newsletter]);
- return $counts[$newsletter->getId()] ?? 0;
- }
- public function getStatisticsBounceCount(NewsletterEntity $newsletter): int {
- $counts = $this->getStatisticCounts(StatisticsBounceEntity::class, [$newsletter]);
- return $counts[$newsletter->getId()] ?? 0;
- }
- public function getWooCommerceRevenue(NewsletterEntity $newsletter) {
- $revenues = $this->getWooCommerceRevenues([$newsletter]);
- return $revenues[$newsletter->getId()] ?? null;
- }
- /**
- * @param NewsletterEntity $newsletter
- * @return int
- */
- public function getChildrenCount(NewsletterEntity $newsletter) {
- try {
- return (int)$this->entityManager
- ->createQueryBuilder()
- ->select('COUNT(n.id) as cnt')
- ->from(NewsletterEntity::class, 'n')
- ->where('n.parent = :newsletter')
- ->setParameter('newsletter', $newsletter)
- ->getQuery()
- ->getSingleScalarResult();
- } catch (UnexpectedResultException $e) {
- return 0;
- }
- }
- private function getTotalSentCounts(array $newsletters): array {
- $results = $this->doctrineRepository
- ->createQueryBuilder('n')
- ->select('n.id, SUM(q.countProcessed) AS cnt')
- ->join('n.queues', 'q')
- ->join('q.task', 't')
- ->where('t.status = :status')
- ->setParameter('status', ScheduledTaskEntity::STATUS_COMPLETED)
- ->andWhere('q.newsletter IN (:newsletters)')
- ->setParameter('newsletters', $newsletters)
- ->groupBy('n.id')
- ->getQuery()
- ->getResult();
- $counts = [];
- foreach ($results ?: [] as $result) {
- $counts[(int)$result['id']] = (int)$result['cnt'];
- }
- return $counts;
- }
- private function getStatisticCounts(string $statisticsEntityName, array $newsletters): array {
- $qb = $this->getStatisticsQuery($statisticsEntityName, $newsletters);
- if (in_array($statisticsEntityName, [StatisticsOpenEntity::class, StatisticsClickEntity::class], true)) {
- $qb->andWhere('(stats.userAgentType = :userAgentType) OR (stats.userAgentType IS NULL)')
- ->setParameter('userAgentType', UserAgentEntity::USER_AGENT_TYPE_HUMAN);
- }
- $results = $qb
- ->getQuery()
- ->getResult();
- $counts = [];
- foreach ($results ?: [] as $result) {
- $counts[(int)$result['id']] = (int)$result['cnt'];
- }
- return $counts;
- }
- private function getStatisticsQuery(string $statisticsEntityName, array $newsletters): QueryBuilder {
- return $this->entityManager->createQueryBuilder()
- ->select('IDENTITY(stats.newsletter) AS id, COUNT(DISTINCT stats.subscriber) as cnt')
- ->from($statisticsEntityName, 'stats')
- ->where('stats.newsletter IN (:newsletters)')
- ->groupBy('stats.newsletter')
- ->setParameter('newsletters', $newsletters);
- }
- private function getWooCommerceRevenues(array $newsletters) {
- if (!$this->wcHelper->isWooCommerceActive()) {
- return null;
- }
- $currency = $this->wcHelper->getWoocommerceCurrency();
- $results = $this->entityManager
- ->createQueryBuilder()
- ->select('IDENTITY(stats.newsletter) AS id, SUM(stats.orderPriceTotal) AS total, COUNT(stats.id) AS cnt')
- ->from(StatisticsWooCommercePurchaseEntity::class, 'stats')
- ->where('stats.newsletter IN (:newsletters)')
- ->andWhere('stats.orderCurrency = :currency')
- ->setParameter('newsletters', $newsletters)
- ->setParameter('currency', $currency)
- ->groupBy('stats.newsletter')
- ->getQuery()
- ->getResult();
- $revenues = [];
- foreach ($results ?: [] as $result) {
- $revenues[(int)$result['id']] = new WooCommerceRevenue(
- $currency,
- (float)$result['total'],
- (int)$result['cnt'],
- $this->wcHelper
- );
- }
- return $revenues;
- }
- }
|