Use doctrine in stats notifications for auto emails

[MAILPOET-2439]
This commit is contained in:
Pavel Dohnal
2019-10-28 12:42:21 +01:00
committed by Jack Kitterhing
parent 5a2edff9fe
commit 95564cfa32
4 changed files with 138 additions and 92 deletions

View File

@ -5,11 +5,14 @@ namespace MailPoet\Cron\Workers\StatsNotifications;
use Carbon\Carbon; use Carbon\Carbon;
use MailPoet\Config\Renderer; use MailPoet\Config\Renderer;
use MailPoet\Cron\Workers\SimpleWorker; use MailPoet\Cron\Workers\SimpleWorker;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Features\FeaturesController; use MailPoet\Features\FeaturesController;
use MailPoet\Mailer\Mailer; use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\MetaInfo; use MailPoet\Mailer\MetaInfo;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Models\ScheduledTask; use MailPoet\Models\ScheduledTask;
use MailPoet\Newsletter\Statistics\NewsletterStatistics;
use MailPoet\Newsletter\Statistics\NewsletterStatisticsRepository;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
use MailPoet\WooCommerce\Helper as WCHelper; use MailPoet\WooCommerce\Helper as WCHelper;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
@ -26,20 +29,24 @@ class AutomatedEmails extends SimpleWorker {
/** @var Renderer */ /** @var Renderer */
private $renderer; private $renderer;
/** @var WCHelper */
private $woocommerce_helper;
/** @var MetaInfo */ /** @var MetaInfo */
private $mailerMetaInfo; private $mailerMetaInfo;
/** @var float */ /** @var float */
public $timer; public $timer;
/** @var StatsNotificationsRepository */
private $repository;
/** @var NewsletterStatisticsRepository */
private $newsletter_statistics_repository;
function __construct( function __construct(
Mailer $mailer, Mailer $mailer,
Renderer $renderer, Renderer $renderer,
SettingsController $settings, SettingsController $settings,
WCHelper $woocommerce_helper, StatsNotificationsRepository $repository,
NewsletterStatisticsRepository $newsletter_statistics_repository,
MetaInfo $mailerMetaInfo, MetaInfo $mailerMetaInfo,
$timer = false $timer = false
) { ) {
@ -47,9 +54,10 @@ class AutomatedEmails extends SimpleWorker {
$this->mailer = $mailer; $this->mailer = $mailer;
$this->settings = $settings; $this->settings = $settings;
$this->renderer = $renderer; $this->renderer = $renderer;
$this->woocommerce_helper = $woocommerce_helper;
$this->mailerMetaInfo = $mailerMetaInfo; $this->mailerMetaInfo = $mailerMetaInfo;
$this->timer = $timer ?: microtime(true); $this->timer = $timer ?: microtime(true);
$this->repository = $repository;
$this->newsletter_statistics_repository = $newsletter_statistics_repository;
} }
function checkProcessingRequirements() { function checkProcessingRequirements() {
@ -107,44 +115,37 @@ class AutomatedEmails extends SimpleWorker {
} }
protected function getNewsletters() { protected function getNewsletters() {
$newsletters = Newsletter
::whereNull('deleted_at')
->whereIn('type', [Newsletter::TYPE_AUTOMATIC, Newsletter::TYPE_WELCOME])
->where('status', Newsletter::STATUS_ACTIVE)
->orderByAsc('subject')
->findMany();
foreach ($newsletters as $newsletter) {
$newsletter
->withSendingQueue()
->withTotalSent()
->withStatistics($this->woocommerce_helper);
}
$result = []; $result = [];
$newsletters = $this->repository->getDueAutomatedNewsletters();
foreach ($newsletters as $newsletter) { foreach ($newsletters as $newsletter) {
if ($newsletter->total_sent) { $statistics = $this->newsletter_statistics_repository->getStatistics($newsletter);
$result[] = $newsletter; if ($statistics->getTotalSentCount()) {
$result[] = [
'statistics' => $statistics,
'newsletter' => $newsletter,
];
} }
} }
return $result; return $result;
} }
/**
* @param Newsletter[] $newsletters
* @return array
*/
private function prepareContext(array $newsletters) { private function prepareContext(array $newsletters) {
$context = [ $context = [
'linkSettings' => WPFunctions::get()->getSiteUrl(null, '/wp-admin/admin.php?page=mailpoet-settings#basics'), 'linkSettings' => WPFunctions::get()->getSiteUrl(null, '/wp-admin/admin.php?page=mailpoet-settings#basics'),
'newsletters' => [], 'newsletters' => [],
]; ];
foreach ($newsletters as $newsletter) { foreach ($newsletters as $row) {
$clicked = ($newsletter->statistics['clicked'] * 100) / $newsletter->total_sent; /** @var NewsletterStatistics $statistics */
$opened = ($newsletter->statistics['opened'] * 100) / $newsletter->total_sent; $statistics = $row['statistics'];
/** @var NewsletterEntity $newsletter */
$newsletter = $row['newsletter'];
$clicked = ($statistics->getClickCount() * 100) / $statistics->getTotalSentCount();
$opened = ($statistics->getOpenCount() * 100) / $statistics->getTotalSentCount();
$context['newsletters'][] = [ $context['newsletters'][] = [
'linkStats' => WPFunctions::get()->getSiteUrl(null, '/wp-admin/admin.php?page=mailpoet-newsletters#/stats/' . $newsletter->id), 'linkStats' => WPFunctions::get()->getSiteUrl(null, '/wp-admin/admin.php?page=mailpoet-newsletters#/stats/' . $newsletter->getId()),
'clicked' => $clicked, 'clicked' => $clicked,
'opened' => $opened, 'opened' => $opened,
'subject' => $newsletter->subject, 'subject' => $newsletter->getSubject(),
]; ];
} }
return $context; return $context;

View File

@ -4,6 +4,7 @@ namespace MailPoet\Cron\Workers\StatsNotifications;
use Carbon\Carbon; use Carbon\Carbon;
use MailPoet\Doctrine\Repository; use MailPoet\Doctrine\Repository;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\ScheduledTaskEntity; use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\StatsNotificationEntity; use MailPoet\Entities\StatsNotificationEntity;
@ -56,5 +57,24 @@ class StatsNotificationsRepository extends Repository {
} }
return $query->getQuery()->getResult(); return $query->getQuery()->getResult();
} }
/**
* @return NewsletterEntity[]
*/
public function getDueAutomatedNewsletters() {
return $this->entity_manager
->createQueryBuilder()
->select('n')
->from(NewsletterEntity::class, 'n')
->where('n.status = :status')
->setParameter(':status', NewsletterEntity::STATUS_ACTIVE)
->andWhere('n.deleted_at is null')
->andWhere('n.type IN (:types)')
->setParameter('types', [NewsletterEntity::TYPE_AUTOMATIC, NewsletterEntity::TYPE_WELCOME])
->orderBy('n.subject')
->getQuery()
->getResult();
}
} }

View File

@ -162,7 +162,15 @@ class WorkersFactory {
/** @return StatsNotificationsWorkerForAutomatedEmails */ /** @return StatsNotificationsWorkerForAutomatedEmails */
function createStatsNotificationsWorkerForAutomatedEmails($timer) { function createStatsNotificationsWorkerForAutomatedEmails($timer) {
return new StatsNotificationsWorkerForAutomatedEmails($this->mailer, $this->renderer, $this->settings, $this->woocommerce_helper, $this->mailerMetaInfo, $timer); return new StatsNotificationsWorkerForAutomatedEmails(
$this->mailer,
$this->renderer,
$this->settings,
$this->stats_notifications_repository,
$this->newsletter_statistics_repository,
$this->mailerMetaInfo,
$timer
);
} }
/** @return SendingServiceKeyCheckWorker */ /** @return SendingServiceKeyCheckWorker */

View File

@ -3,10 +3,15 @@
namespace MailPoet\Cron\Workers\StatsNotifications; namespace MailPoet\Cron\Workers\StatsNotifications;
use MailPoet\Config\Renderer; use MailPoet\Config\Renderer;
use MailPoet\DI\ContainerWrapper;
use MailPoet\Mailer\Mailer; use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\MetaInfo; use MailPoet\Mailer\MetaInfo;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Models\ScheduledTask; use MailPoet\Models\ScheduledTask;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\StatisticsClicks;
use MailPoet\Models\StatisticsOpens;
use MailPoet\Newsletter\Statistics\NewsletterStatisticsRepository;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
use MailPoet\WooCommerce\Helper as WCHelper; use MailPoet\WooCommerce\Helper as WCHelper;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
@ -28,6 +33,7 @@ class AutomatedEmailsTest extends \MailPoetTest {
function _before() { function _before() {
parent::_before(); parent::_before();
\ORM::raw_execute('TRUNCATE ' . ScheduledTask::$_table); \ORM::raw_execute('TRUNCATE ' . ScheduledTask::$_table);
\ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
ScheduledTask::createOrUpdate([ ScheduledTask::createOrUpdate([
'type' => AutomatedEmails::TASK_TYPE, 'type' => AutomatedEmails::TASK_TYPE,
'status' => null, 'status' => null,
@ -37,17 +43,15 @@ class AutomatedEmailsTest extends \MailPoetTest {
$this->mailer = $this->createMock(Mailer::class); $this->mailer = $this->createMock(Mailer::class);
$this->renderer = $this->createMock(Renderer::class); $this->renderer = $this->createMock(Renderer::class);
$this->settings = new SettingsController(); $this->settings = new SettingsController();
$this->stats_notifications = $this->getMockBuilder(AutomatedEmails::class) $this->stats_notifications = new AutomatedEmails(
->enableOriginalConstructor() $this->mailer,
->setConstructorArgs([ $this->renderer,
$this->mailer, $this->settings,
$this->renderer, ContainerWrapper::getInstance()->get(StatsNotificationsRepository::class),
$this->settings, ContainerWrapper::getInstance()->get(NewsletterStatisticsRepository::class),
$this->makeEmpty(WCHelper::class), new MetaInfo
new MetaInfo, );
])
->setMethods(['getNewsletters'])
->getMock();
$this->settings->set(Worker::SETTINGS_KEY, [ $this->settings->set(Worker::SETTINGS_KEY, [
'automated' => true, 'automated' => true,
'address' => 'email@example.com', 'address' => 'email@example.com',
@ -76,15 +80,11 @@ class AutomatedEmailsTest extends \MailPoetTest {
expect($this->stats_notifications->checkProcessingRequirements())->equals(false); expect($this->stats_notifications->checkProcessingRequirements())->equals(false);
} }
function testItDoesntWorkIfEnabled() { function testItDoesWorkIfEnabled() {
expect($this->stats_notifications->checkProcessingRequirements())->equals(true); expect($this->stats_notifications->checkProcessingRequirements())->equals(true);
} }
function testItDoesntRenderIfNoNewslettersFound() { function testItDoesntRenderIfNoNewslettersFound() {
$this->stats_notifications
->expects($this->once())
->method('getNewsletters')
->will($this->returnValue([]));
$this->renderer->expects($this->never()) $this->renderer->expects($this->never())
->method('render'); ->method('render');
$this->mailer->expects($this->never()) $this->mailer->expects($this->never())
@ -96,20 +96,15 @@ class AutomatedEmailsTest extends \MailPoetTest {
} }
function testItRenders() { function testItRenders() {
$newsletter1 = Newsletter::create(); Newsletter::createOrUpdate([
$newsletter1->hydrate([ 'id' => 8763,
'id' => 8765,
'subject' => 'Subject', 'subject' => 'Subject',
'total_sent' => 10, 'type' => 'welcome',
'statistics' => [ 'status' => 'active',
'clicked' => 5,
'opened' => 2,
],
]); ]);
$this->stats_notifications $this->createQueue(8763, 10);
->expects($this->once()) $this->createClicks(8763, 5);
->method('getNewsletters') $this->createOpens(8763, 2);
->will($this->returnValue([$newsletter1]));
$this->renderer->expects($this->exactly(2)) $this->renderer->expects($this->exactly(2))
->method('render'); ->method('render');
$this->renderer->expects($this->at(0)) $this->renderer->expects($this->at(0))
@ -129,20 +124,16 @@ class AutomatedEmailsTest extends \MailPoetTest {
} }
function testItSends() { function testItSends() {
$newsletter1 = Newsletter::create(); Newsletter::createOrUpdate([
$newsletter1->hydrate([ 'id' => 8763,
'id' => 8765,
'subject' => 'Subject', 'subject' => 'Subject',
'total_sent' => 10, 'type' => 'welcome',
'statistics' => [ 'status' => 'active',
'clicked' => 5,
'opened' => 2,
],
]); ]);
$this->stats_notifications $this->createQueue(8763, 10);
->expects($this->once()) $this->createClicks(8763, 5);
->method('getNewsletters') $this->createOpens(8763, 2);
->will($this->returnValue([$newsletter1]));
$this->renderer->expects($this->exactly(2)) $this->renderer->expects($this->exactly(2))
->method('render'); ->method('render');
@ -163,20 +154,15 @@ class AutomatedEmailsTest extends \MailPoetTest {
} }
function testItPreparesContext() { function testItPreparesContext() {
$newsletter1 = Newsletter::create(); Newsletter::createOrUpdate([
$newsletter1->hydrate([ 'id' => 8764,
'id' => 8765,
'subject' => 'Subject', 'subject' => 'Subject',
'total_sent' => 10, 'type' => 'welcome',
'statistics' => [ 'status' => 'active',
'clicked' => 5,
'opened' => 2,
],
]); ]);
$this->stats_notifications $this->createClicks(8764, 5);
->expects($this->once()) $this->createOpens(8764, 2);
->method('getNewsletters') $this->createQueue(8764, 10);
->will($this->returnValue([$newsletter1]));
$this->renderer->expects($this->exactly(2)) // html + text template $this->renderer->expects($this->exactly(2)) // html + text template
->method('render') ->method('render')
->with( ->with(
@ -189,20 +175,16 @@ class AutomatedEmailsTest extends \MailPoetTest {
} }
function testItAddsNewsletterStatsToContext() { function testItAddsNewsletterStatsToContext() {
$newsletter1 = Newsletter::create(); Newsletter::createOrUpdate([
$newsletter1->hydrate([
'id' => 8765, 'id' => 8765,
'subject' => 'Subject', 'subject' => 'Subject',
'total_sent' => 10, 'type' => 'welcome',
'statistics' => [ 'status' => 'active',
'clicked' => 5,
'opened' => 2,
],
]); ]);
$this->stats_notifications $this->createClicks(8765, 5);
->expects($this->once()) $this->createOpens(8765, 2);
->method('getNewsletters') $this->createQueue(8765, 10);
->will($this->returnValue([$newsletter1]));
$this->renderer->expects($this->exactly(2)) // html + text template $this->renderer->expects($this->exactly(2)) // html + text template
->method('render') ->method('render')
->with( ->with(
@ -217,4 +199,39 @@ class AutomatedEmailsTest extends \MailPoetTest {
$this->stats_notifications->process(); $this->stats_notifications->process();
} }
private function createClicks($newsletter_id, $count) {
for ($i = 0; $i < $count; $i++) {
StatisticsClicks::createOrUpdate([
'newsletter_id' => $newsletter_id,
'subscriber_id' => $i + 1,
'queue_id' => 5,
'link_id' => 4,
'count' => 1,
]);
}
}
private function createOpens($newsletter_id, $count) {
for ($i = 0; $i < $count; $i++) {
StatisticsOpens::createOrUpdate([
'newsletter_id' => $newsletter_id,
'subscriber_id' => $i + 1,
'queue_id' => 5,
]);
}
}
private function createQueue($newsletter_id, $count_processed) {
$sending_task = ScheduledTask::createOrUpdate([
'type' => 'sending',
'status' => ScheduledTask::STATUS_COMPLETED,
]);
SendingQueue::createOrUpdate([
'newsletter_rendered_subject' => 'Email Subject',
'task_id' => $sending_task->id,
'newsletter_id' => $newsletter_id,
'count_processed' => $count_processed,
]);
}
} }