Fix code using the combined segments

[MAILPOET-3212]
This commit is contained in:
Pavel Dohnal
2021-03-16 13:14:41 +01:00
committed by Veljko V
parent 5b45bdac1e
commit ce48153b12
7 changed files with 56 additions and 26 deletions

View File

@ -75,14 +75,23 @@ class FilterHandler {
if (!isset($data['connect']) || $data['connect'] === 'or') { if (!isset($data['connect']) || $data['connect'] === 'or') {
// the final query: SELECT * FROM subscribers INNER JOIN (filter_select1 UNION filter_select2) filtered_subscribers ON filtered_subscribers.inner_subscriber_id = id // the final query: SELECT * FROM subscribers INNER JOIN (filter_select1 UNION filter_select2) filtered_subscribers ON filtered_subscribers.inner_subscriber_id = id
$queryBuilder->innerJoin($subscribersTable, sprintf('(%s)', join(' UNION ', $subQueries)), 'filtered_subscribers', 'filtered_subscribers.inner_subscriber_id = id'); $queryBuilder->innerJoin(
$subscribersTable,
sprintf('(%s)', join(' UNION ', $subQueries)),
'filtered_subscribers',
"filtered_subscribers.inner_subscriber_id = $subscribersTable.id"
);
return $queryBuilder; return $queryBuilder;
} }
foreach ($subQueries as $subQuery) { foreach ($subQueries as $subQuery) {
// we need a unique name for each subquery so that we can join them together in the sql query - just make sure the identifier starts with a letter, not a number // we need a unique name for each subquery so that we can join them together in the sql query - just make sure the identifier starts with a letter, not a number
$subqueryName = 'a' . Security::generateRandomString(5); $subqueryName = 'a' . Security::generateRandomString(5);
$queryBuilder->innerJoin($subscribersTable, "($subQuery)", $subqueryName, "$subqueryName.inner_subscriber_id = id"); $queryBuilder->innerJoin(
$subscribersTable,
"($subQuery)",
$subqueryName,
"$subqueryName.inner_subscriber_id = $subscribersTable.id");
} }
return $queryBuilder; return $queryBuilder;
} }

View File

@ -189,9 +189,8 @@ class SegmentSubscribersRepository {
// For BC compatibility fetching an empty result // For BC compatibility fetching an empty result
if (count($filters) === 0) { if (count($filters) === 0) {
return $queryBuilder->andWhere('0 = 1'); return $queryBuilder->andWhere('0 = 1');
} } elseif ($segment instanceof SegmentEntity) {
foreach ($filters as $filter) { $queryBuilder = $this->filterHandler->apply($queryBuilder, $segment);
$queryBuilder = $this->filterHandler->apply($queryBuilder, $filter);
} }
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName(); $subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
$queryBuilder = $queryBuilder->andWhere("$subscribersTable.deleted_at IS NULL"); $queryBuilder = $queryBuilder->andWhere("$subscribersTable.deleted_at IS NULL");

View File

@ -185,10 +185,7 @@ class ImportExportRepository {
// So we need to use a placeholder // So we need to use a placeholder
$qb->addSelect(":segmentName AS segment_name") $qb->addSelect(":segmentName AS segment_name")
->setParameter('segmentName', $segment->getName()); ->setParameter('segmentName', $segment->getName());
$filters = $segment->getDynamicFilters(); $qb = $this->filterHandler->apply($qb, $segment);
foreach ($filters as $filter) {
$qb = $this->filterHandler->apply($qb, $filter->getFilterData());
}
} }
$statement = $qb->execute(); $statement = $qb->execute();

View File

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

View File

@ -12,6 +12,7 @@ use MailPoet\Entities\StatisticsOpenEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Segments\DynamicSegments\Filters\EmailAction; use MailPoet\Segments\DynamicSegments\Filters\EmailAction;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoetVendor\Doctrine\DBAL\Driver\Statement;
class FilterHandlerTest extends \MailPoetTest { class FilterHandlerTest extends \MailPoetTest {
@ -46,17 +47,24 @@ class FilterHandlerTest extends \MailPoetTest {
// fetch entities // fetch entities
/** @var SubscribersRepository $subscribersRepository */ /** @var SubscribersRepository $subscribersRepository */
$subscribersRepository = $this->diContainer->get(SubscribersRepository::class); $subscribersRepository = $this->diContainer->get(SubscribersRepository::class);
$this->subscriber1 = $subscribersRepository->findOneBy(['email' => 'user-role-test1@example.com']); $subscriber1 = $subscribersRepository->findOneBy(['email' => 'user-role-test1@example.com']);
$this->subscriber2 = $subscribersRepository->findOneBy(['email' => 'user-role-test2@example.com']); assert($subscriber1 instanceof SubscriberEntity);
$this->subscriber1 = $subscriber1;
$subscriber2 = $subscribersRepository->findOneBy(['email' => 'user-role-test2@example.com']);
assert($subscriber2 instanceof SubscriberEntity);
$this->subscriber2 = $subscriber2;
} }
public function testItAppliesFilter() { public function testItAppliesFilter() {
$segment = $this->getSegment('editor'); $segment = $this->getSegment('editor');
$queryBuilder = $this->filterHandler->apply($this->getQueryBuilder(), $segment); $statement = $this->filterHandler->apply($this->getQueryBuilder(), $segment)->execute();
$result = $queryBuilder->execute()->fetchAll(); assert($statement instanceof Statement);
$result = $statement->fetchAll();
expect($result)->count(2); expect($result)->count(2);
$subscriber1 = $this->entityManager->find(SubscriberEntity::class, $result[0]['id']); $subscriber1 = $this->entityManager->find(SubscriberEntity::class, $result[0]['id']);
assert($subscriber1 instanceof SubscriberEntity);
$subscriber2 = $this->entityManager->find(SubscriberEntity::class, $result[1]['id']); $subscriber2 = $this->entityManager->find(SubscriberEntity::class, $result[1]['id']);
assert($subscriber2 instanceof SubscriberEntity);
expect($subscriber1->getEmail())->equals('user-role-test1@example.com'); expect($subscriber1->getEmail())->equals('user-role-test1@example.com');
expect($subscriber2->getEmail())->equals('user-role-test3@example.com'); expect($subscriber2->getEmail())->equals('user-role-test3@example.com');
} }
@ -71,8 +79,9 @@ class FilterHandlerTest extends \MailPoetTest {
$this->entityManager->persist($dynamicSegmentFilter); $this->entityManager->persist($dynamicSegmentFilter);
$segment->addDynamicFilter($dynamicSegmentFilter); $segment->addDynamicFilter($dynamicSegmentFilter);
$this->entityManager->flush(); $this->entityManager->flush();
$queryBuilder = $this->filterHandler->apply($this->getQueryBuilder(), $segment); $statement = $this->filterHandler->apply($this->getQueryBuilder(), $segment)->execute();
$result = $queryBuilder->execute()->fetchAll(); assert($statement instanceof Statement);
$result = $statement->fetchAll();
expect($result)->count(3); expect($result)->count(3);
} }
@ -96,8 +105,9 @@ class FilterHandlerTest extends \MailPoetTest {
$this->entityManager->persist($dynamicSegmentFilter); $this->entityManager->persist($dynamicSegmentFilter);
$segment->addDynamicFilter($dynamicSegmentFilter); $segment->addDynamicFilter($dynamicSegmentFilter);
$this->entityManager->flush(); $this->entityManager->flush();
$queryBuilder = $this->filterHandler->apply($this->getQueryBuilder(), $segment); $statement = $this->filterHandler->apply($this->getQueryBuilder(), $segment)->execute();
$result = $queryBuilder->execute()->fetchAll(); assert($statement instanceof Statement);
$result = $statement->fetchAll();
expect($result)->count(3); expect($result)->count(3);
} }
@ -143,8 +153,9 @@ class FilterHandlerTest extends \MailPoetTest {
$segment->addDynamicFilter($filterOpened); $segment->addDynamicFilter($filterOpened);
$this->entityManager->flush(); $this->entityManager->flush();
$queryBuilder = $this->filterHandler->apply($this->getQueryBuilder(), $segment); $statement = $this->filterHandler->apply($this->getQueryBuilder(), $segment)->execute();
$result = $queryBuilder->execute()->fetchAll(); assert($statement instanceof Statement);
$result = $statement->fetchAll();
expect($result)->count(1); expect($result)->count(1);
} }

View File

@ -3,9 +3,11 @@
namespace MailPoet\Segments\DynamicSegments\Filters; namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterData; use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\NewsletterEntity; use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\NewsletterLinkEntity; use MailPoet\Entities\NewsletterLinkEntity;
use MailPoet\Entities\ScheduledTaskEntity; use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SendingQueueEntity; use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\StatisticsClickEntity; use MailPoet\Entities\StatisticsClickEntity;
use MailPoet\Entities\StatisticsNewsletterEntity; use MailPoet\Entities\StatisticsNewsletterEntity;
@ -177,13 +179,19 @@ class EmailActionTest extends \MailPoetTest {
->from($subscribersTable); ->from($subscribersTable);
} }
private function getSegmentFilter(string $action, int $newsletterId, int $linkId = null): DynamicSegmentFilterData { private function getSegmentFilter(string $action, int $newsletterId, int $linkId = null): DynamicSegmentFilterEntity {
return new DynamicSegmentFilterData([ $segmentFilterData = new DynamicSegmentFilterData([
'segmentType' => DynamicSegmentFilterData::TYPE_EMAIL, 'segmentType' => DynamicSegmentFilterData::TYPE_EMAIL,
'action' => $action, 'action' => $action,
'newsletter_id' => $newsletterId, 'newsletter_id' => $newsletterId,
'link_id' => $linkId, 'link_id' => $linkId,
]); ]);
$segment = new SegmentEntity('Dynamic Segment', SegmentEntity::TYPE_DYNAMIC, 'description');
$this->entityManager->persist($segment);
$dynamicSegmentFilter = new DynamicSegmentFilterEntity($segment, $segmentFilterData);
$this->entityManager->persist($dynamicSegmentFilter);
$segment->addDynamicFilter($dynamicSegmentFilter);
return $dynamicSegmentFilter;
} }
private function createSubscriber(string $email) { private function createSubscriber(string $email) {

View File

@ -3,6 +3,8 @@
namespace MailPoet\Segments\DynamicSegments\Filters; namespace MailPoet\Segments\DynamicSegments\Filters;
use MailPoet\Entities\DynamicSegmentFilterData; use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
class UserRoleTest extends \MailPoetTest { class UserRoleTest extends \MailPoetTest {
@ -47,11 +49,17 @@ class UserRoleTest extends \MailPoetTest {
->from($subscribersTable); ->from($subscribersTable);
} }
private function getSegmentFilter(string $role): DynamicSegmentFilterData { private function getSegmentFilter(string $role): DynamicSegmentFilterEntity {
return new DynamicSegmentFilterData([ $data = new DynamicSegmentFilterData([
'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE, 'segmentType' => DynamicSegmentFilterData::TYPE_USER_ROLE,
'wordpressRole' => $role, 'wordpressRole' => $role,
]); ]);
$segment = new SegmentEntity('Dynamic Segment', SegmentEntity::TYPE_DYNAMIC, 'description');
$this->entityManager->persist($segment);
$dynamicSegmentFilter = new DynamicSegmentFilterEntity($segment, $data);
$this->entityManager->persist($dynamicSegmentFilter);
$segment->addDynamicFilter($dynamicSegmentFilter);
return $dynamicSegmentFilter;
} }
public function _after() { public function _after() {