Add test for respository
[MAILPOET-2657]
This commit is contained in:
@ -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),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -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, [
|
||||
|
@ -68,4 +68,11 @@ class SubscriberSegmentEntity {
|
||||
public function getStatus(): string {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
*/
|
||||
public function setStatus(string $status) {
|
||||
$this->status = $status;
|
||||
}
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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']
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user