Refactor segment filter data to embedded object

[MAILPOET-3177]
This commit is contained in:
Rostislav Wolny
2021-03-03 15:25:29 +01:00
committed by Veljko V
parent bd63ae508f
commit 40c9f047be
18 changed files with 109 additions and 95 deletions

View File

@ -37,7 +37,7 @@ class DynamicSegmentsResponseBuilder {
if (!$filter instanceof DynamicSegmentFilterEntity) {
return $data;
}
return array_merge($data, $filter->getFilterData() ?? []);
return array_merge($data, $filter->getFilterData()->getData() ?? []);
}
public function buildForListing(array $segments): array {

View File

@ -0,0 +1,40 @@
<?php
namespace MailPoet\Entities;
use MailPoetVendor\Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Embeddable()
*/
class DynamicSegmentFilterData {
const TYPE_USER_ROLE = 'userRole';
const TYPE_EMAIL = 'email';
const TYPE_WOOCOMMERCE = 'woocommerce';
/**
* @ORM\Column(type="serialized_array")
* @var array|null
*/
private $filterData;
public function __construct(array $filterData) {
$this->filterData = $filterData;
}
public function getData(): ?array {
return $this->filterData;
}
/**
* @return mixed|null
*/
public function getParam(string $name) {
return $this->filterData[$name] ?? null;
}
public function getFilterType(): ?string {
$filterData = $this->getData();
return $filterData['segmentType'] ?? null;
}
}

View File

@ -18,10 +18,6 @@ class DynamicSegmentFilterEntity {
use UpdatedAtTrait;
use SafeToOneAssociationLoadTrait;
const TYPE_USER_ROLE = 'userRole';
const TYPE_EMAIL = 'email';
const TYPE_WOOCOMMERCE = 'woocommerce';
/**
* @ORM\ManyToOne(targetEntity="MailPoet\Entities\SegmentEntity", inversedBy="filters")
* @var SegmentEntity|null
@ -29,12 +25,12 @@ class DynamicSegmentFilterEntity {
private $segment;
/**
* @ORM\Column(type="serialized_array")
* @var array|null
* @ORM\Embedded(class="MailPoet\Entities\DynamicSegmentFilterData", columnPrefix=false)
* @var DynamicSegmentFilterData
*/
private $filterData;
public function __construct(SegmentEntity $segment, array $filterData) {
public function __construct(SegmentEntity $segment, DynamicSegmentFilterData $filterData) {
$this->segment = $segment;
$this->filterData = $filterData;
}
@ -48,32 +44,13 @@ class DynamicSegmentFilterEntity {
}
/**
* @return array|null
* @return DynamicSegmentFilterData
*/
public function getFilterData() {
return $this->filterData;
}
/**
* @return mixed|null
*/
public function getFilterDataParam(string $name) {
return $this->filterData[$name] ?? null;
}
/**
* @return string|null
*/
public function getSegmentType() {
$filterData = $this->getFilterData();
return $filterData['segmentType'] ?? null;
}
public function setSegment(SegmentEntity $segment) {
$this->segment = $segment;
}
public function setFilterData(array $filterData) {
$this->filterData = $filterData;
}
}

View File

@ -3,7 +3,7 @@
namespace MailPoet\Segments\DynamicSegments;
use MailPoet\DynamicSegments\Exceptions\InvalidSegmentTypeException;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Segments\DynamicSegments\Filters\EmailAction;
use MailPoet\Segments\DynamicSegments\Filters\UserRole;
use MailPoet\Segments\DynamicSegments\Filters\WooCommerceCategory;
@ -35,18 +35,18 @@ class FilterHandler {
$this->wooCommerceCategory = $wooCommerceCategory;
}
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder {
switch ($filterEntity->getSegmentType()) {
case DynamicSegmentFilterEntity::TYPE_USER_ROLE:
return $this->userRole->apply($queryBuilder, $filterEntity);
case DynamicSegmentFilterEntity::TYPE_EMAIL:
return $this->emailAction->apply($queryBuilder, $filterEntity);
case DynamicSegmentFilterEntity::TYPE_WOOCOMMERCE:
$action = $filterEntity->getFilterDataParam('action');
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterData $filter): QueryBuilder {
switch ($filter->getFilterType()) {
case DynamicSegmentFilterData::TYPE_USER_ROLE:
return $this->userRole->apply($queryBuilder, $filter);
case DynamicSegmentFilterData::TYPE_EMAIL:
return $this->emailAction->apply($queryBuilder, $filter);
case DynamicSegmentFilterData::TYPE_WOOCOMMERCE:
$action = $filter->getParam('action');
if ($action === WooCommerceProduct::ACTION_PRODUCT) {
return $this->wooCommerceProduct->apply($queryBuilder, $filterEntity);
return $this->wooCommerceProduct->apply($queryBuilder, $filter);
}
return $this->wooCommerceCategory->apply($queryBuilder, $filterEntity);
return $this->wooCommerceCategory->apply($queryBuilder, $filter);
default:
throw new InvalidSegmentTypeException('Invalid type', InvalidSegmentTypeException::INVALID_TYPE);
}

View File

@ -2,7 +2,7 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\StatisticsClickEntity;
use MailPoet\Entities\StatisticsNewsletterEntity;
use MailPoet\Entities\StatisticsOpenEntity;
@ -23,10 +23,10 @@ class EmailAction implements Filter {
$this->entityManager = $entityManager;
}
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder {
$action = $filterEntity->getFilterDataParam('action');
$newsletterId = (int)$filterEntity->getFilterDataParam('newsletter_id');
$linkId = $filterEntity->getFilterDataParam('link_id') ? (int)$filterEntity->getFilterDataParam('link_id') : null;
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterData $filter): QueryBuilder {
$action = $filter->getParam('action');
$newsletterId = (int)$filter->getParam('newsletter_id');
$linkId = $filter->getParam('link_id') ? (int)$filter->getParam('link_id') : null;
$statsSentTable = $this->entityManager->getClassMetadata(StatisticsNewsletterEntity::class)->getTableName();
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();

View File

@ -2,9 +2,9 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
interface Filter {
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder;
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterData $filter): QueryBuilder;
}

View File

@ -2,7 +2,7 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Segments\DynamicSegments\Exceptions\InvalidFilterException;
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
@ -16,9 +16,9 @@ class UserRole implements Filter {
$this->entityManager = $entityManager;
}
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder {
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterData $filter): QueryBuilder {
global $wpdb;
$role = $filterEntity->getFilterDataParam('wordpressRole');
$role = $filter->getParam('wordpressRole');
if (!$role) {
throw new InvalidFilterException('Missing role', InvalidFilterException::MISSING_ROLE);
}

View File

@ -2,7 +2,7 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
@ -27,9 +27,9 @@ class WooCommerceCategory implements Filter {
$this->wp = $wp;
}
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder {
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterData $filter): QueryBuilder {
global $wpdb;
$categoryId = (int)$filterEntity->getFilterDataParam('category_id');
$categoryId = (int)$filter->getParam('category_id');
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
return $queryBuilder->innerJoin(
$subscribersTable,

View File

@ -2,7 +2,7 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\SubscriberEntity;
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
use MailPoetVendor\Doctrine\ORM\EntityManager;
@ -17,9 +17,9 @@ class WooCommerceProduct implements Filter {
$this->entityManager = $entityManager;
}
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder {
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterData $filter): QueryBuilder {
global $wpdb;
$productId = (int)$filterEntity->getFilterDataParam('product_id');
$productId = (int)$filter->getParam('product_id');
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
return $queryBuilder->innerJoin(
$subscribersTable,

View File

@ -171,7 +171,7 @@ class SegmentSubscribersRepository {
return $queryBuilder->andWhere('0 = 1');
}
foreach ($filters as $filter) {
$queryBuilder = $this->filterHandler->apply($queryBuilder, $filter);
$queryBuilder = $this->filterHandler->apply($queryBuilder, $filter->getFilterData());
}
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
$queryBuilder = $queryBuilder->andWhere("$subscribersTable.deleted_at IS NULL");

View File

@ -335,7 +335,7 @@ class SubscriberListingRepository extends ListingRepository {
) {
// Apply dynamic segments filters
foreach ($segment->getDynamicFilters() as $filter) {
$subscribersQuery = $this->dynamicSegmentsFilter->apply($subscribersQuery, $filter);
$subscribersQuery = $this->dynamicSegmentsFilter->apply($subscribersQuery, $filter->getFilterData());
}
// Apply group, search to fetch only necessary ids
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();

View File

@ -2,6 +2,7 @@
namespace MailPoet\API\JSON\ResponseBuilders;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
@ -27,7 +28,7 @@ class DynamicSegmentsResponseBuilderTest extends \MailPoetTest {
expect($response['name'])->equals($name);
expect($response['description'])->equals($description);
expect($response['type'])->equals(SegmentEntity::TYPE_DYNAMIC);
expect($response['segmentType'])->equals(DynamicSegmentFilterEntity::TYPE_USER_ROLE);
expect($response['segmentType'])->equals(DynamicSegmentFilterData::TYPE_USER_ROLE);
expect($response['wordpressRole'])->equals('editor');
expect($response)->hasKey('created_at');
expect($response)->hasKey('updated_at');
@ -65,10 +66,10 @@ class DynamicSegmentsResponseBuilderTest extends \MailPoetTest {
private function createDynamicSegmentEntity(string $name, string $description): SegmentEntity {
$segment = new SegmentEntity($name, SegmentEntity::TYPE_DYNAMIC, $description);
$dynamicFilter = new DynamicSegmentFilterEntity($segment, [
$dynamicFilter = new DynamicSegmentFilterEntity($segment, new DynamicSegmentFilterData([
'wordpressRole' => 'editor',
'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE,
]);
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
]));
$segment->getDynamicFilters()->add($dynamicFilter);
$this->entityManager->persist($segment);
$this->entityManager->persist($dynamicFilter);

View File

@ -8,6 +8,7 @@ use MailPoet\API\JSON\ResponseBuilders\DynamicSegmentsResponseBuilder;
use MailPoet\DI\ContainerWrapper;
use MailPoet\DynamicSegments\Exceptions\ErrorSavingException;
use MailPoet\DynamicSegments\Exceptions\InvalidSegmentTypeException;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Listing\BulkActionController;
@ -249,10 +250,10 @@ class DynamicSegmentsTest extends \MailPoetTest {
private function createDynamicSegmentEntity(string $name, string $description): SegmentEntity {
$segment = new SegmentEntity($name, SegmentEntity::TYPE_DYNAMIC, $description);
$dynamicFilter = new DynamicSegmentFilterEntity($segment, [
$dynamicFilter = new DynamicSegmentFilterEntity($segment, new DynamicSegmentFilterData([
'wordpressRole' => 'editor',
'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE,
]);
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
]));
$segment->getDynamicFilters()->add($dynamicFilter);
$this->entityManager->persist($segment);
$this->entityManager->persist($dynamicFilter);

View File

@ -2,11 +2,10 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\NewsletterLinkEntity;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\StatisticsClickEntity;
use MailPoet\Entities\StatisticsNewsletterEntity;
@ -178,16 +177,13 @@ class EmailActionTest extends \MailPoetTest {
->from($subscribersTable);
}
private function getSegmentFilter(string $action, int $newsletterId, int $linkId = null): DynamicSegmentFilterEntity {
return new DynamicSegmentFilterEntity(
new SegmentEntity('segment', SegmentEntity::TYPE_DYNAMIC, 'Description'),
[
'segmentType' => DynamicSegmentFilterEntity::TYPE_EMAIL,
'action' => $action,
'newsletter_id' => $newsletterId,
'link_id' => $linkId,
]
);
private function getSegmentFilter(string $action, int $newsletterId, int $linkId = null): DynamicSegmentFilterData {
return new DynamicSegmentFilterData([
'segmentType' => DynamicSegmentFilterData::TYPE_EMAIL,
'action' => $action,
'newsletter_id' => $newsletterId,
'link_id' => $linkId,
]);
}
private function createSubscriber(string $email) {

View File

@ -2,8 +2,7 @@
namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\SubscriberEntity;
class UserRoleTest extends \MailPoetTest {
@ -48,14 +47,11 @@ class UserRoleTest extends \MailPoetTest {
->from($subscribersTable);
}
private function getSegmentFilter(string $role): DynamicSegmentFilterEntity {
return new DynamicSegmentFilterEntity(
new SegmentEntity('segment', SegmentEntity::TYPE_DYNAMIC, 'Description'),
[
'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE,
'wordpressRole' => $role,
]
);
private function getSegmentFilter(string $role): DynamicSegmentFilterData {
return new DynamicSegmentFilterData([
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
'wordpressRole' => $role,
]);
}
public function _after() {

View File

@ -2,6 +2,7 @@
namespace MailPoet\Segments;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
@ -170,10 +171,10 @@ class SegmentSubscribersRepositoryTest extends \MailPoetTest {
private function createDynamicSegmentEntity(): SegmentEntity {
$segment = new SegmentEntity('Segment' . rand(0, 10000), SegmentEntity::TYPE_DYNAMIC, 'Segment description');
$dynamicFilter = new DynamicSegmentFilterEntity($segment, [
$dynamicFilter = new DynamicSegmentFilterEntity($segment, new DynamicSegmentFilterData([
'wordpressRole' => 'editor',
'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE,
]);
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
]));
$segment->getDynamicFilters()->add($dynamicFilter);
$this->entityManager->persist($segment);
$this->entityManager->persist($dynamicFilter);

View File

@ -3,6 +3,7 @@
namespace MailPoet\Segments;
use MailPoet\Config\Populator;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
@ -140,10 +141,10 @@ class SegmentsSimpleListRepositoryTest extends \MailPoetTest {
private function createDynamicSegmentEntityForEditorUsers(): SegmentEntity {
$segment = new SegmentEntity('Segment' . rand(0, 10000), SegmentEntity::TYPE_DYNAMIC, 'Segment description');
$dynamicFilter = new DynamicSegmentFilterEntity($segment, [
$dynamicFilter = new DynamicSegmentFilterEntity($segment, new DynamicSegmentFilterData([
'wordpressRole' => 'editor',
'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE,
]);
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
]));
$segment->getDynamicFilters()->add($dynamicFilter);
$this->entityManager->persist($segment);
$this->entityManager->persist($dynamicFilter);

View File

@ -2,6 +2,7 @@
namespace MailPoet\Subscribers;
use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
@ -289,10 +290,10 @@ class SubscriberListingRepositoryTest extends \MailPoetTest {
private function createDynamicSegmentEntity(): SegmentEntity {
$segment = new SegmentEntity('Segment' . rand(0, 10000), SegmentEntity::TYPE_DYNAMIC, 'Segment description');
$dynamicFilter = new DynamicSegmentFilterEntity($segment, [
$dynamicFilter = new DynamicSegmentFilterEntity($segment, new DynamicSegmentFilterData([
'wordpressRole' => 'editor',
'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE,
]);
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
]));
$segment->getDynamicFilters()->add($dynamicFilter);
$this->entityManager->persist($segment);
$this->entityManager->persist($dynamicFilter);