Files
piratepoet/mailpoet/tests/integration/Subscribers/SubscribersRepositoryTest.php
2024-02-12 15:33:28 +01:00

467 lines
20 KiB
PHP

<?php declare(strict_types = 1);
namespace MailPoet\Subscribers;
use DateTimeImmutable;
use DateTimeInterface;
use MailPoet\Entities\CustomFieldEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberCustomFieldEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Segments\SegmentsRepository;
class SubscribersRepositoryTest extends \MailPoetTest {
/** @var SubscribersRepository */
private $repository;
/** @var SegmentsRepository */
private $segmentRepository;
/** @var SubscriberSegmentRepository */
private $subscriberSegmentRepository;
/** @var SubscriberCustomFieldRepository */
private $subscriberCustomFieldRepository;
public function _before() {
parent::_before();
$this->repository = $this->diContainer->get(SubscribersRepository::class);
$this->segmentRepository = $this->diContainer->get(SegmentsRepository::class);
$this->subscriberSegmentRepository = $this->diContainer->get(SubscriberSegmentRepository::class);
$this->subscriberCustomFieldRepository = $this->diContainer->get(SubscriberCustomFieldRepository::class);
}
public function testItBulkTrashSubscribers(): void {
$subscriberOne = $this->createSubscriber('one@trash.com');
$subscriberTwo = $this->createSubscriber('two@trash.com');
$subscriberThree = $this->createSubscriber('three@trash.com');
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$subscriberThreeId = $subscriberThree->getId();
$this->repository->bulkTrash([
$subscriberOneId,
$subscriberTwoId,
]);
$this->entityManager->clear();
// trashed subscriber
$subscriberOne = $this->repository->findOneById($subscriberOneId);
$this->assertInstanceOf(SubscriberEntity::class, $subscriberOne);
verify($subscriberOne->getDeletedAt())->notNull();
$subscriberTwo = $this->repository->findOneById($subscriberOneId);
$this->assertInstanceOf(SubscriberEntity::class, $subscriberTwo);
verify($subscriberTwo->getDeletedAt())->notNull();
// don't trashed subscriber
$subscriberThree = $this->repository->findOneById($subscriberThreeId);
$this->assertInstanceOf(SubscriberEntity::class, $subscriberThree);
verify($subscriberThree->getDeletedAt())->null();
}
public function testItBulkRestoreTrashedSubscribers(): void {
$subscriberOne = $this->createSubscriber('one@restore.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@restore.com', new DateTimeImmutable());
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$this->repository->bulkRestore([
$subscriberOneId,
]);
$this->entityManager->clear();
// restored subscriber
$subscriberOne = $this->repository->findOneById($subscriberOneId);
$this->assertInstanceOf(SubscriberEntity::class, $subscriberOne);
verify($subscriberOne->getDeletedAt())->null();
// don't restored subscriber
$subscriberTwo = $this->repository->findOneById($subscriberTwoId);
$this->assertInstanceOf(SubscriberEntity::class, $subscriberTwo);
verify($subscriberTwo->getDeletedAt())->notNull();
}
public function testItBulkUpdatesLastSendingAt(): void {
$subscriberOne = $this->createSubscriber('one@e.com');
$subscriberTwo = $this->createSubscriber('two@e.com');
$subscriberThree = $this->createSubscriber('three@e.com');
verify($subscriberOne->getLastSendingAt())->null();
verify($subscriberTwo->getLastSendingAt())->null();
verify($subscriberThree->getLastSendingAt())->null();
$idsToUpdate = [
$subscriberOne->getId(),
$subscriberThree->getId(),
];
$now = new DateTimeImmutable();
$this->repository->bulkUpdateLastSendingAt($idsToUpdate, $now);
$this->repository->refresh($subscriberOne);
$this->repository->refresh($subscriberTwo);
$this->repository->refresh($subscriberThree);
$this->assertInstanceOf(DateTimeInterface::class, $subscriberOne->getLastSendingAt());
verify($subscriberOne->getLastSendingAt()->getTimestamp())->equals($now->getTimestamp());
verify($subscriberTwo->getLastSendingAt())->null();
$this->assertInstanceOf(DateTimeInterface::class, $subscriberThree->getLastSendingAt());
verify($subscriberThree->getLastSendingAt()->getTimestamp())->equals($now->getTimestamp());
}
public function testItBulkUpdatesEngagementScoreUpdatedAt(): void {
$subscriberOne = $this->createSubscriber('one@e.com');
$subscriberTwo = $this->createSubscriber('two@e.com');
$subscriberThree = $this->createSubscriber('three@e.com');
verify($subscriberOne->getEngagementScoreUpdatedAt())->null();
verify($subscriberTwo->getEngagementScoreUpdatedAt())->null();
verify($subscriberThree->getEngagementScoreUpdatedAt())->null();
$idsToUpdate = [
$subscriberOne->getId(),
$subscriberThree->getId(),
];
$now = new DateTimeImmutable();
$this->repository->bulkUpdateEngagementScoreUpdatedAt($idsToUpdate, $now);
$this->repository->refresh($subscriberOne);
$this->repository->refresh($subscriberTwo);
$this->repository->refresh($subscriberThree);
$this->assertInstanceOf(DateTimeInterface::class, $subscriberOne->getEngagementScoreUpdatedAt());
verify($subscriberOne->getEngagementScoreUpdatedAt()->getTimestamp())->equals($now->getTimestamp());
verify($subscriberTwo->getEngagementScoreUpdatedAt())->null();
$this->assertInstanceOf(DateTimeInterface::class, $subscriberThree->getEngagementScoreUpdatedAt());
verify($subscriberThree->getEngagementScoreUpdatedAt()->getTimestamp())->equals($now->getTimestamp());
}
public function testBulkUpdatesOfEngagementScoreCanNullifyData(): void {
$subscriberOne = $this->createSubscriber('one@e.com');
$subscriberTwo = $this->createSubscriber('two@e.com');
$subscriberThree = $this->createSubscriber('three@e.com');
$now = new DateTimeImmutable();
$subscriberOne->setEngagementScoreUpdatedAt($now);
$subscriberTwo->setEngagementScoreUpdatedAt($now);
$subscriberThree->setEngagementScoreUpdatedAt($now);
$this->entityManager->persist($subscriberOne);
$this->entityManager->persist($subscriberTwo);
$this->entityManager->persist($subscriberThree);
$this->entityManager->flush();
$this->repository->refresh($subscriberOne);
$this->repository->refresh($subscriberTwo);
$this->repository->refresh($subscriberThree);
$this->assertInstanceOf(DateTimeInterface::class, $subscriberOne->getEngagementScoreUpdatedAt());
$this->assertInstanceOf(DateTimeInterface::class, $subscriberTwo->getEngagementScoreUpdatedAt());
$this->assertInstanceOf(DateTimeInterface::class, $subscriberThree->getEngagementScoreUpdatedAt());
$idsToUpdate = [
$subscriberOne->getId(),
$subscriberThree->getId(),
];
$this->repository->bulkUpdateEngagementScoreUpdatedAt($idsToUpdate, null);
$this->repository->refresh($subscriberOne);
$this->repository->refresh($subscriberTwo);
$this->repository->refresh($subscriberThree);
verify($subscriberOne->getEngagementScoreUpdatedAt())->null();
$this->assertInstanceOf(DateTimeInterface::class, $subscriberTwo->getEngagementScoreUpdatedAt());
verify($subscriberOne->getEngagementScoreUpdatedAt())->null();
}
public function testItBulkDeleteSubscribers(): void {
$subscriberOne = $this->createSubscriber('one@delete.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@delete.com', new DateTimeImmutable());
$segmentOne = $this->segmentRepository->createOrUpdate('One Delete');
$this->createSubscriberSegment($segmentOne, $subscriberOne);
$this->createSubscriberSegment($segmentOne, $subscriberTwo);
$customField = $this->createCustomField('CF');
$this->createSubscriberCustomField($subscriberOne, $customField);
$this->createSubscriberCustomField($subscriberTwo, $customField);
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$this->repository->bulkDelete([
$subscriberOneId,
]);
$this->entityManager->clear();
// deleted subscriber
verify($this->repository->findOneById($subscriberOneId))->null();
verify($this->subscriberSegmentRepository->findOneBy(['subscriber' => $subscriberOneId]))->null();
verify($this->subscriberCustomFieldRepository->findOneBy(['subscriber' => $subscriberOneId]))->null();
// don't restored subscriber
$subscriberTwo = $this->repository->findOneById($subscriberTwoId);
$this->assertInstanceOf(SubscriberEntity::class, $subscriberTwo);
verify($subscriberTwo->getDeletedAt())->notNull();
verify($this->subscriberSegmentRepository->findOneBy(['subscriber' => $subscriberTwoId]))->notNull();
verify($this->subscriberCustomFieldRepository->findOneBy(['subscriber' => $subscriberTwoId]))->notNull();
}
public function testItBulkRemoveSubscribersFromSegment(): void {
$subscriberOne = $this->createSubscriber('one@remove.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@remove.com', new DateTimeImmutable());
$segmentOne = $this->segmentRepository->createOrUpdate('One Remove');
$segmentTwo = $this->segmentRepository->createOrUpdate('Two Remove');
$this->createSubscriberSegment($segmentOne, $subscriberOne);
$this->createSubscriberSegment($segmentOne, $subscriberTwo);
$this->createSubscriberSegment($segmentTwo, $subscriberOne);
$this->createSubscriberSegment($segmentTwo, $subscriberTwo);
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$segmentOneId = $segmentOne->getId();
$segmentTwoId = $segmentTwo->getId();
$this->repository->bulkRemoveFromSegment($segmentOne, [$subscriberOneId]);
$this->repository->bulkRemoveFromSegment($segmentTwo, [$subscriberTwoId]);
$this->entityManager->clear();
// subscriber with removed segment one
verify($this->repository->findOneById($subscriberOneId))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberOneId,
'segment' => $segmentOneId,
]))->null();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberOneId,
'segment' => $segmentTwoId,
]))->notNull();
// subscriber with removed segment two
verify($this->repository->findOneById($subscriberTwoId))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberTwoId,
'segment' => $segmentTwoId,
]))->null();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberTwoId,
'segment' => $segmentOneId,
]))->notNull();
}
public function testItBulkUnsubscribes(): void {
$subscriberOne = $this->createSubscriber('one@removeAll.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@removeAll.com', new DateTimeImmutable());
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$this->repository->bulkUnsubscribe([$subscriberOneId]);
$this->entityManager->clear();
// subscriber with removed segments
$unsubscribedSubscriber = $this->repository->findOneById($subscriberOneId);
verify($unsubscribedSubscriber)->notNull();
$this->assertInstanceOf(SubscriberEntity::class, $unsubscribedSubscriber);
verify($unsubscribedSubscriber->getStatus())->equals(SubscriberEntity::STATUS_UNSUBSCRIBED);
// subscriber still subscribed
$subscribedSubscriber = $this->repository->findOneById($subscriberTwoId);
verify($subscribedSubscriber)->notNull();
$this->assertInstanceOf(SubscriberEntity::class, $subscribedSubscriber);
verify($subscribedSubscriber->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
}
public function testItBulkRemoveSubscriberFromAllSegments(): void {
$subscriberOne = $this->createSubscriber('one@removeAll.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@removeAll.com', new DateTimeImmutable());
$segmentOne = $this->segmentRepository->createOrUpdate('One Remove All');
$segmentTwo = $this->segmentRepository->createOrUpdate('Two Remove All');
$this->createSubscriberSegment($segmentOne, $subscriberOne);
$this->createSubscriberSegment($segmentOne, $subscriberTwo);
$this->createSubscriberSegment($segmentTwo, $subscriberOne);
$this->createSubscriberSegment($segmentTwo, $subscriberTwo);
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$segmentOneId = $segmentOne->getId();
$segmentTwoId = $segmentTwo->getId();
$this->repository->bulkRemoveFromAllSegments([$subscriberOneId]);
$this->entityManager->clear();
// subscriber with removed segments
verify($this->repository->findOneById($subscriberOneId))->notNull();
verify($this->subscriberSegmentRepository->findBy(['subscriber' => $subscriberOneId]))->arrayCount(0);
// subscriber with segments
verify($this->repository->findOneById($subscriberTwoId))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberTwoId,
'segment' => $segmentOneId,
]))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberTwoId,
'segment' => $segmentTwoId,
]))->notNull();
}
public function testItBulkAddSubscribersToSegment(): void {
$subscriberOne = $this->createSubscriber('one@add.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@add.com', new DateTimeImmutable());
$segmentOne = $this->segmentRepository->createOrUpdate('One Add');
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$segmentOneId = $segmentOne->getId();
$this->repository->bulkAddToSegment($segmentOne, [$subscriberOneId]);
$this->entityManager->clear();
// subscriber with segment
verify($this->repository->findOneById($subscriberOneId))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberOneId,
'segment' => $segmentOneId,
]))->notNull();
// subscriber without segment
verify($this->repository->findOneById($subscriberTwoId))->notNull();
verify($this->subscriberSegmentRepository->findBy(['subscriber' => $subscriberTwoId]))->arrayCount(0);
}
public function testItBulMoveSubscribersToSegment(): void {
$subscriberOne = $this->createSubscriber('one@move.com', new DateTimeImmutable());
$subscriberTwo = $this->createSubscriber('two@move.com', new DateTimeImmutable());
$segmentOne = $this->segmentRepository->createOrUpdate('One Move');
$segmentTwo = $this->segmentRepository->createOrUpdate('Two Move');
$this->createSubscriberSegment($segmentOne, $subscriberOne);
$this->createSubscriberSegment($segmentTwo, $subscriberTwo);
$subscriberOneId = $subscriberOne->getId();
$subscriberTwoId = $subscriberTwo->getId();
$segmentOneId = $segmentOne->getId();
$segmentTwoId = $segmentTwo->getId();
$this->repository->bulkMoveToSegment($segmentTwo, [$subscriberOneId]);
$this->entityManager->clear();
// subscriber moved to segment two
verify($this->repository->findOneById($subscriberOneId))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberOneId,
'segment' => $segmentOneId,
]))->null();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberOneId,
'segment' => $segmentTwoId,
]))->notNull();
// subscriber which stay in segment two
verify($this->repository->findOneById($subscriberTwoId))->notNull();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberTwoId,
'segment' => $segmentOneId,
]))->null();
verify($this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriberTwoId,
'segment' => $segmentTwoId,
]))->notNull();
}
public function testItDoesntRemovePermanentlyWordpressSubscriber(): void {
$subscriber = $this->createSubscriber('wpsubscriber@delete.com');
$subscriber->setWpUserId(1);
$this->repository->flush();
$this->entityManager->clear();
$subscriberId = $subscriber->getId();
$count = $this->repository->bulkDelete([$subscriber->getId()]);
verify($count)->equals(0);
verify($this->repository->findOneById($subscriberId))->notNull();
}
public function testItDoesntRemovePermanentlyWoocommerceSubscriber(): void {
$subscriber = $this->createSubscriber('wcsubscriber@delete.com');
$subscriber->setIsWoocommerceUser(true);
$this->repository->flush();
$this->entityManager->clear();
$subscriberId = $subscriber->getId();
$count = $this->repository->bulkDelete([$subscriberId]);
verify($count)->equals(0);
verify($this->repository->findOneById($subscriberId))->notNull();
}
public function testItGetsMaxSubscriberId(): void {
// check if equals to zero when no subscribers
verify($this->repository->getMaxSubscriberId())->equals(0);
// check if equals to max subscriber id
$this->createSubscriber('sub1@test.com');
$subscriberTwo = $this->createSubscriber('sub2@test.com');
verify($this->repository->getMaxSubscriberId())->equals($subscriberTwo->getId());
}
public function testRemoveOrphanedSubscribersFromWpSegment(): void {
$wpUserId1 = $this->tester->createWordPressUser('subscriber1@email.com', 'author');
$wpUserId2 = $this->tester->createWordPressUser('subscriber2@email.com', 'author');
$wpUserId3 = $this->tester->createWordPressUser('subscriber3@email.com', 'author');
$subscriber2 = $this->repository->findOneBy(['wpUserId' => $wpUserId2]);
$subscriber3 = $this->repository->findOneBy(['wpUserId' => $wpUserId3]);
$this->tester->deleteWPUserFromDatabase($wpUserId1);
$this->repository->removeOrphanedSubscribersFromWpSegment();
$subscribers = $this->repository->findAll();
$this->assertCount(2, $subscribers);
$this->assertSame($subscribers[0], $subscriber2);
$this->assertSame($subscribers[1], $subscriber3);
}
public function testRemoveByWpUserIds(): void {
$wpUserId1 = $this->tester->createWordPressUser('subscriber1@email.com', 'author');
$wpUserId2 = $this->tester->createWordPressUser('subscriber2@email.com', 'author');
$wpUserId3 = $this->tester->createWordPressUser('subscriber3@email.com', 'author');
$subscriber3 = $this->repository->findOneBy(['wpUserId' => $wpUserId3]);
$deletedRows = $this->repository->removeByWpUserIds([$wpUserId1, $wpUserId2]);
$this->assertSame(2, $deletedRows);
$subscribers = $this->repository->findAll();
$this->assertCount(1, $subscribers);
$this->assertSame($subscribers[0], $subscriber3);
}
private function createSubscriber(string $email, ?DateTimeImmutable $deletedAt = null): SubscriberEntity {
$subscriber = new SubscriberEntity();
$subscriber->setEmail($email);
$subscriber->setFirstName('John');
$subscriber->setLastName('Doe');
$subscriber->setStatus(SubscriberEntity::STATUS_SUBSCRIBED);
$subscriber->setDeletedAt($deletedAt);
$this->entityManager->persist($subscriber);
$this->entityManager->flush();
return $subscriber;
}
private function createSubscriberSegment(SegmentEntity $segment, SubscriberEntity $subscriber): SubscriberSegmentEntity {
$subscriberSegment = new SubscriberSegmentEntity($segment, $subscriber, SubscriberEntity::STATUS_SUBSCRIBED);
$this->entityManager->persist($subscriberSegment);
$this->entityManager->flush();
return $subscriberSegment;
}
private function createCustomField(string $name): CustomFieldEntity {
$customField = new CustomFieldEntity();
$customField->setName($name);
$customField->setType(CustomFieldEntity::TYPE_TEXT);
$this->entityManager->persist($customField);
$this->entityManager->flush();
return $customField;
}
private function createSubscriberCustomField(SubscriberEntity $subscriber, CustomFieldEntity $customField): SubscriberCustomFieldEntity {
$subscirberCustomField = new SubscriberCustomFieldEntity($subscriber, $customField, 'some value');
$this->entityManager->persist($subscirberCustomField);
$this->entityManager->flush();
return $subscirberCustomField;
}
}