Add subscriber automation fields
[MAILPOET-5172]
This commit is contained in:
@@ -5,6 +5,7 @@ namespace MailPoet\Automation\Engine\Storage;
|
|||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use MailPoet\Automation\Engine\Data\Automation;
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
use MailPoet\Automation\Engine\Data\Step;
|
use MailPoet\Automation\Engine\Data\Step;
|
||||||
|
use MailPoet\Automation\Engine\Data\Subject;
|
||||||
use MailPoet\Automation\Engine\Exceptions;
|
use MailPoet\Automation\Engine\Exceptions;
|
||||||
use MailPoet\Automation\Engine\Integration\Trigger;
|
use MailPoet\Automation\Engine\Integration\Trigger;
|
||||||
use wpdb;
|
use wpdb;
|
||||||
@@ -22,6 +23,9 @@ class AutomationStorage {
|
|||||||
/** @var string */
|
/** @var string */
|
||||||
private $runsTable;
|
private $runsTable;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $subjectsTable;
|
||||||
|
|
||||||
/** @var wpdb */
|
/** @var wpdb */
|
||||||
private $wpdb;
|
private $wpdb;
|
||||||
|
|
||||||
@@ -31,6 +35,7 @@ class AutomationStorage {
|
|||||||
$this->versionsTable = $wpdb->prefix . 'mailpoet_automation_versions';
|
$this->versionsTable = $wpdb->prefix . 'mailpoet_automation_versions';
|
||||||
$this->triggersTable = $wpdb->prefix . 'mailpoet_automation_triggers';
|
$this->triggersTable = $wpdb->prefix . 'mailpoet_automation_triggers';
|
||||||
$this->runsTable = $wpdb->prefix . 'mailpoet_automation_runs';
|
$this->runsTable = $wpdb->prefix . 'mailpoet_automation_runs';
|
||||||
|
$this->subjectsTable = $wpdb->prefix . 'mailpoet_automation_run_subjects';
|
||||||
$this->wpdb = $wpdb;
|
$this->wpdb = $wpdb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +121,34 @@ class AutomationStorage {
|
|||||||
}, (array)$data);
|
}, (array)$data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Automation[] */
|
||||||
|
public function getAutomationsBySubject(Subject $subject, array $runStatus = null): array {
|
||||||
|
$automationsTable = esc_sql($this->automationsTable);
|
||||||
|
$versionsTable = esc_sql($this->versionsTable);
|
||||||
|
$runsTable = esc_sql($this->runsTable);
|
||||||
|
$subjectTable = esc_sql($this->subjectsTable);
|
||||||
|
|
||||||
|
$statusFilter = $runStatus ? 'AND r.status IN(' . implode(',', array_fill(0, count($runStatus), '%s')) . ')' : '';
|
||||||
|
$query = (string)$this->wpdb->prepare("
|
||||||
|
SELECT DISTINCT a.*, v.id AS version_id, v.steps
|
||||||
|
FROM $automationsTable a
|
||||||
|
INNER JOIN $versionsTable v ON v.automation_id = a.id
|
||||||
|
INNER JOIN $runsTable r ON r.automation_id = a.id
|
||||||
|
INNER JOIN $subjectTable s ON s.automation_run_id = r.id
|
||||||
|
WHERE v.id = (
|
||||||
|
SELECT MAX(id) FROM $versionsTable WHERE automation_id = v.automation_id
|
||||||
|
)
|
||||||
|
AND s.hash = %s
|
||||||
|
$statusFilter
|
||||||
|
ORDER BY a.id DESC
|
||||||
|
", $subject->getHash(), ...($runStatus ?? []));
|
||||||
|
|
||||||
|
$data = $this->wpdb->get_results($query, ARRAY_A);
|
||||||
|
return array_map(function (array $automationData) {
|
||||||
|
return Automation::fromArray($automationData);
|
||||||
|
}, (array)$data);
|
||||||
|
}
|
||||||
|
|
||||||
public function getAutomationCount(): int {
|
public function getAutomationCount(): int {
|
||||||
$automationsTable = esc_sql($this->automationsTable);
|
$automationsTable = esc_sql($this->automationsTable);
|
||||||
return (int)$this->wpdb->get_var("SELECT COUNT(*) FROM $automationsTable");
|
return (int)$this->wpdb->get_var("SELECT COUNT(*) FROM $automationsTable");
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace MailPoet\Automation\Integrations\MailPoet\Fields;
|
||||||
|
|
||||||
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
|
use MailPoet\Automation\Engine\Data\AutomationRun;
|
||||||
|
use MailPoet\Automation\Engine\Data\Field;
|
||||||
|
use MailPoet\Automation\Engine\Data\Subject;
|
||||||
|
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Payloads\SubscriberPayload;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Subjects\SubscriberSubject;
|
||||||
|
|
||||||
|
class SubscriberAutomationFieldsFactory {
|
||||||
|
/** @var AutomationStorage */
|
||||||
|
private $automationStorage;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
AutomationStorage $automationStorage
|
||||||
|
) {
|
||||||
|
$this->automationStorage = $automationStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return Field[] */
|
||||||
|
public function getFields(): array {
|
||||||
|
$automations = $this->automationStorage->getAutomations(
|
||||||
|
array_diff(Automation::STATUS_ALL, [Automation::STATUS_TRASH])
|
||||||
|
);
|
||||||
|
$args = [
|
||||||
|
'options' => array_map(function (Automation $automation) {
|
||||||
|
return [
|
||||||
|
'id' => $automation->getId(),
|
||||||
|
'name' => $automation->getName() . " [{$automation->getId()}]",
|
||||||
|
];
|
||||||
|
}, $automations),
|
||||||
|
];
|
||||||
|
|
||||||
|
return [
|
||||||
|
new Field(
|
||||||
|
'mailpoet:subscriber:automations-entered',
|
||||||
|
Field::TYPE_ENUM_ARRAY,
|
||||||
|
__('Automations — entered', 'mailpoet'),
|
||||||
|
function (SubscriberPayload $payload) {
|
||||||
|
return $this->getAutomationIds($payload);
|
||||||
|
},
|
||||||
|
$args
|
||||||
|
),
|
||||||
|
new Field(
|
||||||
|
'mailpoet:subscriber:automations-processing',
|
||||||
|
Field::TYPE_ENUM_ARRAY,
|
||||||
|
__('Automations — processing', 'mailpoet'),
|
||||||
|
function (SubscriberPayload $payload) {
|
||||||
|
return $this->getAutomationIds($payload, [AutomationRun::STATUS_RUNNING]);
|
||||||
|
},
|
||||||
|
$args
|
||||||
|
),
|
||||||
|
new Field(
|
||||||
|
'mailpoet:subscriber:automations-exited',
|
||||||
|
Field::TYPE_ENUM_ARRAY,
|
||||||
|
__('Automations — exited', 'mailpoet'),
|
||||||
|
function (SubscriberPayload $payload) {
|
||||||
|
return $this->getAutomationIds($payload, [AutomationRun::STATUS_COMPLETE]);
|
||||||
|
},
|
||||||
|
$args
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAutomationIds(SubscriberPayload $payload, array $status = null): array {
|
||||||
|
$subject = new Subject(SubscriberSubject::KEY, ['subscriber_id' => $payload->getId()]);
|
||||||
|
$automations = $this->automationStorage->getAutomationsBySubject($subject, $status);
|
||||||
|
return array_map(function (Automation $automation) {
|
||||||
|
return $automation->getId();
|
||||||
|
}, $automations);
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,9 @@ class SubscriberFieldsFactory {
|
|||||||
/** @var SegmentsRepository */
|
/** @var SegmentsRepository */
|
||||||
private $segmentsRepository;
|
private $segmentsRepository;
|
||||||
|
|
||||||
|
/** @var SubscriberAutomationFieldsFactory */
|
||||||
|
private $automationFieldsFactory;
|
||||||
|
|
||||||
/** @var SubscriberCustomFieldsFactory */
|
/** @var SubscriberCustomFieldsFactory */
|
||||||
private $customFieldsFactory;
|
private $customFieldsFactory;
|
||||||
|
|
||||||
@@ -29,12 +32,14 @@ class SubscriberFieldsFactory {
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
SegmentsFinder $segmentsFinder,
|
SegmentsFinder $segmentsFinder,
|
||||||
SegmentsRepository $segmentsRepository,
|
SegmentsRepository $segmentsRepository,
|
||||||
|
SubscriberAutomationFieldsFactory $automationFieldsFactory,
|
||||||
SubscriberCustomFieldsFactory $customFieldsFactory,
|
SubscriberCustomFieldsFactory $customFieldsFactory,
|
||||||
SubscriberStatisticFieldsFactory $statisticFieldsFactory,
|
SubscriberStatisticFieldsFactory $statisticFieldsFactory,
|
||||||
TagRepository $tagRepository
|
TagRepository $tagRepository
|
||||||
) {
|
) {
|
||||||
$this->segmentsFinder = $segmentsFinder;
|
$this->segmentsFinder = $segmentsFinder;
|
||||||
$this->segmentsRepository = $segmentsRepository;
|
$this->segmentsRepository = $segmentsRepository;
|
||||||
|
$this->automationFieldsFactory = $automationFieldsFactory;
|
||||||
$this->customFieldsFactory = $customFieldsFactory;
|
$this->customFieldsFactory = $customFieldsFactory;
|
||||||
$this->statisticFieldsFactory = $statisticFieldsFactory;
|
$this->statisticFieldsFactory = $statisticFieldsFactory;
|
||||||
$this->tagRepository = $tagRepository;
|
$this->tagRepository = $tagRepository;
|
||||||
@@ -222,7 +227,8 @@ class SubscriberFieldsFactory {
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
$this->statisticFieldsFactory->getFields()
|
$this->statisticFieldsFactory->getFields(),
|
||||||
|
$this->automationFieldsFactory->getFields()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -159,6 +159,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
|||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\ContextFactory::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\ContextFactory::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\MailPoetIntegration::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\MailPoetIntegration::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberFieldsFactory::class)->setPublic(true)->setShared(false);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberFieldsFactory::class)->setPublic(true)->setShared(false);
|
||||||
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberAutomationFieldsFactory::class)->setPublic(true)->setShared(false);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberCustomFieldsFactory::class)->setPublic(true)->setShared(false);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberCustomFieldsFactory::class)->setPublic(true)->setShared(false);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberStatisticFieldsFactory::class)->setPublic(true)->setShared(false);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberStatisticFieldsFactory::class)->setPublic(true)->setShared(false);
|
||||||
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Subjects\SegmentSubject::class)->setPublic(true)->setShared(false);
|
$container->autowire(\MailPoet\Automation\Integrations\MailPoet\Subjects\SegmentSubject::class)->setPublic(true)->setShared(false);
|
||||||
|
@@ -48,7 +48,7 @@ parameters:
|
|||||||
path: ../../lib/Automation/Engine/Storage/AutomationRunStorage.php
|
path: ../../lib/Automation/Engine/Storage/AutomationRunStorage.php
|
||||||
-
|
-
|
||||||
message: "#^Cannot cast string|void to string\\.$#"
|
message: "#^Cannot cast string|void to string\\.$#"
|
||||||
count: 10
|
count: 11
|
||||||
path: ../../lib/Automation/Engine/Storage/AutomationStorage.php
|
path: ../../lib/Automation/Engine/Storage/AutomationStorage.php
|
||||||
-
|
-
|
||||||
message: '/^Call to static method get_orders_table_name\(\) on an unknown class Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\OrdersTableDataStore\.$/'
|
message: '/^Call to static method get_orders_table_name\(\) on an unknown class Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\OrdersTableDataStore\.$/'
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace integration\Automation\Integrations\MailPoet\Fields;
|
||||||
|
|
||||||
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
|
use MailPoet\Automation\Engine\Data\AutomationRun;
|
||||||
|
use MailPoet\Automation\Engine\Data\Subject;
|
||||||
|
use MailPoet\Automation\Engine\Storage\AutomationRunStorage;
|
||||||
|
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Fields\SubscriberAutomationFieldsFactory;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Payloads\SubscriberPayload;
|
||||||
|
use MailPoet\Automation\Integrations\MailPoet\Subjects\SubscriberSubject;
|
||||||
|
use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory;
|
||||||
|
use MailPoetTest;
|
||||||
|
|
||||||
|
class SubscriberAutomationFieldsFactoryTest extends MailPoetTest {
|
||||||
|
public function testItCreatesAutomationFields(): void {
|
||||||
|
$draft = $this->createAutomation('Draft', Automation::STATUS_DRAFT);
|
||||||
|
$active = $this->createAutomation('Active', Automation::STATUS_ACTIVE);
|
||||||
|
$deactivating = $this->createAutomation('Deactivating', Automation::STATUS_DEACTIVATING);
|
||||||
|
$this->createAutomation('Trash', Automation::STATUS_TRASH); // not included
|
||||||
|
|
||||||
|
$fields = $this->getFieldsMap();
|
||||||
|
|
||||||
|
// check definitions
|
||||||
|
$this->assertCount(3, $fields);
|
||||||
|
$expected = [
|
||||||
|
'mailpoet:subscriber:automations-entered' => 'Automations — entered',
|
||||||
|
'mailpoet:subscriber:automations-processing' => 'Automations — processing',
|
||||||
|
'mailpoet:subscriber:automations-exited' => 'Automations — exited',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($expected as $key => $name) {
|
||||||
|
$field = $fields[$key];
|
||||||
|
$this->assertSame($name, $field->getName());
|
||||||
|
$this->assertSame('enum_array', $field->getType());
|
||||||
|
$this->assertSame(['options' => [
|
||||||
|
['id' => $deactivating->getId(), 'name' => "Deactivating [{$deactivating->getId()}]"],
|
||||||
|
['id' => $active->getId(), 'name' => "Active [{$active->getId()}]"],
|
||||||
|
['id' => $draft->getId(), 'name' => "Draft [{$draft->getId()}]"],
|
||||||
|
]], $field->getArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
// check values
|
||||||
|
$subscriber = (new SubscriberFactory())->create();
|
||||||
|
$subject = new Subject(SubscriberSubject::KEY, ['subscriber_id' => $subscriber->getId()]);
|
||||||
|
$this->createAutomationRun($draft, AutomationRun::STATUS_COMPLETE, [$subject]);
|
||||||
|
$this->createAutomationRun($active, AutomationRun::STATUS_CANCELLED, [$subject]);
|
||||||
|
$this->createAutomationRun($active, AutomationRun::STATUS_RUNNING, [$subject]);
|
||||||
|
$this->createAutomationRun($active, AutomationRun::STATUS_COMPLETE, [$subject]);
|
||||||
|
$this->createAutomationRun($deactivating, AutomationRun::STATUS_RUNNING, [$subject]);
|
||||||
|
|
||||||
|
$payload = new SubscriberPayload($subscriber);
|
||||||
|
$entered = $fields['mailpoet:subscriber:automations-entered'];
|
||||||
|
$processing = $fields['mailpoet:subscriber:automations-processing'];
|
||||||
|
$exited = $fields['mailpoet:subscriber:automations-exited'];
|
||||||
|
|
||||||
|
$this->assertSame([$deactivating->getId(), $active->getId(), $draft->getId()], $entered->getValue($payload));
|
||||||
|
$this->assertSame([$deactivating->getId(), $active->getId()], $processing->getValue($payload));
|
||||||
|
$this->assertSame([$active->getId(), $draft->getId()], $exited->getValue($payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFieldsMap(): array {
|
||||||
|
$factory = $this->diContainer->get(SubscriberAutomationFieldsFactory::class);
|
||||||
|
$fields = [];
|
||||||
|
foreach ($factory->getFields() as $field) {
|
||||||
|
$fields[$field->getKey()] = $field;
|
||||||
|
}
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createAutomation(string $name, string $status): Automation {
|
||||||
|
$automation = $this->tester->createAutomation($name);
|
||||||
|
$automation->setStatus($status);
|
||||||
|
$this->diContainer->get(AutomationStorage::class)->updateAutomation($automation);
|
||||||
|
return $automation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createAutomationRun(Automation $automation, string $status, array $subjects): AutomationRun {
|
||||||
|
$run = $this->tester->createAutomationRun($automation, $subjects);
|
||||||
|
$this->diContainer->get(AutomationRunStorage::class)->updateStatus($run->getId(), $status);
|
||||||
|
return $run;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user