Skip to content

Commit d179107

Browse files
committed
ClientFactory + refactor
1 parent 34ec99c commit d179107

File tree

10 files changed

+205
-97
lines changed

10 files changed

+205
-97
lines changed

config/parameters.yml.dist

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ parameters:
4343
env(BOUNCE_IMAP_PORT): 993
4444
imap_bounce.encryption: '%%env(BOUNCE_IMAP_ENCRYPTION)%%'
4545
env(BOUNCE_IMAP_ENCRYPTION): 'ssl'
46+
imap_bounce.mailbox: '%%env(BOUNCE_IMAP_MAILBOX)%%'
47+
env(BOUNCE_IMAP_MAILBOX): '/var/spool/mail/bounces'
48+
imap_bounce.mailbox_name: '%%env(BOUNCE_IMAP_MAILBOX_NAME)%%'
49+
env(BOUNCE_IMAP_MAILBOX_NAME): 'INBOX,ONE_MORE'
50+
imap_bounce.protocol: '%%env(BOUNCE_IMAP_PROTOCOL)%%'
51+
env(BOUNCE_IMAP_PROTOCOL): 'imap'
52+
imap_bounce.unsubscribe_threshold: '%%env(BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD)%%'
53+
env(BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD): 5
54+
imap_bounce.blacklist_threshold: '%%env(BOUNCE_IMAP_BLACKLIST_THRESHOLD)%%'
55+
env(BOUNCE_IMAP_BLACKLIST_THRESHOLD): 3
56+
imap_bounce.purge: '%%env(BOUNCE_IMAP_PURGE)%%'
57+
env(BOUNCE_IMAP_PURGE): 0
58+
imap_bounce.purge_unprocessed: '%%env(BOUNCE_IMAP_PURGE_UNPROCESSED)%%'
59+
env(BOUNCE_IMAP_PURGE_UNPROCESSED): 0
4660

4761
# Messenger configuration for asynchronous processing
4862
app.messenger_transport_dsn: '%%env(MESSENGER_TRANSPORT_DSN)%%'

config/services/processor.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ services:
55
public: false
66

77
PhpList\Core\Domain\Messaging\Service\Processor\PopBounceProcessor:
8+
arguments:
9+
$host: '%imap_bounce.host%'
10+
$port: '%imap_bounce.port%'
11+
$mailboxNames: '%imap_bounce.mailbox_name%'
812
tags: ['phplist.bounce_protocol_processor']
913

1014
PhpList\Core\Domain\Messaging\Service\Processor\MboxBounceProcessor:

config/services/services.yml

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,41 @@ services:
4545
autoconfigure: true
4646

4747
PhpList\Core\Domain\Messaging\Service\ConsecutiveBounceHandler:
48-
autowire: true
49-
autoconfigure: true
50-
arguments:
51-
$unsubscribeThreshold: '%app.unsubscribe_threshold%'
52-
$blacklistThreshold: '%app.blacklist_threshold%'
48+
autowire: true
49+
autoconfigure: true
50+
arguments:
51+
$unsubscribeThreshold: '%imap_bounce.unsubscribe_threshold%'
52+
$blacklistThreshold: '%imap_bounce.blacklist_threshold%'
5353

5454
Webklex\PHPIMAP\ClientManager: ~
5555

56+
PhpList\Core\Domain\Messaging\Service\WebklexImapClientFactory:
57+
autowire: true
58+
autoconfigure: true
59+
arguments:
60+
$mailbox: '%imap_bounce.mailbox%'# e.g. "{imap.example.com:993/imap/ssl}INBOX" or "/var/mail/user"
61+
$host: '%imap_bounce.host%'
62+
$port: '%imap_bounce.port%'
63+
$encryption: '%imap_bounce.encryption%'
64+
$username: '%imap_bounce.email%'
65+
$password: '%imap_bounce.password%'
66+
$protocol: '%imap_bounce.protocol%'
67+
5668
PhpList\Core\Domain\Common\Mail\NativeImapMailReader:
57-
arguments:
58-
$mailbox: '%env(IMAP_MAILBOX)%' # e.g. "{imap.example.com:993/imap/ssl}INBOX" or "/var/mail/user"
59-
$user: '%imap_bounce.email%'
60-
$pass: '%imap_bounce.password%'
69+
arguments:
70+
$username: '%imap_bounce.email%'
71+
$password: '%imap_bounce.password%'
72+
73+
PhpList\Core\Domain\Messaging\Service\NativeBounceProcessingService:
74+
autowire: true
75+
autoconfigure: true
76+
arguments:
77+
$purgeProcessed: '%imap_bounce.purge%'
78+
$purgeUnprocessed: '%imap_bounce.purge_unprocessed%'
79+
80+
PhpList\Core\Domain\Messaging\Service\WebklexBounceProcessingService:
81+
autowire: true
82+
autoconfigure: true
83+
arguments:
84+
$purgeProcessed: '%imap_bounce.purge%'
85+
$purgeUnprocessed: '%imap_bounce.purge_unprocessed%'

src/Domain/Common/Mail/NativeImapMailReader.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,22 @@
1010

1111
class NativeImapMailReader
1212
{
13-
public function open(string $mailbox, ?string $user = null, ?string $password = null, int $options = 0): Connection
13+
private string $username;
14+
private string $password;
15+
16+
public function __construct(string $username, string $password)
1417
{
15-
$link = @imap_open($mailbox, (string)$user, (string)$password, $options);
18+
$this->username = $username;
19+
$this->password = $password;
20+
}
21+
22+
public function open(string $mailbox, int $options = 0): Connection
23+
{
24+
$link = @imap_open($mailbox, $this->username, $this->password, $options);
1625
if ($link === false) {
1726
throw new RuntimeException('Cannot open mailbox: '.(imap_last_error() ?: 'unknown error'));
1827
}
28+
1929
return $link;
2030
}
2131

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Messaging\Service;
6+
7+
use Symfony\Component\Console\Style\SymfonyStyle;
8+
9+
interface BounceProcessingServiceInterface
10+
{
11+
public function processMailbox(SymfonyStyle $io, string $mailbox, int $max, bool $testMode): string;
12+
}

src/Domain/Messaging/Service/NativeBounceProcessingService.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,39 @@
1111
use Symfony\Component\Console\Style\SymfonyStyle;
1212
use Throwable;
1313

14-
class NativeBounceProcessingService
14+
class NativeBounceProcessingService implements BounceProcessingServiceInterface
1515
{
1616
private BounceManager $bounceManager;
1717
private NativeImapMailReader $mailReader;
1818
private MessageParser $messageParser;
1919
private BounceDataProcessor $bounceDataProcessor;
20+
private bool $purgeProcessed;
21+
private bool $purgeUnprocessed;
2022

2123
public function __construct(
2224
BounceManager $bounceManager,
2325
NativeImapMailReader $mailReader,
2426
MessageParser $messageParser,
2527
BounceDataProcessor $bounceDataProcessor,
28+
bool $purgeProcessed,
29+
bool $purgeUnprocessed
2630
) {
2731
$this->bounceManager = $bounceManager;
2832
$this->mailReader = $mailReader;
2933
$this->messageParser = $messageParser;
3034
$this->bounceDataProcessor = $bounceDataProcessor;
35+
$this->purgeProcessed = $purgeProcessed;
36+
$this->purgeUnprocessed = $purgeUnprocessed;
3137
}
3238

3339
public function processMailbox(
3440
SymfonyStyle $io,
3541
string $mailbox,
36-
string $user,
37-
string $password,
3842
int $max,
39-
bool $purgeProcessed,
40-
bool $purgeUnprocessed,
4143
bool $testMode
4244
): string {
4345
try {
44-
$link = $this->mailReader->open($mailbox, $user, $password, $testMode ? 0 : CL_EXPUNGE);
46+
$link = $this->mailReader->open($mailbox, $testMode ? 0 : CL_EXPUNGE);
4547
} catch (Throwable $e) {
4648
$io->error('Cannot open mailbox file: '.$e->getMessage());
4749
throw new RuntimeException('Cannot open mbox file');
@@ -66,11 +68,11 @@ public function processMailbox(
6668
$header = $this->mailReader->fetchHeader($link, $x);
6769
$processed = $this->processImapBounce($link, $x, $header, $io);
6870
if ($processed) {
69-
if (!$testMode && $purgeProcessed) {
71+
if (!$testMode && $this->purgeProcessed) {
7072
$this->mailReader->delete($link, $x);
7173
}
7274
} else {
73-
if (!$testMode && $purgeUnprocessed) {
75+
if (!$testMode && $this->purgeUnprocessed) {
7476
$this->mailReader->delete($link, $x);
7577
}
7678
}

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

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,18 @@
44

55
namespace PhpList\Core\Domain\Messaging\Service\Processor;
66

7-
use PhpList\Core\Domain\Messaging\Service\NativeBounceProcessingService;
7+
use PhpList\Core\Domain\Messaging\Service\BounceProcessingServiceInterface;
88
use RuntimeException;
99
use Symfony\Component\Console\Input\InputInterface;
1010
use Symfony\Component\Console\Style\SymfonyStyle;
1111

1212
class MboxBounceProcessor implements BounceProtocolProcessor
1313
{
14-
private $processingService;
15-
private string $user;
16-
private string $pass;
14+
private BounceProcessingServiceInterface $processingService;
1715

18-
public function __construct(NativeBounceProcessingService $processingService, string $user, string $pass)
16+
public function __construct(BounceProcessingServiceInterface $processingService)
1917
{
2018
$this->processingService = $processingService;
21-
$this->user = $user;
22-
$this->pass = $pass;
2319
}
2420

2521
public function getProtocol(): string
@@ -31,8 +27,6 @@ public function process(InputInterface $input, SymfonyStyle $io): string
3127
{
3228
$testMode = (bool)$input->getOption('test');
3329
$max = (int)$input->getOption('maximum');
34-
$purgeProcessed = $input->getOption('purge') && !$testMode;
35-
$purgeUnprocessed = $input->getOption('purge-unprocessed') && !$testMode;
3630

3731
$file = (string)$input->getOption('mailbox');
3832
if (!$file) {
@@ -45,11 +39,7 @@ public function process(InputInterface $input, SymfonyStyle $io): string
4539
return $this->processingService->processMailbox(
4640
$io,
4741
$file,
48-
$this->user,
49-
$this->pass,
5042
$max,
51-
$purgeProcessed,
52-
$purgeUnprocessed,
5343
$testMode
5444
);
5545
}

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

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,27 @@
44

55
namespace PhpList\Core\Domain\Messaging\Service\Processor;
66

7-
use PhpList\Core\Domain\Messaging\Service\NativeBounceProcessingService;
8-
use RuntimeException;
7+
use PhpList\Core\Domain\Messaging\Service\BounceProcessingServiceInterface;
98
use Symfony\Component\Console\Input\InputInterface;
109
use Symfony\Component\Console\Style\SymfonyStyle;
1110

1211
class PopBounceProcessor implements BounceProtocolProcessor
1312
{
14-
private $processingService;
15-
16-
public function __construct(NativeBounceProcessingService $processingService)
17-
{
13+
private BounceProcessingServiceInterface $processingService;
14+
private string $host;
15+
private int $port;
16+
private string $mailboxNames;
17+
18+
public function __construct(
19+
BounceProcessingServiceInterface $processingService,
20+
string $host,
21+
int $port,
22+
string $mailboxNames
23+
) {
1824
$this->processingService = $processingService;
25+
$this->host = $host;
26+
$this->port = $port;
27+
$this->mailboxNames = $mailboxNames;
1928
}
2029

2130
public function getProtocol(): string
@@ -27,35 +36,18 @@ public function process(InputInterface $input, SymfonyStyle $io): string
2736
{
2837
$testMode = (bool)$input->getOption('test');
2938
$max = (int)$input->getOption('maximum');
30-
$purgeProcessed = $input->getOption('purge') && !$testMode;
31-
$purgeUnprocessed = $input->getOption('purge-unprocessed') && !$testMode;
32-
33-
$host = (string)$input->getOption('host');
34-
$user = (string)$input->getOption('user');
35-
$password = (string)$input->getOption('password');
36-
$port = (string)$input->getOption('port');
37-
$mailboxes = (string)$input->getOption('mailbox');
38-
39-
if (!$host || !$user || !$password) {
40-
$io->error('POP configuration incomplete: host, user, and password are required.');
41-
throw new RuntimeException('POP configuration incomplete');
42-
}
4339

4440
$downloadReport = '';
45-
foreach (explode(',', $mailboxes) as $mailboxName) {
41+
foreach (explode(',', $this->mailboxNames) as $mailboxName) {
4642
$mailboxName = trim($mailboxName);
4743
if ($mailboxName === '') { $mailboxName = 'INBOX'; }
48-
$mailbox = sprintf('{%s:%s}%s', $host, $port, $mailboxName);
44+
$mailbox = sprintf('{%s:%s}%s', $this->host, $this->port, $mailboxName);
4945
$io->section("Connecting to $mailbox");
5046

5147
$downloadReport .= $this->processingService->processMailbox(
5248
$io,
5349
$mailbox,
54-
$user,
55-
$password,
5650
$max,
57-
$purgeProcessed,
58-
$purgeUnprocessed,
5951
$testMode
6052
);
6153
}

0 commit comments

Comments
 (0)