diff --git a/composer.json b/composer.json index 3bf738e..7753dff 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^8.1", - "directorytree/imapengine": "^1.13.0", + "directorytree/imapengine": "^1.19.0", "illuminate/contracts": "^10.0|^11.0|^12.0" }, "require-dev": { diff --git a/src/Commands/WatchMailbox.php b/src/Commands/WatchMailbox.php index 45a1dac..b392cc7 100644 --- a/src/Commands/WatchMailbox.php +++ b/src/Commands/WatchMailbox.php @@ -7,11 +7,11 @@ use DirectoryTree\ImapEngine\Laravel\Facades\Imap; use DirectoryTree\ImapEngine\Laravel\Support\LoopInterface; use DirectoryTree\ImapEngine\MailboxInterface; -use DirectoryTree\ImapEngine\Message; use Exception; use Illuminate\Console\Command; use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; +use Symfony\Component\Console\Exception\InvalidOptionException; class WatchMailbox extends Command { @@ -20,7 +20,7 @@ class WatchMailbox extends Command * * @var string */ - protected $signature = 'imap:watch {mailbox} {folder?} {--with=} {--timeout=30} {--attempts=5} {--debug=false}'; + protected $signature = 'imap:watch {mailbox} {folder?} {--method=idle} {--with=} {--timeout=30} {--attempts=5} {--debug=false}'; /** * The console command description. @@ -34,6 +34,10 @@ class WatchMailbox extends Command */ public function handle(LoopInterface $loop): void { + if (! in_array($method = $this->option('method'), ['idle', 'poll'])) { + throw new InvalidOptionException("Invalid method [{$method}]. Valid options are [idle, poll]."); + } + $mailbox = Imap::mailbox($name = $this->argument('mailbox')); $with = explode(',', $this->option('with')); @@ -48,11 +52,18 @@ public function handle(LoopInterface $loop): void try { $folder = $this->folder($mailbox); - $folder->idle( - new HandleMessageReceived($this, $attempts, $lastReceivedAt), - new ConfigureIdleQuery($with), - $this->option('timeout') - ); + match ($this->option('method')) { + 'idle' => $folder->idle( + new HandleMessageReceived($this, $attempts, $lastReceivedAt), + new ConfigureIdleQuery($with), + $this->option('timeout'), + ), + 'poll' => $folder->poll( + new HandleMessageReceived($this, $attempts, $lastReceivedAt), + new ConfigureIdleQuery($with), + $this->option('timeout'), + ), + }; } catch (Exception $e) { if ($this->isMessageMissing($e)) { return; diff --git a/tests/Commands/WatchMailboxTest.php b/tests/Commands/WatchMailboxTest.php index 12f3807..d7f6878 100644 --- a/tests/Commands/WatchMailboxTest.php +++ b/tests/Commands/WatchMailboxTest.php @@ -15,6 +15,7 @@ use Illuminate\Support\Facades\Event; use InvalidArgumentException; use RuntimeException; +use Symfony\Component\Console\Exception\InvalidOptionException; use function Pest\Laravel\artisan; @@ -51,6 +52,35 @@ ); }); +it('can watch mailbox using method', function (string $method) { + Config::set('imap.mailboxes.test', [ + 'host' => 'localhost', + 'port' => 993, + 'encryption' => 'ssl', + 'username' => '', + 'password' => '', + ]); + + Imap::fake('test', folders: [ + new FakeFolder('inbox', messages: [ + $message = new FakeMessage(uid: 1), + ]), + ]); + + App::bind(LoopInterface::class, LoopFake::class); + + Event::fake(); + + artisan(WatchMailbox::class, [ + 'mailbox' => 'test', + '--method' => $method, + ])->assertSuccessful(); + + Event::assertDispatched( + fn (MessageReceived $event) => $event->message->is($message) + ); +})->with(['idle', 'poll']); + it('dispatches event when failure attempts have been reached', function () { Config::set('imap.mailboxes.test', [ 'host' => 'localhost', @@ -91,3 +121,27 @@ public function idle( && $event->exception->getMessage() === 'Simulated exception'; }); }); + +it('throws exception when invalid method is provided', function () { + Config::set('imap.mailboxes.test', [ + 'host' => 'localhost', + 'port' => 993, + 'encryption' => 'ssl', + 'username' => '', + 'password' => '', + ]); + + Imap::fake('test', folders: [ + new FakeFolder('inbox'), + ]); + + App::bind(LoopInterface::class, LoopFake::class); + + artisan(WatchMailbox::class, [ + 'mailbox' => 'test', + '--method' => 'invalid', + ]); +})->throws( + InvalidOptionException::class, + 'Invalid method [invalid]. Valid options are [idle, poll].' +);