diff --git a/lib/Config/PersonalDataExporters.php b/lib/Config/PersonalDataExporters.php index 3caba1a2df..c678287bc1 100644 --- a/lib/Config/PersonalDataExporters.php +++ b/lib/Config/PersonalDataExporters.php @@ -47,7 +47,7 @@ class PersonalDataExporters { public function registerNewsletterClicksExporter($exporters) { $exporters[] = [ 'exporter_friendly_name' => WPFunctions::get()->__('MailPoet Email Clicks', 'mailpoet'), - 'callback' => [new NewsletterClicksExporter(), 'export'], + 'callback' => [ContainerWrapper::getInstance()->get(NewsletterClicksExporter::class), 'export'], ]; return $exporters; } @@ -55,7 +55,7 @@ class PersonalDataExporters { public function registerNewsletterOpensExporter($exporters) { $exporters[] = [ 'exporter_friendly_name' => WPFunctions::get()->__('MailPoet Email Opens', 'mailpoet'), - 'callback' => [new NewsletterOpensExporter(), 'export'], + 'callback' => [ContainerWrapper::getInstance()->get(NewsletterOpensExporter::class), 'export'], ]; return $exporters; } diff --git a/lib/DI/ContainerConfigurator.php b/lib/DI/ContainerConfigurator.php index f6068e8b32..ea62920563 100644 --- a/lib/DI/ContainerConfigurator.php +++ b/lib/DI/ContainerConfigurator.php @@ -265,6 +265,8 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Subscribers\SubscriberSubscribeController::class)->setPublic(true); $container->autowire(\MailPoet\Subscribers\ImportExport\ImportExportRepository::class)->setPublic(true); $container->autowire(\MailPoet\Subscribers\ImportExport\PersonalDataExporters\NewslettersExporter::class)->setPublic(true); + $container->autowire(\MailPoet\Subscribers\ImportExport\PersonalDataExporters\NewsletterOpensExporter::class)->setPublic(true); + $container->autowire(\MailPoet\Subscribers\ImportExport\PersonalDataExporters\NewsletterClicksExporter::class)->setPublic(true); $container->autowire(\MailPoet\Subscribers\Statistics\SubscriberStatisticsRepository::class); $container->autowire(\MailPoet\Subscribers\SubscribersCountsController::class)->setPublic(true); // Segments diff --git a/lib/Models/StatisticsClicks.php b/lib/Models/StatisticsClicks.php index 45bb019c89..61b4fa4c2d 100644 --- a/lib/Models/StatisticsClicks.php +++ b/lib/Models/StatisticsClicks.php @@ -3,9 +3,6 @@ namespace MailPoet\Models; use DateTimeInterface; -use MailPoet\DI\ContainerWrapper; -use MailPoet\Entities\UserAgentEntity; -use MailPoetVendor\Doctrine\ORM\EntityManager; /** * @property int $newsletterId @@ -17,35 +14,6 @@ use MailPoetVendor\Doctrine\ORM\EntityManager; class StatisticsClicks extends Model { public static $_table = MP_STATISTICS_CLICKS_TABLE; // phpcs:ignore PSR2.Classes.PropertyDeclaration - public static function getAllForSubscriber(Subscriber $subscriber) { - $entityManager = ContainerWrapper::getInstance()->get(EntityManager::class); - $userAgentsTable = $entityManager->getClassMetadata(UserAgentEntity::class)->getTableName(); - - return static::tableAlias('clicks') - ->select('clicks.id', 'id') - ->select('newsletter_rendered_subject') - ->select('clicks.created_at', 'created_at') - ->select('url') - ->select('user_agent.user_agent') - ->join( - SendingQueue::$_table, - ['clicks.queue_id', '=', 'queue.id'], - 'queue' - ) - ->join( - NewsletterLink::$_table, - ['clicks.link_id', '=', 'link.id'], - 'link' - ) - ->leftOuterJoin( - $userAgentsTable, - ['clicks.user_agent_id', '=', 'user_agent.id'], - 'user_agent' - ) - ->where('clicks.subscriber_id', $subscriber->id()) - ->orderByAsc('url'); - } - public static function findLatestPerNewsletterBySubscriber(Subscriber $subscriber, DateTimeInterface $from, DateTimeInterface $to) { // subquery to find latest click IDs for each newsletter $table = self::$_table; diff --git a/lib/Models/StatisticsOpens.php b/lib/Models/StatisticsOpens.php index 1cfe3b6d0f..2f6fe2ccd3 100644 --- a/lib/Models/StatisticsOpens.php +++ b/lib/Models/StatisticsOpens.php @@ -2,10 +2,6 @@ namespace MailPoet\Models; -use MailPoet\DI\ContainerWrapper; -use MailPoet\Entities\UserAgentEntity; -use MailPoetVendor\Doctrine\ORM\EntityManager; - /** * @property int $newsletterId * @property int $subscriberId @@ -28,27 +24,4 @@ class StatisticsOpens extends Model { } return $statistics; } - - public static function getAllForSubscriber(Subscriber $subscriber) { - $entityManager = ContainerWrapper::getInstance()->get(EntityManager::class); - $userAgentsTable = $entityManager->getClassMetadata(UserAgentEntity::class)->getTableName(); - - return static::tableAlias('opens') - ->select('opens.id', 'id') - ->select('newsletter_rendered_subject') - ->select('opens.created_at', 'created_at') - ->select('user_agent.user_agent') - ->join( - SendingQueue::$_table, - ['opens.queue_id', '=', 'queue.id'], - 'queue' - ) - ->leftOuterJoin( - $userAgentsTable, - ['opens.user_agent_id', '=', 'user_agent.id'], - 'user_agent' - ) - ->where('opens.subscriber_id', $subscriber->id()) - ->orderByAsc('newsletter_rendered_subject'); - } } diff --git a/lib/Statistics/StatisticsClicksRepository.php b/lib/Statistics/StatisticsClicksRepository.php index 00e186cd9c..97452133cd 100644 --- a/lib/Statistics/StatisticsClicksRepository.php +++ b/lib/Statistics/StatisticsClicksRepository.php @@ -9,6 +9,7 @@ use MailPoet\Entities\SendingQueueEntity; use MailPoet\Entities\StatisticsClickEntity; use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\UserAgentEntity; +use MailPoetVendor\Doctrine\ORM\QueryBuilder; /** * @extends Repository @@ -43,4 +44,16 @@ class StatisticsClicksRepository extends Repository { } return $statistics; } + + public function getAllForSubscriber(SubscriberEntity $subscriber): QueryBuilder { + return $this->entityManager->createQueryBuilder() + ->select('clicks.id id, queue.newsletterRenderedSubject, clicks.createdAt, link.url, userAgent.userAgent') + ->from(StatisticsClickEntity::class, 'clicks') + ->join('clicks.queue', 'queue') + ->join('clicks.link', 'link') + ->leftJoin('clicks.userAgent', 'userAgent') + ->where('clicks.subscriber = :subscriber') + ->orderBy('link.url') + ->setParameter('subscriber', $subscriber->getId()); + } } diff --git a/lib/Statistics/StatisticsOpensRepository.php b/lib/Statistics/StatisticsOpensRepository.php index 8863d093e5..132d517c06 100644 --- a/lib/Statistics/StatisticsOpensRepository.php +++ b/lib/Statistics/StatisticsOpensRepository.php @@ -8,6 +8,7 @@ use MailPoet\Entities\StatisticsNewsletterEntity; use MailPoet\Entities\StatisticsOpenEntity; use MailPoet\Entities\SubscriberEntity; use MailPoetVendor\Carbon\Carbon; +use MailPoetVendor\Doctrine\ORM\QueryBuilder; /** * @extends Repository @@ -86,4 +87,15 @@ class StatisticsOpensRepository extends Repository { ->setParameter('updatedAt', null) ->getQuery()->execute(); } + + public function getAllForSubscriber(SubscriberEntity $subscriber): QueryBuilder { + return $this->entityManager->createQueryBuilder() + ->select('opens.id id, queue.newsletterRenderedSubject, opens.createdAt, userAgent.userAgent') + ->from(StatisticsOpenEntity::class, 'opens') + ->join('opens.queue', 'queue') + ->leftJoin('opens.userAgent', 'userAgent') + ->where('opens.subscriber = :subscriber') + ->orderBy('queue.newsletterRenderedSubject') + ->setParameter('subscriber', $subscriber->getId()); + } } diff --git a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php index 1ba1d7df01..51f1bdc3fb 100644 --- a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php +++ b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporter.php @@ -2,29 +2,29 @@ namespace MailPoet\Subscribers\ImportExport\PersonalDataExporters; -use MailPoet\Models\StatisticsClicks; +use MailPoet\Statistics\StatisticsClicksRepository; use MailPoet\WP\Functions as WPFunctions; class NewsletterClicksExporter extends NewsletterStatsBaseExporter { - protected $statsClass = StatisticsClicks::class; + protected $statsClassName = StatisticsClicksRepository::class; protected function getEmailStats(array $row) { $newsletterData = []; $newsletterData[] = [ 'name' => WPFunctions::get()->__('Email subject', 'mailpoet'), - 'value' => $row['newsletter_rendered_subject'], + 'value' => $row['newsletterRenderedSubject'], ]; $newsletterData[] = [ 'name' => WPFunctions::get()->__('Timestamp of the click event', 'mailpoet'), - 'value' => $row['created_at'], + 'value' => $row['createdAt']->format("Y-m-d H:i:s"), ]; $newsletterData[] = [ 'name' => WPFunctions::get()->__('URL', 'mailpoet'), 'value' => $row['url'], ]; - if (!is_null($row['user_agent'])) { - $userAgent = $row['user_agent']; + if (!is_null($row['userAgent'])) { + $userAgent = $row['userAgent']; } else { $userAgent = WPFunctions::get()->__('Unknown', 'mailpoet'); } diff --git a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporter.php b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporter.php index 8df141d2e4..ac81f74b0f 100644 --- a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporter.php +++ b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporter.php @@ -2,25 +2,25 @@ namespace MailPoet\Subscribers\ImportExport\PersonalDataExporters; -use MailPoet\Models\StatisticsOpens; +use MailPoet\Statistics\StatisticsOpensRepository; use MailPoet\WP\Functions as WPFunctions; class NewsletterOpensExporter extends NewsletterStatsBaseExporter { - protected $statsClass = StatisticsOpens::class; + protected $statsClassName = StatisticsOpensRepository::class; protected function getEmailStats(array $row): array { $newsletterData = []; $newsletterData[] = [ 'name' => WPFunctions::get()->__('Email subject', 'mailpoet'), - 'value' => $row['newsletter_rendered_subject'], + 'value' => $row['newsletterRenderedSubject'], ]; $newsletterData[] = [ 'name' => WPFunctions::get()->__('Timestamp of the open event', 'mailpoet'), - 'value' => $row['created_at'], + 'value' => $row['createdAt']->format("Y-m-d H:i:s"), ]; - if (!is_null($row['user_agent'])) { - $userAgent = $row['user_agent']; + if (!is_null($row['userAgent'])) { + $userAgent = $row['userAgent']; } else { $userAgent = WPFunctions::get()->__('Unknown', 'mailpoet'); } diff --git a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterStatsBaseExporter.php b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterStatsBaseExporter.php index cea36e8db6..92b0f1d812 100644 --- a/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterStatsBaseExporter.php +++ b/lib/Subscribers/ImportExport/PersonalDataExporters/NewsletterStatsBaseExporter.php @@ -2,33 +2,45 @@ namespace MailPoet\Subscribers\ImportExport\PersonalDataExporters; -use MailPoet\Models\Subscriber; +use MailPoet\DI\ContainerWrapper; +use MailPoet\Entities\SubscriberEntity; +use MailPoet\Subscribers\SubscribersRepository; abstract class NewsletterStatsBaseExporter { const LIMIT = 100; - protected $statsClass; + protected $statsClassName; + + protected $subscriberRepository; + + public function __construct(SubscribersRepository $subscribersRepository) { + $this->subscriberRepository = $subscribersRepository; + } + + public function export($email, $page = 1): array { + $data = []; + $subscriber = $this->subscriberRepository->findOneBy(['email' => trim($email)]); + + if ($subscriber instanceof SubscriberEntity) { + $data = $this->getSubscriberData($subscriber, $page); + } - public function export($email, $page = 1) { - $data = $this->getSubscriberData(Subscriber::findOne(trim($email)), $page); return [ 'data' => $data, 'done' => count($data) < self::LIMIT, ]; } - private function getSubscriberData($subscriber, $page) { - if (!$subscriber) { - return []; - } - + private function getSubscriberData(SubscriberEntity $subscriber, $page): array { $result = []; - $statistics = $this->statsClass::getAllForSubscriber($subscriber) - ->limit(self::LIMIT) - ->offset(self::LIMIT * ($page - 1)) - ->findArray(); + $statsClass = ContainerWrapper::getInstance()->get($this->statsClassName); + $statistics = $statsClass->getAllForSubscriber($subscriber) + ->setMaxResults(self::LIMIT) + ->setFirstResult(self::LIMIT * ($page - 1)) + ->getQuery() + ->getResult(); foreach ($statistics as $row) { $result[] = $this->getEmailStats($row); diff --git a/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php b/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php index ece812ecf8..4bf12b83df 100644 --- a/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php +++ b/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterClicksExporterTest.php @@ -20,7 +20,7 @@ class NewsletterClicksExporterTest extends \MailPoetTest { public function _before() { parent::_before(); - $this->exporter = new NewsletterClicksExporter(); + $this->exporter = $this->diContainer->get(NewsletterClicksExporter::class); } public function testExportWorksWhenSubscriberNotFound() { diff --git a/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporterTest.php b/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporterTest.php index 25d7e1f96c..5c2f113add 100644 --- a/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporterTest.php +++ b/tests/integration/Subscribers/ImportExport/PersonalDataExporters/NewsletterOpensExporterTest.php @@ -19,7 +19,7 @@ class NewsletterOpensExporterTest extends \MailPoetTest { public function _before() { parent::_before(); - $this->exporter = new NewsletterOpensExporter(); + $this->exporter = $this->diContainer->get(NewsletterOpensExporter::class); } public function testExportWorksWhenSubscriberNotFound() {