Add test for respository

[MAILPOET-2657]
This commit is contained in:
Pavel Dohnal
2020-08-04 13:09:21 +02:00
committed by Veljko V
parent 9f615548b2
commit 33e2c3d9d2
6 changed files with 180 additions and 58 deletions

View File

@ -61,7 +61,7 @@ class SubscribersResponseBuilder {
'last_name' => $subscriber->getLastName(),
'subscriptions' => $this->buildSubscriptions($subscriber),
'status' => $subscriber->getStatus(),
'created_at' => ($createdAt = $subscriber->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
'created_at' => $subscriber->getCreatedAt()->format(self::DATE_FORMAT),
];
}

View File

@ -166,7 +166,7 @@ class Subscribers extends APIEndpoint {
$listingData['filters']['segment'] = $this->wp->applyFilters(
'mailpoet_subscribers_listings_filters_segments',
$listingData['filters']['segment']
$listingData['filters']['segment'] ?? []
);
return $this->successResponse($result, [

View File

@ -68,4 +68,11 @@ class SubscriberSegmentEntity {
public function getStatus(): string {
return $this->status;
}
/**
* @param string $status
*/
public function setStatus(string $status) {
$this->status = $status;
}
}

View File

@ -221,47 +221,6 @@ class Subscriber extends Model {
return $orm;
}
public static function groups($data) {
return [
[
'name' => 'all',
'label' => WPFunctions::get()->__('All', 'mailpoet'),
'count' => self::getPublished()->count(),
],
[
'name' => self::STATUS_SUBSCRIBED,
'label' => WPFunctions::get()->__('Subscribed', 'mailpoet'),
'count' => self::filter(self::STATUS_SUBSCRIBED)->count(),
],
[
'name' => self::STATUS_UNCONFIRMED,
'label' => WPFunctions::get()->__('Unconfirmed', 'mailpoet'),
'count' => self::filter(self::STATUS_UNCONFIRMED)->count(),
],
[
'name' => self::STATUS_UNSUBSCRIBED,
'label' => WPFunctions::get()->__('Unsubscribed', 'mailpoet'),
'count' => self::filter(self::STATUS_UNSUBSCRIBED)->count(),
],
[
'name' => self::STATUS_INACTIVE,
'label' => WPFunctions::get()->__('Inactive', 'mailpoet'),
'count' => self::filter(self::STATUS_INACTIVE)->count(),
],
[
'name' => self::STATUS_BOUNCED,
'label' => WPFunctions::get()->__('Bounced', 'mailpoet'),
'count' => self::filter(self::STATUS_BOUNCED)->count(),
],
[
'name' => 'trash',
'label' => WPFunctions::get()->__('Trash', 'mailpoet'),
'count' => self::getTrashed()->count(),
],
];
}
public static function groupBy($orm, $group = null) {
if ($group === 'trash') {
return $orm->whereNotNull('deleted_at');

View File

@ -19,14 +19,6 @@ class SubscriberListingRepository extends ListingRepository {
SubscriberEntity::STATUS_UNCONFIRMED,
];
/** @var EntityManager */
private $entityManager;
public function __construct(EntityManager $entityManager) {
parent::__construct($entityManager);
$this->entityManager = $entityManager;
}
protected function applySelectClause(QueryBuilder $queryBuilder) {
$queryBuilder->select("PARTIAL s.{id,email,firstName,lastName,status,createdAt}");
}
@ -53,9 +45,11 @@ class SubscriberListingRepository extends ListingRepository {
}
protected function applySearch(QueryBuilder $queryBuilder, string $search) {
$search = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $search); // escape for 'LIKE'
$search = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], trim($search)); // escape for 'LIKE'
$queryBuilder
->andWhere('s.subject LIKE :search')
->andWhere('s.email LIKE :search')
->orWhere('s.firstName LIKE :search')
->orWhere('s.lastName LIKE :search')
->setParameter('search', "%$search%");
}
@ -149,8 +143,8 @@ class SubscriberListingRepository extends ListingRepository {
$queryBuilderNoSegment = clone $queryBuilder;
$subscribersWithoutSegment = $queryBuilderNoSegment
->select('COUNT(s) AS subscribersCount')
->leftJoin('s.subscriberSegments', 'ssg', Join::WITH, $queryBuilderNoSegment->expr()->eq('ssg.status', ':statusSubscribed'))
->leftJoin('ssg.segment', 'sg', Join::WITH, $queryBuilderNoSegment->expr()->isNull('sg.deletedAt'))
->leftJoin('s.subscriberSegments', 'ssg', Join::WITH, (string)$queryBuilderNoSegment->expr()->eq('ssg.status', ':statusSubscribed'))
->leftJoin('ssg.segment', 'sg', Join::WITH, (string)$queryBuilderNoSegment->expr()->isNull('sg.deletedAt'))
->where('deletedAt IS NULL')
->where('sg.id IS NULL')
->setParameter('statusSubscribed', SubscriberEntity::STATUS_SUBSCRIBED)
@ -163,11 +157,15 @@ class SubscriberListingRepository extends ListingRepository {
$queryBuilder
->select('sg.id, sg.name, COUNT(s) AS subscribersCount')
->join('s.subscriberSegments', 'ssg')
->leftJoin('s.subscriberSegments', 'ssg', Join::WITH, (string)$queryBuilderNoSegment->expr()->eq('ssg.status', ':statusSubscribed'))
->join('ssg.segment', 'sg')
->groupBy('sg.id')
->where('sg.deletedAt IS NULL')
->andWhere('s.deletedAt IS NULL')
->andWhere('s.status = :statusSubscribed')
->orderBy('sg.name')
->having('subscribersCount > 0');
->having('subscribersCount > 0')
->setParameter('statusSubscribed', SubscriberEntity::STATUS_SUBSCRIBED);
// format segment list
$segmentList = [
@ -190,5 +188,4 @@ class SubscriberListingRepository extends ListingRepository {
}
return ['segment' => $segmentList];
}
}

View File

@ -0,0 +1,159 @@
<?php declare(strict_types = 1);
namespace MailPoet\Subscribers;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Listing\ListingDefinition;
class SubscriberListingRepositoryTest extends \MailPoetTest {
/** @var SubscriberListingRepository */
private $repository;
private $listingData = [
'params' => [
0 => '',
],
'offset' => 0,
'limit' => 20,
'group' => '',
'search' => '',
'sort_by' => '',
'sort_order' => '',
'selection' => [],
'filter' => [],
];
public function _before() {
$this->repository = new SubscriberListingRepository($this->entityManager);
$this->truncateEntity(SegmentEntity::class);
$this->truncateEntity(SubscriberEntity::class);
$this->truncateEntity(SubscriberSegmentEntity::class);
}
public function testItBuildsFilters() {
$this->createSubscriberEntity(); // subscriber without a list
$subscriberWithDeletedList = $this->createSubscriberEntity();
$deletedList = $this->createSegmentEntity();
$deletedList->setDeletedAt(new \DateTimeImmutable());
$this->createSubscriberSegmentEntity($deletedList, $subscriberWithDeletedList);
$subscriberUnsubscribedFromAList = $this->createSubscriberEntity();
$list = $this->createSegmentEntity();
$subscriberSegment = $this->createSubscriberSegmentEntity($list, $subscriberUnsubscribedFromAList);
$subscriberSegment->setStatus(SubscriberEntity::STATUS_UNSUBSCRIBED);
$deletedSubscriber = $this->createSubscriberEntity();
$deletedSubscriber->setDeletedAt(new \DateTimeImmutable());
$this->createSubscriberSegmentEntity($list, $deletedSubscriber);
$regularSubscriber = $this->createSubscriberEntity();
$regularSubscriber->setStatus(SubscriberEntity::STATUS_SUBSCRIBED);
$this->createSubscriberSegmentEntity($list, $regularSubscriber);
$this->entityManager->flush();
$filters = $this->repository->getFilters($this->getListingDefinition());
expect($filters['segment'])->count(3);
expect($filters['segment'][0]['label'])->equals('All Lists');
expect($filters['segment'][1]['label'])->equals('Subscribers without a list (3)');
expect($filters['segment'][2]['label'])->endsWith('(1)');
}
public function testItBuildsGroups() {
$list = $this->createSegmentEntity();
$this->createSubscriberEntity(); // subscriber without a list
$subscriberUnsubscribedFromAList = $this->createSubscriberEntity();
$subscriberSegment = $this->createSubscriberSegmentEntity($list, $subscriberUnsubscribedFromAList);
$subscriberSegment->setStatus(SubscriberEntity::STATUS_UNSUBSCRIBED);
$regularSubscriber = $this->createSubscriberEntity();
$regularSubscriber->setStatus(SubscriberEntity::STATUS_SUBSCRIBED);
$this->createSubscriberSegmentEntity($list, $regularSubscriber);
$deletedSubscriber = $this->createSubscriberEntity();
$deletedSubscriber->setDeletedAt(new \DateTimeImmutable());
$this->createSubscriberSegmentEntity($list, $deletedSubscriber);
$unsubscribed = $this->createSubscriberEntity();
$unsubscribed->setStatus(SubscriberEntity::STATUS_UNSUBSCRIBED);
$unconfirmed = $this->createSubscriberEntity();
$unconfirmed->setStatus(SubscriberEntity::STATUS_UNCONFIRMED);
$inactive = $this->createSubscriberEntity();
$inactive->setStatus(SubscriberEntity::STATUS_INACTIVE);
$bounced = $this->createSubscriberEntity();
$bounced->setStatus(SubscriberEntity::STATUS_BOUNCED);
$this->entityManager->flush();
$groups = $this->repository->getGroups($this->getListingDefinition());
expect($groups['0']['name'])->equals('all');
expect($groups['0']['count'])->equals(7); // bounced + inactive + unconfirmed + unsubscribed + regular + unsub from a list + without a list
expect($groups['1']['name'])->equals('subscribed');
expect($groups['1']['count'])->equals(3);// without a list + unsub form a list + regular
expect($groups['2']['name'])->equals('unconfirmed');
expect($groups['2']['count'])->equals(1);
expect($groups['3']['name'])->equals('unsubscribed');
expect($groups['3']['count'])->equals(1);
expect($groups['4']['name'])->equals('inactive');
expect($groups['4']['count'])->equals(1);
expect($groups['5']['name'])->equals('bounced');
expect($groups['5']['count'])->equals(1);
expect($groups['6']['name'])->equals('trash');
expect($groups['6']['count'])->equals(1);
}
private function createSubscriberEntity(): SubscriberEntity {
$subscriber = new SubscriberEntity();
$rand = rand(0, 100000);
$subscriber->setEmail("john{$rand}@mailpoet.com");
$subscriber->setFirstName('John');
$subscriber->setLastName('Doe');
$subscriber->setStatus(SubscriberEntity::STATUS_SUBSCRIBED);
$subscriber->setSource(Source::API);
$this->entityManager->persist($subscriber);
return $subscriber;
}
private function createSegmentEntity(): SegmentEntity {
$segment = new SegmentEntity();
$segment->setName('Segment' . rand(0, 10000));
$segment->setType(SegmentEntity::TYPE_DEFAULT);
$segment->setDescription('Segment description');
$this->entityManager->persist($segment);
return $segment;
}
private function createSubscriberSegmentEntity(SegmentEntity $segment, SubscriberEntity $subscriber): SubscriberSegmentEntity {
$subscriberSegment = new SubscriberSegmentEntity($segment, $subscriber, SubscriberEntity::STATUS_SUBSCRIBED);
$this->entityManager->persist($subscriberSegment);
return $subscriberSegment;
}
private function getListingDefinition(): ListingDefinition {
return new ListingDefinition(
$this->listingData['group'],
$this->listingData['filter'],
$this->listingData['search'],
$this->listingData['params'],
$this->listingData['sort_by'],
$this->listingData['sort_order'],
$this->listingData['offset'],
$this->listingData['limit'],
$this->listingData['selection']
);
}
}