Add scheduling of re-engagement emails
[MAILPOET-3782]
This commit is contained in:
committed by
Veljko V
parent
841ffc1d83
commit
3c5a368c2c
@@ -418,6 +418,16 @@ class NewsletterEntity {
|
|||||||
return $this->newsletterSegments;
|
return $this->newsletterSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getSegmentIds() {
|
||||||
|
return array_filter($this->newsletterSegments->map(function(NewsletterSegmentEntity $newsletterSegment) {
|
||||||
|
$segment = $newsletterSegment->getSegment();
|
||||||
|
return $segment ? (int)$segment->getId() : null;
|
||||||
|
})->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ArrayCollection<int, NewsletterOptionEntity>
|
* @return ArrayCollection<int, NewsletterOptionEntity>
|
||||||
*/
|
*/
|
||||||
|
@@ -7,6 +7,8 @@ use MailPoet\Doctrine\EntityTraits\AutoincrementedIdTrait;
|
|||||||
use MailPoet\Doctrine\EntityTraits\CreatedAtTrait;
|
use MailPoet\Doctrine\EntityTraits\CreatedAtTrait;
|
||||||
use MailPoet\Doctrine\EntityTraits\DeletedAtTrait;
|
use MailPoet\Doctrine\EntityTraits\DeletedAtTrait;
|
||||||
use MailPoet\Doctrine\EntityTraits\UpdatedAtTrait;
|
use MailPoet\Doctrine\EntityTraits\UpdatedAtTrait;
|
||||||
|
use MailPoetVendor\Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use MailPoetVendor\Doctrine\Common\Collections\Collection;
|
||||||
use MailPoetVendor\Doctrine\ORM\Mapping as ORM;
|
use MailPoetVendor\Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,9 +74,14 @@ class ScheduledTaskEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="MailPoet\Entities\ScheduledTaskSubscriberEntity", mappedBy="task", fetch="EXTRA_LAZY")
|
* @ORM\OneToMany(targetEntity="MailPoet\Entities\ScheduledTaskSubscriberEntity", mappedBy="task", fetch="EXTRA_LAZY")
|
||||||
|
* @var Collection<int, ScheduledTaskSubscriberEntity>
|
||||||
*/
|
*/
|
||||||
public $subscribers;
|
public $subscribers;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->subscribers = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
@@ -166,4 +173,11 @@ class ScheduledTaskEntity {
|
|||||||
public function setRescheduleCount(int $rescheduleCount) {
|
public function setRescheduleCount(int $rescheduleCount) {
|
||||||
$this->rescheduleCount = $rescheduleCount;
|
$this->rescheduleCount = $rescheduleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<int, ScheduledTaskSubscriberEntity>
|
||||||
|
*/
|
||||||
|
public function getSubscribers(): Collection {
|
||||||
|
return $this->subscribers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,19 +2,45 @@
|
|||||||
|
|
||||||
namespace MailPoet\Newsletter\Scheduler;
|
namespace MailPoet\Newsletter\Scheduler;
|
||||||
|
|
||||||
|
use MailPoet\Cron\Workers\ReEngagementEmailsScheduler;
|
||||||
use MailPoet\Entities\NewsletterEntity;
|
use MailPoet\Entities\NewsletterEntity;
|
||||||
|
use MailPoet\Entities\NewsletterOptionFieldEntity;
|
||||||
use MailPoet\Entities\ScheduledTaskEntity;
|
use MailPoet\Entities\ScheduledTaskEntity;
|
||||||
|
use MailPoet\Entities\ScheduledTaskSubscriberEntity;
|
||||||
|
use MailPoet\Entities\SendingQueueEntity;
|
||||||
|
use MailPoet\Entities\StatisticsNewsletterEntity;
|
||||||
|
use MailPoet\Entities\SubscriberEntity;
|
||||||
use MailPoet\Newsletter\NewslettersRepository;
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
|
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
||||||
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
use MailPoetVendor\Carbon\Carbon;
|
||||||
|
use MailPoetVendor\Doctrine\DBAL\ParameterType;
|
||||||
|
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||||
|
|
||||||
class ReEngagementScheduler {
|
class ReEngagementScheduler {
|
||||||
|
|
||||||
/** @var NewslettersRepository */
|
/** @var NewslettersRepository */
|
||||||
private $newslettersRepository;
|
private $newslettersRepository;
|
||||||
|
|
||||||
|
/** @var ScheduledTasksRepository */
|
||||||
|
private $scheduledTasksRepository;
|
||||||
|
|
||||||
|
/** @var EntityManager */
|
||||||
|
private $entityManager;
|
||||||
|
|
||||||
|
/** @var WPFunctions */
|
||||||
|
private $wp;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
NewslettersRepository $newslettersRepository
|
NewslettersRepository $newslettersRepository,
|
||||||
|
ScheduledTasksRepository $scheduledTasksRepository,
|
||||||
|
EntityManager $entityManager,
|
||||||
|
WPFunctions $wp
|
||||||
) {
|
) {
|
||||||
$this->newslettersRepository = $newslettersRepository;
|
$this->newslettersRepository = $newslettersRepository;
|
||||||
|
$this->scheduledTasksRepository = $scheduledTasksRepository;
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->wp = $wp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,8 +53,73 @@ class ReEngagementScheduler {
|
|||||||
if (!$emails) {
|
if (!$emails) {
|
||||||
return $scheduled;
|
return $scheduled;
|
||||||
}
|
}
|
||||||
// @todo add creating scheduled task
|
foreach ($emails as $email) {
|
||||||
// @todo fill scheduled tasks subscribers
|
$scheduled[] = $this->scheduleForEmail($email);
|
||||||
return $scheduled;
|
}
|
||||||
|
return array_filter($scheduled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scheduleForEmail(NewsletterEntity $email): ?ScheduledTaskEntity {
|
||||||
|
$scheduledOrRunning = $this->scheduledTasksRepository->findByScheduledAndRunningForNewsletter($email);
|
||||||
|
if ($scheduledOrRunning) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$intervalUnit = $email->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE);
|
||||||
|
$intervalValue = (int)$email->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_NUMBER);
|
||||||
|
if (!$intervalValue || !in_array($intervalUnit, ['weeks', 'months'], true)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!$email->getNewsletterSegments()->count()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$thresholdDate = Carbon::createFromTimestamp($this->wp->currentTime('timestamp'));
|
||||||
|
if ($intervalUnit === 'months') {
|
||||||
|
$thresholdDate->subMonths($intervalValue);
|
||||||
|
} else {
|
||||||
|
$thresholdDate->subWeeks($intervalValue);
|
||||||
|
}
|
||||||
|
// Scheduled task
|
||||||
|
$scheduledTask = new ScheduledTaskEntity();
|
||||||
|
$scheduledTask->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED);
|
||||||
|
$scheduledTask->setScheduledAt(Carbon::createFromTimestamp($this->wp->currentTime('timestamp')));
|
||||||
|
$scheduledTask->setType(ReEngagementEmailsScheduler::TASK_TYPE);
|
||||||
|
$this->scheduledTasksRepository->persist($scheduledTask);
|
||||||
|
|
||||||
|
// Sending queue
|
||||||
|
$sendingQueue = new SendingQueueEntity();
|
||||||
|
$sendingQueue->setTask($scheduledTask);
|
||||||
|
$sendingQueue->setNewsletter($email);
|
||||||
|
$this->scheduledTasksRepository->persist($sendingQueue);
|
||||||
|
$this->scheduledTasksRepository->flush();
|
||||||
|
|
||||||
|
// Parameters for scheduled task subscribers query
|
||||||
|
$taskId = $scheduledTask->getId();
|
||||||
|
$subscribedStatus = SubscriberEntity::STATUS_SUBSCRIBED;
|
||||||
|
$thresholdDateSql = $thresholdDate->toDateTimeString();
|
||||||
|
$newsletterId = $email->getId();
|
||||||
|
$segmentIds = $email->getSegmentIds();
|
||||||
|
$newsletterStatsTable = $this->entityManager->getClassMetadata(StatisticsNewsletterEntity::class)->getTableName();
|
||||||
|
$scheduledTaskSubscribersTable = $this->entityManager->getClassMetadata(ScheduledTaskSubscriberEntity::class)->getTableName();
|
||||||
|
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
|
||||||
|
$nowSql = Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))->toDateTimeString();
|
||||||
|
|
||||||
|
$query = "INSERT IGNORE INTO $scheduledTaskSubscribersTable
|
||||||
|
(subscriber_id, task_id, processed, created_at)
|
||||||
|
SELECT DISTINCT ns.subscriber_id as subscriber_id, :taskId as task_id, 0 as processed, :now as created_at FROM $newsletterStatsTable as ns
|
||||||
|
JOIN $subscribersTable s ON ns.subscriber_id = s.id AND s.deleted_at is NULL AND s.status = :subscribed AND GREATEST(COALESCE(s.created_at, '0'), COALESCE(s.last_subscribed_at, '0'), COALESCE(s.last_engagement_at, '0')) < :thresholdDate
|
||||||
|
JOIN wp_mailpoet_subscriber_segment as ss ON ns.subscriber_id = ss.subscriber_id AND ss.segment_id IN (" . implode(',', $segmentIds) . ") AND ss.status = :subscribed
|
||||||
|
WHERE ns.sent_at > :thresholdDate AND ns.subscriber_id NOT IN (SELECT DISTINCT subscriber_id as id FROM $newsletterStatsTable WHERE newsletter_id = :newsletterId AND sent_at > :thresholdDate);
|
||||||
|
";
|
||||||
|
|
||||||
|
$statement = $this->entityManager->getConnection()->prepare($query);
|
||||||
|
$statement->bindParam('now', $nowSql, ParameterType::STRING);
|
||||||
|
$statement->bindParam('taskId', $taskId, ParameterType::INTEGER);
|
||||||
|
$statement->bindParam('subscribed', $subscribedStatus, ParameterType::STRING);
|
||||||
|
$statement->bindParam('thresholdDate', $thresholdDateSql, ParameterType::STRING);
|
||||||
|
$statement->bindParam('newsletterId', $newsletterId, ParameterType::INTEGER);
|
||||||
|
|
||||||
|
$statement->executeQuery();
|
||||||
|
return $scheduledTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,22 @@ class ScheduledTasksRepository extends Repository {
|
|||||||
->getResult();
|
->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NewsletterEntity $newsletter
|
||||||
|
* @return ScheduledTaskEntity[]
|
||||||
|
*/
|
||||||
|
public function findByScheduledAndRunningForNewsletter(NewsletterEntity $newsletter): array {
|
||||||
|
return $this->doctrineRepository->createQueryBuilder('st')
|
||||||
|
->select('st')
|
||||||
|
->join(SendingQueueEntity::class, 'sq', Join::WITH, 'st = sq.task')
|
||||||
|
->andWhere('st.status = :status OR st.status IS NULL')
|
||||||
|
->andWhere('sq.newsletter = :newsletter')
|
||||||
|
->setParameter('status', NewsletterEntity::STATUS_SCHEDULED)
|
||||||
|
->setParameter('newsletter', $newsletter)
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param NewsletterEntity $newsletter
|
* @param NewsletterEntity $newsletter
|
||||||
* @return ScheduledTaskEntity[]
|
* @return ScheduledTaskEntity[]
|
||||||
|
@@ -2,9 +2,20 @@
|
|||||||
|
|
||||||
namespace MailPoet\Newsletter\Scheduler;
|
namespace MailPoet\Newsletter\Scheduler;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use MailPoet\Entities\NewsletterEntity;
|
use MailPoet\Entities\NewsletterEntity;
|
||||||
use MailPoet\Entities\NewsletterOptionEntity;
|
use MailPoet\Entities\NewsletterOptionEntity;
|
||||||
use MailPoet\Entities\NewsletterOptionFieldEntity;
|
use MailPoet\Entities\NewsletterOptionFieldEntity;
|
||||||
|
use MailPoet\Entities\NewsletterSegmentEntity;
|
||||||
|
use MailPoet\Entities\ScheduledTaskEntity;
|
||||||
|
use MailPoet\Entities\SegmentEntity;
|
||||||
|
use MailPoet\Entities\SendingQueueEntity;
|
||||||
|
use MailPoet\Entities\StatisticsNewsletterEntity;
|
||||||
|
use MailPoet\Entities\SubscriberEntity;
|
||||||
|
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||||
|
use MailPoet\Test\DataFactories\Newsletter;
|
||||||
|
use MailPoet\Test\DataFactories\Segment;
|
||||||
|
use MailPoet\Test\DataFactories\Subscriber;
|
||||||
|
|
||||||
class ReEngagementSchedulerTest extends \MailPoetTest {
|
class ReEngagementSchedulerTest extends \MailPoetTest {
|
||||||
/** @var NewsletterOptionFieldEntity */
|
/** @var NewsletterOptionFieldEntity */
|
||||||
@@ -16,6 +27,12 @@ class ReEngagementSchedulerTest extends \MailPoetTest {
|
|||||||
/** @var ReEngagementScheduler */
|
/** @var ReEngagementScheduler */
|
||||||
private $scheduler;
|
private $scheduler;
|
||||||
|
|
||||||
|
/** @var SegmentEntity */
|
||||||
|
private $segment;
|
||||||
|
|
||||||
|
/** @var NewsletterEntity */
|
||||||
|
private $sentStandardNewsletter;
|
||||||
|
|
||||||
public function _before() {
|
public function _before() {
|
||||||
parent::_before();
|
parent::_before();
|
||||||
$this->cleanup();
|
$this->cleanup();
|
||||||
@@ -28,7 +45,9 @@ class ReEngagementSchedulerTest extends \MailPoetTest {
|
|||||||
$this->afterTimeTypeField->setName(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE);
|
$this->afterTimeTypeField->setName(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE);
|
||||||
$this->afterTimeTypeField->setNewsletterType(NewsletterEntity::TYPE_RE_ENGAGEMENT);
|
$this->afterTimeTypeField->setNewsletterType(NewsletterEntity::TYPE_RE_ENGAGEMENT);
|
||||||
$this->entityManager->persist($this->afterTimeTypeField);
|
$this->entityManager->persist($this->afterTimeTypeField);
|
||||||
$this->entityManager->flush();
|
|
||||||
|
$this->segment = (new Segment())->withName('Re-engagement test')->create();
|
||||||
|
$this->sentStandardNewsletter = (new Newsletter())->withSentStatus()->withSendingQueue()->create();
|
||||||
|
|
||||||
$this->scheduler = $this->diContainer->get(ReEngagementScheduler::class);
|
$this->scheduler = $this->diContainer->get(ReEngagementScheduler::class);
|
||||||
}
|
}
|
||||||
@@ -39,9 +58,73 @@ class ReEngagementSchedulerTest extends \MailPoetTest {
|
|||||||
expect($scheduled)->count(0);
|
expect($scheduled)->count(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItScheduleEmailWithCorrectSubscribers() {
|
||||||
|
$beforeCheckInterval = Carbon::now();
|
||||||
|
$beforeCheckInterval->subMonths(10);
|
||||||
|
$withinCheckInterval = Carbon::now();
|
||||||
|
$withinCheckInterval->subMonth();
|
||||||
|
$reEngagementEmail = $this->createReEngagementEmail(5);
|
||||||
|
|
||||||
|
// SUBSCRIBERS WHO SHOULD RECEIVE THE RE-ENGAGEMENT EMAIL
|
||||||
|
|
||||||
|
// Subscriber who should match all conditions and should and be scheduled
|
||||||
|
$subscriberToBeScheduled = $this->createSubscriber('ok_subscriber@example.com', $beforeCheckInterval, $this->segment);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $subscriberToBeScheduled, $withinCheckInterval);
|
||||||
|
|
||||||
|
// Subscriber who received re-engagement email but in the past
|
||||||
|
$subscriberToBeScheduledWithReEmail = $this->createSubscriber('with_reemail_in_past@example.com', $beforeCheckInterval, $this->segment);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $subscriberToBeScheduledWithReEmail, $withinCheckInterval);
|
||||||
|
$this->addSentEmailToSubscriber($reEngagementEmail, $subscriberToBeScheduledWithReEmail, $beforeCheckInterval);
|
||||||
|
|
||||||
|
// SUBSCRIBERS WHO SHOULD NOT RECEIVE THE RE-ENGAGEMENT EMAIL
|
||||||
|
|
||||||
|
// Subscriber who received re-engagement email within the interval
|
||||||
|
$subscriberWithReEmail = $this->createSubscriber('with_reemail_in_interval@example.com', $beforeCheckInterval, $this->segment);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $subscriberWithReEmail, $withinCheckInterval);
|
||||||
|
$this->addSentEmailToSubscriber($reEngagementEmail, $subscriberWithReEmail, $withinCheckInterval);
|
||||||
|
|
||||||
|
// Subscriber who didn't receive any newsletter within the interval
|
||||||
|
$subscriberWithoutSentEmail = $this->createSubscriber('without_email@example.com', $beforeCheckInterval, $this->segment);
|
||||||
|
|
||||||
|
// Subscriber who is globally subscribed but unsubscribed from the re-engagement email's list
|
||||||
|
$subscriberUnsubscribedFromList = $this->createSubscriber('list_unsubscribed@example.com', $beforeCheckInterval, $this->segment);
|
||||||
|
$this->entityManager->refresh($subscriberUnsubscribedFromList);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $subscriberUnsubscribedFromList, $withinCheckInterval);
|
||||||
|
$subscriberSegment = $subscriberUnsubscribedFromList->getSubscriberSegments()->first();
|
||||||
|
$this->assertInstanceOf(SubscriberSegmentEntity::class, $subscriberSegment);
|
||||||
|
$subscriberSegment->setStatus(SubscriberEntity::STATUS_UNSUBSCRIBED);
|
||||||
|
|
||||||
|
// Subscriber who is not globally subscribed
|
||||||
|
$unsubscribedSubscriber = $this->createSubscriber('global_unsubscribed@example.com', $beforeCheckInterval, $this->segment);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $unsubscribedSubscriber, $withinCheckInterval);
|
||||||
|
$unsubscribedSubscriber->setStatus(SubscriberEntity::STATUS_UNSUBSCRIBED);
|
||||||
|
|
||||||
|
// Subscriber who is not in the list
|
||||||
|
$notInListSubscriber = $this->createSubscriber('without_list@example.com', $beforeCheckInterval, null);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $notInListSubscriber, $withinCheckInterval);
|
||||||
|
|
||||||
|
// Subscriber who engaged recently
|
||||||
|
$subscriberWithoutRecentEngagement = $this->createSubscriber('with_engagement@example.com', $withinCheckInterval, $this->segment);
|
||||||
|
$this->addSentEmailToSubscriber($this->sentStandardNewsletter, $subscriberWithoutRecentEngagement, $withinCheckInterval);
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$task = $this->scheduler->scheduleAll()[0];
|
||||||
|
$this->entityManager->refresh($task);
|
||||||
|
$this->assertInstanceOf(ScheduledTaskEntity::class, $task);
|
||||||
|
expect($task->getStatus())->equals(ScheduledTaskEntity::STATUS_SCHEDULED);
|
||||||
|
expect($task->getType())->equals(Sending::TASK_TYPE);
|
||||||
|
$scheduledAt = $task->getScheduledAt();
|
||||||
|
$this->assertInstanceOf(\DateTimeInterface::class, $scheduledAt);
|
||||||
|
expect($scheduledAt->getTimestamp())->equals(Carbon::now()->getTimestamp(), 1);
|
||||||
|
expect($task->getSubscribers()->count())->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
private function createReEngagementEmail(int $monthsAfter, string $status = NewsletterEntity::STATUS_ACTIVE) {
|
private function createReEngagementEmail(int $monthsAfter, string $status = NewsletterEntity::STATUS_ACTIVE) {
|
||||||
$email = new NewsletterEntity();
|
$email = (new Newsletter())
|
||||||
$email->setSubject("Re-engagement $monthsAfter months");
|
->withSubject("Re-engagement $monthsAfter months")
|
||||||
|
->withSendingQueue()
|
||||||
|
->create();
|
||||||
$email->setType(NewsletterEntity::TYPE_RE_ENGAGEMENT);
|
$email->setType(NewsletterEntity::TYPE_RE_ENGAGEMENT);
|
||||||
$email->setStatus($status);
|
$email->setStatus($status);
|
||||||
$afterTimeType = new NewsletterOptionEntity($email, $this->afterTimeTypeField);
|
$afterTimeType = new NewsletterOptionEntity($email, $this->afterTimeTypeField);
|
||||||
@@ -53,13 +136,51 @@ class ReEngagementSchedulerTest extends \MailPoetTest {
|
|||||||
$this->entityManager->persist($afterTimeNumber);
|
$this->entityManager->persist($afterTimeNumber);
|
||||||
$email->getOptions()->add($afterTimeNumber);
|
$email->getOptions()->add($afterTimeNumber);
|
||||||
$this->entityManager->persist($email);
|
$this->entityManager->persist($email);
|
||||||
|
$emailSegment = new NewsletterSegmentEntity($email, $this->segment);
|
||||||
|
$this->entityManager->persist($emailSegment);
|
||||||
|
$email->getNewsletterSegments()->add($emailSegment);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
return $email;
|
return $email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function addSentEmailToSubscriber(NewsletterEntity $email, SubscriberEntity $subscriber, \DateTimeInterface $sentAt) {
|
||||||
|
$queue = $email->getLatestQueue();
|
||||||
|
$this->assertInstanceOf(SendingQueueEntity::class, $queue);
|
||||||
|
$sentStats = new StatisticsNewsletterEntity($email, $queue, $subscriber);
|
||||||
|
$sentStats->setSentAt($sentAt);
|
||||||
|
$this->entityManager->persist($sentStats);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createSubscriber($email, $lastEngagement, SegmentEntity $segment = null) {
|
||||||
|
$factory = new Subscriber();
|
||||||
|
if ($segment) {
|
||||||
|
$factory = $factory->withSegments([$segment]);
|
||||||
|
}
|
||||||
|
$subscriber = $factory
|
||||||
|
->withStatus(SubscriberEntity::STATUS_SUBSCRIBED)
|
||||||
|
->withEmail($email)
|
||||||
|
->create();
|
||||||
|
$subscriber->setCreatedAt($lastEngagement);
|
||||||
|
$subscriber->setLastEngagementAt($lastEngagement);
|
||||||
|
$subscriber->setLastSubscribedAt($lastEngagement);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
return $subscriber;
|
||||||
|
}
|
||||||
|
|
||||||
private function cleanup() {
|
private function cleanup() {
|
||||||
$this->truncateEntity(NewsletterEntity::class);
|
$this->truncateEntity(NewsletterEntity::class);
|
||||||
$this->truncateEntity(NewsletterOptionFieldEntity::class);
|
$this->truncateEntity(NewsletterOptionFieldEntity::class);
|
||||||
$this->truncateEntity(NewsletterOptionEntity::class);
|
$this->truncateEntity(NewsletterOptionEntity::class);
|
||||||
|
$this->truncateEntity(ScheduledTaskEntity::class);
|
||||||
|
$this->truncateEntity(SubscriberEntity::class);
|
||||||
|
$this->truncateEntity(SegmentEntity::class);
|
||||||
|
$this->truncateEntity(SubscriberSegmentEntity::class);
|
||||||
|
$this->truncateEntity(NewsletterSegmentEntity::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function _after() {
|
||||||
|
parent::_after();
|
||||||
|
$this->cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user