Skip to content

Commit 0f455f5

Browse files
committed
UserMessageStatus
1 parent 94155dc commit 0f455f5

File tree

6 files changed

+69
-12
lines changed

6 files changed

+69
-12
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Messaging\Model\Message;
6+
7+
enum UserMessageStatus: string
8+
{
9+
case Todo = 'todo';
10+
case Active = 'active';
11+
case Sent = 'sent';
12+
case NotSent = 'not sent';
13+
case InvalidEmailAddress = 'invalid email address';
14+
case UnconfirmedUser = 'unconfirmed user';
15+
case Excluded = 'excluded';
16+
}

src/Domain/Messaging/Model/UserMessage.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use DateTime;
88
use Doctrine\ORM\Mapping as ORM;
99
use PhpList\Core\Domain\Common\Model\Interfaces\DomainModel;
10+
use PhpList\Core\Domain\Messaging\Model\Message\UserMessageStatus;
1011
use PhpList\Core\Domain\Messaging\Repository\UserMessageRepository;
1112
use PhpList\Core\Domain\Subscription\Model\Subscriber;
1213

@@ -65,9 +66,12 @@ public function getViewed(): ?DateTime
6566
return $this->viewed;
6667
}
6768

68-
public function getStatus(): ?string
69+
/**
70+
* @SuppressWarnings("PHPMD.StaticAccess")
71+
*/
72+
public function getStatus(): ?UserMessageStatus
6973
{
70-
return $this->status;
74+
return UserMessageStatus::from($this->status);
7175
}
7276

7377
public function setViewed(?DateTime $viewed): self
@@ -76,9 +80,9 @@ public function setViewed(?DateTime $viewed): self
7680
return $this;
7781
}
7882

79-
public function setStatus(?string $status): self
83+
public function setStatus(?UserMessageStatus $status): self
8084
{
81-
$this->status = $status;
85+
$this->status = $status->value;
8286
return $this;
8387
}
8488
}

src/Domain/Messaging/Repository/UserMessageRepository.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
namespace PhpList\Core\Domain\Messaging\Repository;
66

77
use PhpList\Core\Domain\Common\Repository\AbstractRepository;
8+
use PhpList\Core\Domain\Messaging\Model\Message;
9+
use PhpList\Core\Domain\Messaging\Model\UserMessage;
10+
use PhpList\Core\Domain\Subscription\Model\Subscriber;
811

912
class UserMessageRepository extends AbstractRepository
1013
{
14+
public function findOneByUserAndMessage(Subscriber $subscriber, Message $campaign): ?UserMessage
15+
{
16+
return $this->findOneBy(['user' => $subscriber, 'message' => $campaign]);
17+
}
1118
}

src/Domain/Messaging/Service/Processor/CampaignProcessor.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use Doctrine\ORM\EntityManagerInterface;
88
use PhpList\Core\Domain\Messaging\Model\Message;
9+
use PhpList\Core\Domain\Messaging\Model\UserMessage;
10+
use PhpList\Core\Domain\Messaging\Model\Message\UserMessageStatus;
11+
use PhpList\Core\Domain\Messaging\Repository\UserMessageRepository;
912
use PhpList\Core\Domain\Messaging\Service\MessageProcessingPreparator;
1013
use PhpList\Core\Domain\Messaging\Service\SendRateLimiter;
1114
use PhpList\Core\Domain\Subscription\Service\Provider\SubscriberProvider;
@@ -23,6 +26,7 @@ class CampaignProcessor
2326
private MessageProcessingPreparator $messagePreparator;
2427
private LoggerInterface $logger;
2528
private SendRateLimiter $rateLimiter;
29+
private UserMessageRepository $userMessageRepository;
2630

2731
public function __construct(
2832
MailerInterface $mailer,
@@ -31,13 +35,15 @@ public function __construct(
3135
MessageProcessingPreparator $messagePreparator,
3236
LoggerInterface $logger,
3337
SendRateLimiter $rateLimiter,
38+
UserMessageRepository $userMessageRepository
3439
) {
3540
$this->mailer = $mailer;
3641
$this->entityManager = $entityManager;
3742
$this->subscriberProvider = $subscriberProvider;
3843
$this->messagePreparator = $messagePreparator;
3944
$this->logger = $logger;
4045
$this->rateLimiter = $rateLimiter;
46+
$this->userMessageRepository = $userMessageRepository;
4147
}
4248

4349
public function process(Message $campaign, ?OutputInterface $output = null): void
@@ -48,12 +54,25 @@ public function process(Message $campaign, ?OutputInterface $output = null): voi
4854
$this->updateMessageStatus($campaign, Message\MessageStatus::InProcess);
4955

5056
foreach ($subscribers as $subscriber) {
57+
$existing = $this->userMessageRepository->findOneByUserAndMessage($subscriber, $campaign);
58+
if ($existing && $existing->getStatus() !== UserMessageStatus::Todo->value) {
59+
continue;
60+
}
61+
62+
$userMessage = $existing ?? new UserMessage($subscriber, $campaign);
63+
$userMessage->setStatus(UserMessageStatus::Active);
64+
$this->entityManager->persist($userMessage);
65+
$this->entityManager->flush();
66+
5167
$this->rateLimiter->awaitTurn($output);
5268

5369
if (!filter_var($subscriber->getEmail(), FILTER_VALIDATE_EMAIL)) {
70+
$this->updateUserMessageStatus($userMessage, UserMessageStatus::InvalidEmailAddress);
5471
continue;
5572
}
73+
5674
$this->messagePreparator->processMessageLinks($campaign, $subscriber->getId());
75+
5776
$email = (new Email())
5877
5978
->to($subscriber->getEmail())
@@ -63,8 +82,10 @@ public function process(Message $campaign, ?OutputInterface $output = null): voi
6382

6483
try {
6584
$this->mailer->send($email);
85+
$this->updateUserMessageStatus($userMessage, UserMessageStatus::Sent);
6686
$this->rateLimiter->afterSend();
6787
} catch (Throwable $e) {
88+
$this->updateUserMessageStatus($userMessage, UserMessageStatus::NotSent);
6889
$this->logger->error($e->getMessage(), [
6990
'subscriber_id' => $subscriber->getId(),
7091
'campaign_id' => $campaign->getId(),
@@ -81,4 +102,9 @@ private function updateMessageStatus(Message $message, Message\MessageStatus $st
81102
$message->getMetadata()->setStatus($status);
82103
$this->entityManager->flush();
83104
}
84-
}
105+
106+
private function updateUserMessageStatus(UserMessage $userMessage, Message\UserMessageStatus $status): void
107+
{
108+
$userMessage->setStatus($status);
109+
$this->entityManager->flush();
110+
}}

tests/Integration/Domain/Subscription/Service/SubscriberDeletionServiceTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public function testDeleteSubscriberWithRelatedDataDoesNotThrowDoctrineError():
9292
$this->entityManager->persist($linkTrackUmlClick);
9393

9494
$userMessage = new UserMessage($subscriber, $msg);
95-
$userMessage->setStatus('sent');
95+
$userMessage->setStatus(Message\UserMessageStatus::Sent);
9696
$this->entityManager->persist($userMessage);
9797

9898
$userMessageBounce = new UserMessageBounce(1, new DateTime());

tests/Unit/Domain/Messaging/Service/Processor/CampaignProcessorTest.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpList\Core\Domain\Messaging\Model\Message;
1010
use PhpList\Core\Domain\Messaging\Model\Message\MessageContent;
1111
use PhpList\Core\Domain\Messaging\Model\Message\MessageMetadata;
12+
use PhpList\Core\Domain\Messaging\Repository\UserMessageRepository;
1213
use PhpList\Core\Domain\Messaging\Service\MessageProcessingPreparator;
1314
use PhpList\Core\Domain\Messaging\Service\Processor\CampaignProcessor;
1415
use PhpList\Core\Domain\Messaging\Service\SendRateLimiter;
@@ -31,6 +32,7 @@ class CampaignProcessorTest extends TestCase
3132
private OutputInterface&MockObject $output;
3233
private CampaignProcessor $campaignProcessor;
3334
private SendRateLimiter&MockObject $rateLimiter;
35+
private UserMessageRepository&MockObject $userMessageRepository;
3436

3537
protected function setUp(): void
3638
{
@@ -41,16 +43,18 @@ protected function setUp(): void
4143
$this->logger = $this->createMock(LoggerInterface::class);
4244
$this->output = $this->createMock(OutputInterface::class);
4345
$this->rateLimiter = $this->createMock(SendRateLimiter::class);
46+
$this->userMessageRepository = $this->createMock(UserMessageRepository::class);
4447
$this->rateLimiter->method('awaitTurn');
4548
$this->rateLimiter->method('afterSend');
4649

4750
$this->campaignProcessor = new CampaignProcessor(
48-
$this->mailer,
49-
$this->entityManager,
50-
$this->subscriberProvider,
51-
$this->messagePreparator,
52-
$this->logger,
53-
$this->rateLimiter
51+
mailer: $this->mailer,
52+
entityManager: $this->entityManager,
53+
subscriberProvider: $this->subscriberProvider,
54+
messagePreparator: $this->messagePreparator,
55+
logger: $this->logger,
56+
rateLimiter: $this->rateLimiter,
57+
userMessageRepository: $this->userMessageRepository,
5458
);
5559
}
5660

0 commit comments

Comments
 (0)