Add AutomationEmailController
[MAILPOET-5433]
This commit is contained in:
@ -0,0 +1,92 @@
|
|||||||
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace MailPoet\Automation\Integrations\MailPoet\Analytics\Controller;
|
||||||
|
|
||||||
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
|
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction;
|
||||||
|
use MailPoet\Entities\NewsletterEntity;
|
||||||
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
|
|
||||||
|
class AutomationEmailController {
|
||||||
|
|
||||||
|
|
||||||
|
/** @var AutomationStorage */
|
||||||
|
private $automationStorage;
|
||||||
|
|
||||||
|
/** @var NewslettersRepository */
|
||||||
|
private $newslettersRepository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
AutomationStorage $automationStorage,
|
||||||
|
NewslettersRepository $newslettersRepository
|
||||||
|
) {
|
||||||
|
$this->automationStorage = $automationStorage;
|
||||||
|
$this->newslettersRepository = $newslettersRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Automation $automation
|
||||||
|
* @param \DateTimeImmutable $after
|
||||||
|
* @param \DateTimeImmutable $before
|
||||||
|
* @return NewsletterEntity[]
|
||||||
|
*/
|
||||||
|
public function getAutomationEmailsInTimeSpan(Automation $automation, \DateTimeImmutable $after, \DateTimeImmutable $before): array {
|
||||||
|
$automationVersions = $this->automationStorage->getAutomationVersionDates($automation->getId());
|
||||||
|
usort(
|
||||||
|
$automationVersions,
|
||||||
|
function (array $a, array $b) {
|
||||||
|
return $a['created_at'] <=> $b['created_at'];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// filter automations that were created before the after date
|
||||||
|
$versionIds = [];
|
||||||
|
foreach ($automationVersions as $automationVersion) {
|
||||||
|
if ($automationVersion['created_at'] > $before) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!$versionIds || $automationVersion['created_at'] < $after) {
|
||||||
|
$versionIds = [(int)$automationVersion['id']];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$versionIds[] = (int)$automationVersion['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$automations = $this->automationStorage->getAutomationWithDifferentVersions($versionIds);
|
||||||
|
return $this->getEmailsFromAutomations($automations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Automation[] $automations
|
||||||
|
* @return NewsletterEntity[]
|
||||||
|
*/
|
||||||
|
public function getEmailsFromAutomations(array $automations): array {
|
||||||
|
$emailSteps = [];
|
||||||
|
foreach ($automations as $automation) {
|
||||||
|
$emailSteps = array_merge(
|
||||||
|
$emailSteps,
|
||||||
|
array_values(
|
||||||
|
array_filter(
|
||||||
|
$automation->getSteps(),
|
||||||
|
function($step) {
|
||||||
|
return $step->getKey() === SendEmailAction::KEY;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$emailIds = array_unique(
|
||||||
|
array_filter(
|
||||||
|
array_map(
|
||||||
|
function($step) {
|
||||||
|
return $step->getArgs()['email_id'];
|
||||||
|
},
|
||||||
|
$emailSteps
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->newslettersRepository->findBy(['id' => $emailIds]);
|
||||||
|
}
|
||||||
|
}
|
@ -3,10 +3,7 @@
|
|||||||
namespace MailPoet\Automation\Integrations\MailPoet\Analytics\Controller;
|
namespace MailPoet\Automation\Integrations\MailPoet\Analytics\Controller;
|
||||||
|
|
||||||
use MailPoet\Automation\Engine\Data\Automation;
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
|
||||||
use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction;
|
|
||||||
use MailPoet\Automation\Integrations\MailPoet\Analytics\Entities\QueryWithCompare;
|
use MailPoet\Automation\Integrations\MailPoet\Analytics\Entities\QueryWithCompare;
|
||||||
use MailPoet\Entities\NewsletterEntity;
|
|
||||||
use MailPoet\Entities\StatisticsClickEntity;
|
use MailPoet\Entities\StatisticsClickEntity;
|
||||||
use MailPoet\Entities\StatisticsOpenEntity;
|
use MailPoet\Entities\StatisticsOpenEntity;
|
||||||
use MailPoet\Newsletter\NewslettersRepository;
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
@ -24,24 +21,24 @@ class OverviewStatisticsController {
|
|||||||
/** @var NewsletterUrl */
|
/** @var NewsletterUrl */
|
||||||
private $newsletterUrl;
|
private $newsletterUrl;
|
||||||
|
|
||||||
/** @var AutomationStorage */
|
/** @var AutomationEmailController */
|
||||||
private $automationStorage;
|
private $automationEmailController;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
NewslettersRepository $newslettersRepository,
|
NewslettersRepository $newslettersRepository,
|
||||||
NewsletterStatisticsRepository $newsletterStatisticsRepository,
|
NewsletterStatisticsRepository $newsletterStatisticsRepository,
|
||||||
NewsletterUrl $newsletterUrl,
|
NewsletterUrl $newsletterUrl,
|
||||||
AutomationStorage $automationStorage
|
AutomationEmailController $automationEmailController
|
||||||
) {
|
) {
|
||||||
$this->newslettersRepository = $newslettersRepository;
|
$this->newslettersRepository = $newslettersRepository;
|
||||||
$this->newsletterStatisticsRepository = $newsletterStatisticsRepository;
|
$this->newsletterStatisticsRepository = $newsletterStatisticsRepository;
|
||||||
$this->newsletterUrl = $newsletterUrl;
|
$this->newsletterUrl = $newsletterUrl;
|
||||||
$this->automationStorage = $automationStorage;
|
$this->automationEmailController = $automationEmailController;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStatisticsForAutomation(Automation $automation, QueryWithCompare $query): array {
|
public function getStatisticsForAutomation(Automation $automation, QueryWithCompare $query): array {
|
||||||
$currentEmails = $this->getAutomationEmailsInTimeSpan($automation, $query->getAfter(), $query->getBefore());
|
$currentEmails = $this->automationEmailController->getAutomationEmailsInTimeSpan($automation, $query->getAfter(), $query->getBefore());
|
||||||
$previousEmails = $this->getAutomationEmailsInTimeSpan($automation, $query->getCompareWithAfter(), $query->getCompareWithBefore());
|
$previousEmails = $this->automationEmailController->getAutomationEmailsInTimeSpan($automation, $query->getCompareWithAfter(), $query->getCompareWithBefore());
|
||||||
$data = [
|
$data = [
|
||||||
'sent' => ['current' => 0, 'previous' => 0],
|
'sent' => ['current' => 0, 'previous' => 0],
|
||||||
'opened' => ['current' => 0, 'previous' => 0],
|
'opened' => ['current' => 0, 'previous' => 0],
|
||||||
@ -110,64 +107,4 @@ class OverviewStatisticsController {
|
|||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getAutomationEmailsInTimeSpan(Automation $automation, \DateTimeImmutable $after, \DateTimeImmutable $before): array {
|
|
||||||
$automationVersions = $this->automationStorage->getAutomationVersionDates($automation->getId());
|
|
||||||
usort(
|
|
||||||
$automationVersions,
|
|
||||||
function (array $a, array $b) {
|
|
||||||
return $a['created_at'] <=> $b['created_at'];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// filter automations that were created before the after date
|
|
||||||
$versionIds = [];
|
|
||||||
foreach ($automationVersions as $automationVersion) {
|
|
||||||
if ($automationVersion['created_at'] > $before) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!$versionIds || $automationVersion['created_at'] < $after) {
|
|
||||||
$versionIds = [(int)$automationVersion['id']];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$versionIds[] = (int)$automationVersion['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$automations = $this->automationStorage->getAutomationWithDifferentVersions($versionIds);
|
|
||||||
return $this->getEmailsFromAutomations($automations);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Automation[] $automations
|
|
||||||
* @return NewsletterEntity[]
|
|
||||||
*/
|
|
||||||
private function getEmailsFromAutomations(array $automations): array {
|
|
||||||
$emailSteps = [];
|
|
||||||
foreach ($automations as $automation) {
|
|
||||||
$emailSteps = array_merge(
|
|
||||||
$emailSteps,
|
|
||||||
array_values(
|
|
||||||
array_filter(
|
|
||||||
$automation->getSteps(),
|
|
||||||
function($step) {
|
|
||||||
return $step->getKey() === SendEmailAction::KEY;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$emailIds = array_unique(
|
|
||||||
array_filter(
|
|
||||||
array_map(
|
|
||||||
function($step) {
|
|
||||||
return $step->getArgs()['email_id'];
|
|
||||||
},
|
|
||||||
$emailSteps
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->newslettersRepository->findBy(['id' => $emailIds]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -198,6 +198,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
|||||||
//Automation Analytics
|
//Automation Analytics
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Analytics::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Analytics::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Endpoints\OverviewEndpoint::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Endpoints\OverviewEndpoint::class)->setPublic(true);
|
||||||
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Controller\AutomationEmailController::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Controller\OverviewStatisticsController::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Controller\OverviewStatisticsController::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Controller\FreeOrderController::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Controller\FreeOrderController::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Factories\OrderControllerFactory::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Analytics\Factories\OrderControllerFactory::class)->setPublic(true);
|
||||||
|
@ -0,0 +1,176 @@
|
|||||||
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace MailPoet\Test\Automation\Integrations\MailPoet\Analytics\Controller;
|
||||||
|
|
||||||
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
|
use MailPoet\Automation\Engine\Data\NextStep;
|
||||||
|
use MailPoet\Automation\Engine\Data\Step;
|
||||||
|
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Analytics\Controller\AutomationEmailController;
|
||||||
|
use MailPoet\Entities\NewsletterEntity;
|
||||||
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
|
|
||||||
|
class AutomationEmailControllerTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
/** @var AutomationEmailController */
|
||||||
|
private $testee;
|
||||||
|
|
||||||
|
/** @var NewslettersRepository */
|
||||||
|
private $newsletterRepository;
|
||||||
|
|
||||||
|
/** @var AutomationStorage */
|
||||||
|
private $automationStorage;
|
||||||
|
|
||||||
|
public function _before() {
|
||||||
|
$this->testee = $this->diContainer->get(AutomationEmailController::class);
|
||||||
|
$this->newsletterRepository = $this->diContainer->get(NewslettersRepository::class);
|
||||||
|
$this->automationStorage = $this->diContainer->get(AutomationStorage::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItReturnsNoEmailWhenNoEmailStepExist() {
|
||||||
|
$automation = $this->tester->createAutomation('test');
|
||||||
|
$this->createEmail();
|
||||||
|
$emails = $this->testee->getEmailsFromAutomations([$automation]);
|
||||||
|
$this->assertEmpty($emails);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItReturnsEmailsWhenEmailStepsExist() {
|
||||||
|
$newsletter1 = $this->createEmail();
|
||||||
|
$newsletter2 = $this->createEmail();
|
||||||
|
$this->createEmail();
|
||||||
|
|
||||||
|
$trigger = new Step(
|
||||||
|
'trigger',
|
||||||
|
Step::TYPE_TRIGGER,
|
||||||
|
'trigger',
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new NextStep('first-email'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$firstEmail = new Step(
|
||||||
|
'first-email',
|
||||||
|
Step::TYPE_ACTION,
|
||||||
|
SendEmailAction::KEY,
|
||||||
|
['email_id' => $newsletter1->getId()],
|
||||||
|
[
|
||||||
|
new NextStep('second-email'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$secondEmail = new Step(
|
||||||
|
'second-email',
|
||||||
|
Step::TYPE_ACTION,
|
||||||
|
SendEmailAction::KEY,
|
||||||
|
['email_id' => $newsletter2->getId()],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
$automation = $this->tester->createAutomation('test', $trigger, $firstEmail, $secondEmail);
|
||||||
|
|
||||||
|
$emails = $this->testee->getEmailsFromAutomations([$automation]);
|
||||||
|
$this->assertCount(2, $emails);
|
||||||
|
$expectedIds = [$newsletter1->getId(), $newsletter2->getId()];
|
||||||
|
$actualIds = array_map(function (NewsletterEntity $newsletter) {
|
||||||
|
return $newsletter->getId();
|
||||||
|
}, $emails);
|
||||||
|
$this->assertEquals($expectedIds, $actualIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItReturnsTheEmailsFromTheCorrectTimespan() {
|
||||||
|
global $wpdb;
|
||||||
|
$after = new \DateTimeImmutable('2022-01-01 00:00:00');
|
||||||
|
$before = new \DateTimeImmutable('2022-02-02 00:00:00');
|
||||||
|
$automation = $this->tester->createAutomation('test');
|
||||||
|
$emailBefore = $this->createEmail('emailBefore');
|
||||||
|
$emailInTimeSpan = $this->createEmail('emailInTimeSpan');
|
||||||
|
$emailInTimeSpan2 = $this->createEmail('emailInTimeSpan2');
|
||||||
|
$emailAfter = $this->createEmail('emailAfter');
|
||||||
|
|
||||||
|
$root = new Step(
|
||||||
|
'root',
|
||||||
|
Step::TYPE_ROOT,
|
||||||
|
'root',
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new NextStep('trigger'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$trigger = new Step(
|
||||||
|
'trigger',
|
||||||
|
Step::TYPE_TRIGGER,
|
||||||
|
'trigger',
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
new NextStep('first-email'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create versions
|
||||||
|
$emailsCreatedAtMap = [
|
||||||
|
[
|
||||||
|
'email' => $emailBefore,
|
||||||
|
'date' => new \DateTimeImmutable('2021-12-02 00:00:00'),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
/**
|
||||||
|
* This email is in the timespan as it could have been sent in the timespan
|
||||||
|
* although the creation of the version was before the timespan.
|
||||||
|
*/
|
||||||
|
'email' => $emailInTimeSpan,
|
||||||
|
'date' => new \DateTimeImmutable('2021-12-31 00:00:00'),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'email' => $emailInTimeSpan2,
|
||||||
|
'date' => new \DateTimeImmutable('2022-01-03 00:00:00'),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'email' => $emailAfter,
|
||||||
|
'date' => new \DateTimeImmutable('2022-06-02 00:00:00'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
foreach ($emailsCreatedAtMap as $emailCreatedAt) {
|
||||||
|
$email = $emailCreatedAt['email'];
|
||||||
|
|
||||||
|
$emailStep = new Step(
|
||||||
|
'first-email',
|
||||||
|
Step::TYPE_ACTION,
|
||||||
|
SendEmailAction::KEY,
|
||||||
|
['email_id' => $email->getId()],
|
||||||
|
[
|
||||||
|
new NextStep('second-email'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$automation->setSteps([$root, $trigger, $emailStep]);
|
||||||
|
$this->automationStorage->updateAutomation($automation);
|
||||||
|
$automation = $this->automationStorage->getAutomation($automation->getId());
|
||||||
|
$this->assertInstanceOf(Automation::class, $automation);
|
||||||
|
|
||||||
|
// Update the created_at value of the version
|
||||||
|
$sql = 'update ' . $wpdb->prefix . 'mailpoet_automation_versions set created_at=%s where id=%d';
|
||||||
|
$sql = $wpdb->prepare(
|
||||||
|
$sql,
|
||||||
|
$emailCreatedAt['date']->format('Y-m-d H:i:s'),
|
||||||
|
$automation->getVersionId()
|
||||||
|
);
|
||||||
|
$this->assertEquals(1, $wpdb->query($sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
$emails = $this->testee->getAutomationEmailsInTimeSpan($automation, $after, $before);
|
||||||
|
$this->assertCount(2, $emails);
|
||||||
|
$expectedIds = [$emailInTimeSpan->getId(), $emailInTimeSpan2->getId()];
|
||||||
|
$actualIds = array_map(function (NewsletterEntity $newsletter) {
|
||||||
|
return $newsletter->getId();
|
||||||
|
}, $emails);
|
||||||
|
$this->assertEquals($expectedIds, $actualIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createEmail(string $subject = 'subject'): NewsletterEntity {
|
||||||
|
$newsletter = new NewsletterEntity();
|
||||||
|
$newsletter->setType(NewsletterEntity::TYPE_AUTOMATION);
|
||||||
|
$newsletter->setSubject($subject);
|
||||||
|
$newsletter->setStatus(NewsletterEntity::STATUS_DRAFT);
|
||||||
|
$this->newsletterRepository->persist($newsletter);
|
||||||
|
$this->newsletterRepository->flush();
|
||||||
|
return $newsletter;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user