From ac18e60c6b655f28e2c72dae4594bf4dc45b99e3 Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 13:05:01 +0200 Subject: [PATCH 1/7] added option to queue e-mail --- src/EmailComposer.php | 25 +++++++++++++++++++++++++ src/SendEmailJob.php | 27 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/SendEmailJob.php diff --git a/src/EmailComposer.php b/src/EmailComposer.php index a7d25ff..0ab2cf8 100644 --- a/src/EmailComposer.php +++ b/src/EmailComposer.php @@ -194,6 +194,23 @@ public function later($scheduledAt) return $this->send(); } + /** + * Queue the e-mail. + * + * @return Email + */ + public function queue($connection = null, $queue = null) + { + $connection = $connection ?: config('queue.default'); + $queue = $queue ?: 'default'; + + $this->setData('queued', true); + $this->setData('connection', $connection); + $this->setData('queue', $queue); + + return $this->send(); + } + /** * Set the Mailable. * @@ -273,6 +290,14 @@ public function send() $this->email->refresh(); + if ($this->getData('queued') === true) { + dispatch(new SendEmailJob($this->email)) + ->onConnection($this->getData('connection')) + ->onQueue($this->getData('queue')); + + return $this->email; + } + if (Config::sendImmediately()) { $this->email->send(); } diff --git a/src/SendEmailJob.php b/src/SendEmailJob.php new file mode 100644 index 0000000..2f77769 --- /dev/null +++ b/src/SendEmailJob.php @@ -0,0 +1,27 @@ +email = $email; + } + + public function handle() + { + (new Sender())->send($this->email); + } +} From ce35b0edfded68d576d86ebe3972b95c297112e3 Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 13:08:56 +0200 Subject: [PATCH 2/7] provide default for optional value queued --- src/EmailComposer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EmailComposer.php b/src/EmailComposer.php index 0ab2cf8..933e97e 100644 --- a/src/EmailComposer.php +++ b/src/EmailComposer.php @@ -290,7 +290,7 @@ public function send() $this->email->refresh(); - if ($this->getData('queued') === true) { + if ($this->getData('queued', false) === true) { dispatch(new SendEmailJob($this->email)) ->onConnection($this->getData('connection')) ->onQueue($this->getData('queue')); From 73d3984d17335c6c33155a3e312c07cda655694d Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 13:32:44 +0200 Subject: [PATCH 3/7] added tests --- src/SendEmailJob.php | 2 +- tests/QueuedEmailsTest.php | 88 ++++++++++++++++++++++++++++++++++++++ tests/TestCase.php | 5 +++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/QueuedEmailsTest.php diff --git a/src/SendEmailJob.php b/src/SendEmailJob.php index 2f77769..4ca3070 100644 --- a/src/SendEmailJob.php +++ b/src/SendEmailJob.php @@ -13,7 +13,7 @@ class SendEmailJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - private $email; + public $email; public function __construct(Email $email) { diff --git a/tests/QueuedEmailsTest.php b/tests/QueuedEmailsTest.php new file mode 100644 index 0000000..1a1be88 --- /dev/null +++ b/tests/QueuedEmailsTest.php @@ -0,0 +1,88 @@ +registerPlugin(new TestingMailEventListener($this)); + } + + /** @test */ + public function queueing_an_email_will_leave_sending_on_false() + { + $email = $this->queueEmail(); + + $this->assertEquals(0, $email->sending); + } + + /** @test */ + public function queueing_an_email_will_dispatch_a_job() + { + Queue::fake(); + + $email = $this->queueEmail(); + + Queue::assertPushed(SendEmailJob::class, function (SendEmailJob $job) use ($email) { + return $job->email->id === $email->id; + }); + } + + /** @test */ + public function emails_can_be_queued_on_a_specific_connection() + { + Queue::fake(); + + $this->queueEmail('some-connection'); + + Queue::assertPushed(SendEmailJob::class, function (SendEmailJob $job) { + return $job->connection === 'some-connection'; + }); + } + + /** @test */ + public function emails_can_be_queued_on_a_specific_queue() + { + Queue::fake(); + + $this->queueEmail('default', 'some-queue'); + + Queue::assertPushed(SendEmailJob::class, function (SendEmailJob $job) { + return $job->queue === 'some-queue'; + }); + } + + /** @test */ + public function the_send_email_job_will_call_send_on_the_email_instance() + { + Queue::fake(); + + $email = $this->queueEmail('default', 'some-queue'); + + $job = new SendEmailJob($email); + + Mail::shouldReceive('send')->once(); + + $job->handle(); + } + + /** @test */ + public function the_mail_will_be_marked_as_sent_when_job_is_finished() + { + Queue::fake(); + + $email = $this->queueEmail('default', 'some-queue'); + + $job = new SendEmailJob($email); + $job->handle(); + + $this->assertTrue($email->isSent()); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 1565e14..a1b021e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -131,6 +131,11 @@ public function scheduleEmail($scheduledFor, $overwrite = []) return $this->createEmail($overwrite)->schedule($scheduledFor); } + public function queueEmail($connection = null, $queue = null, $overwrite = []) + { + return $this->createEmail($overwrite)->queue($connection, $queue); + } + public function assertStringContains($needle, $haystack) { if (method_exists($this, 'assertStringContainsString')) { From 0d9946590250325f074b7eda3db9a8df10608e64 Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 15:26:35 +0200 Subject: [PATCH 4/7] added option to delay queued mail --- src/EmailComposer.php | 9 +++++++-- tests/QueuedEmailsTest.php | 14 ++++++++++++++ tests/TestCase.php | 4 ++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/EmailComposer.php b/src/EmailComposer.php index 933e97e..31e3397 100644 --- a/src/EmailComposer.php +++ b/src/EmailComposer.php @@ -197,9 +197,12 @@ public function later($scheduledAt) /** * Queue the e-mail. * + * @param string|null $connection + * @param string|null $queue + * @param \DateTimeInterface|\DateInterval|int|null $delay * @return Email */ - public function queue($connection = null, $queue = null) + public function queue($connection = null, $queue = null, $delay = null) { $connection = $connection ?: config('queue.default'); $queue = $queue ?: 'default'; @@ -207,6 +210,7 @@ public function queue($connection = null, $queue = null) $this->setData('queued', true); $this->setData('connection', $connection); $this->setData('queue', $queue); + $this->setData('delay', $delay); return $this->send(); } @@ -293,7 +297,8 @@ public function send() if ($this->getData('queued', false) === true) { dispatch(new SendEmailJob($this->email)) ->onConnection($this->getData('connection')) - ->onQueue($this->getData('queue')); + ->onQueue($this->getData('queue')) + ->delay($this->getData('delay')); return $this->email; } diff --git a/tests/QueuedEmailsTest.php b/tests/QueuedEmailsTest.php index 1a1be88..6842b3f 100644 --- a/tests/QueuedEmailsTest.php +++ b/tests/QueuedEmailsTest.php @@ -59,6 +59,20 @@ public function emails_can_be_queued_on_a_specific_queue() }); } + /** @test */ + public function emails_can_be_queued_with_a_delay() + { + Queue::fake(); + + $delay = now()->addMinutes(6); + + $this->queueEmail(null, null, $delay); + + Queue::assertPushed(SendEmailJob::class, function (SendEmailJob $job) use ($delay) { + return $job->delay->getTimestamp() === $delay->timestamp; + }); + } + /** @test */ public function the_send_email_job_will_call_send_on_the_email_instance() { diff --git a/tests/TestCase.php b/tests/TestCase.php index a1b021e..01b8e2a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -131,9 +131,9 @@ public function scheduleEmail($scheduledFor, $overwrite = []) return $this->createEmail($overwrite)->schedule($scheduledFor); } - public function queueEmail($connection = null, $queue = null, $overwrite = []) + public function queueEmail($connection = null, $queue = null, $delay = null, $overwrite = []) { - return $this->createEmail($overwrite)->queue($connection, $queue); + return $this->createEmail($overwrite)->queue($connection, $queue, $delay); } public function assertStringContains($needle, $haystack) From d1157059f8f2965ff6a3b0ebfb2cbae670784dcb Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 15:29:48 +0200 Subject: [PATCH 5/7] test on laravel 7 --- .github/workflows/run-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 906edca..62ef497 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -12,9 +12,11 @@ jobs: strategy: matrix: php: [7.4, 7.3, 7.2] - laravel: [6.*, 5.8.*, 5.7.*, 5.6.*] + laravel: [7.*, 6.*, 5.8.*, 5.7.*, 5.6.*] os: [ubuntu-latest] include: + - laravel: 7.* + testbench: 5.* - laravel: 6.* testbench: 4.* - laravel: 5.8.* From e7b0501e830369b66f593194cae672d32e0b9e41 Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 15:33:01 +0200 Subject: [PATCH 6/7] update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index c505a69..5400b51 100644 --- a/composer.json +++ b/composer.json @@ -30,8 +30,8 @@ }, "require-dev": { "mockery/mockery": "^1.2", - "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0", - "symfony/console": "^4.4", + "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0 || ^5.0", + "symfony/console": "^4.4|^5.0", "tecnickcom/tcpdf": "^6.3" } } From 98aba43080e1e38bb0840b32aa4f3fe2e7271f3f Mon Sep 17 00:00:00 2001 From: Marick Date: Sat, 2 May 2020 16:26:33 +0200 Subject: [PATCH 7/7] update package so it works with all laravel versions --- src/Email.php | 15 ++++++++++++--- src/Sender.php | 14 ++------------ tests/EncryptionTest.php | 14 +++++++------- tests/QueuedEmailsTest.php | 2 -- tests/SendEmailsCommandTest.php | 8 +++----- tests/SenderTest.php | 3 +-- tests/TestCase.php | 2 ++ 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/Email.php b/src/Email.php index 32f29d2..f4a30bf 100644 --- a/src/Email.php +++ b/src/Email.php @@ -348,7 +348,7 @@ public function hasFrom() */ public function hasCc() { - return strlen($this->getOriginal('cc')) > 0; + return strlen($this->getRawDatabaseValue('cc')) > 0; } /** @@ -358,7 +358,7 @@ public function hasCc() */ public function hasBcc() { - return strlen($this->getOriginal('bcc')) > 0; + return strlen($this->getRawDatabaseValue('bcc')) > 0; } /** @@ -378,7 +378,7 @@ public function isScheduled() */ public function isEncrypted() { - return (bool) $this->getOriginal('encrypted'); + return (bool) $this->getRawDatabaseValue('encrypted'); } /** @@ -479,4 +479,13 @@ public function retry() $retry->save(); } + + public function getRawDatabaseValue($key = null, $default = null) + { + if (method_exists($this, 'getRawOriginal')) { + return $this->getRawOriginal($key, $default); + } + + return $this->getOriginal($key, $default); + } } diff --git a/src/Sender.php b/src/Sender.php index 8d74471..567819f 100644 --- a/src/Sender.php +++ b/src/Sender.php @@ -2,8 +2,8 @@ namespace Stackkit\LaravelDatabaseEmails; -use Illuminate\Mail\Mailer; use Illuminate\Mail\Message; +use Illuminate\Support\Facades\Mail; class Sender { @@ -20,23 +20,13 @@ public function send(Email $email) $email->markAsSending(); - $this->getMailerInstance()->send([], [], function (Message $message) use ($email) { + Mail::send([], [], function (Message $message) use ($email) { $this->buildMessage($message, $email); }); $email->markAsSent(); } - /** - * Get the instance of the Laravel mailer. - * - * @return Mailer - */ - private function getMailerInstance() - { - return app('mailer'); - } - /** * Build the e-mail message. * diff --git a/tests/EncryptionTest.php b/tests/EncryptionTest.php index d023c88..e3f6c01 100644 --- a/tests/EncryptionTest.php +++ b/tests/EncryptionTest.php @@ -26,7 +26,7 @@ public function the_recipient_should_be_encrypted_and_decrypted() { $email = $this->sendEmail(['recipient' => 'john@doe.com']); - $this->assertEquals('john@doe.com', decrypt($email->getOriginal('recipient'))); + $this->assertEquals('john@doe.com', decrypt($email->getRawDatabaseValue('recipient'))); $this->assertEquals('john@doe.com', $email->getRecipient()); } @@ -39,8 +39,8 @@ public function cc_and_bb_should_be_encrypted_and_decrypted() 'bcc' => $bcc = ['jane+1@doe.com', 'jane+2@doe.com'], ]); - $this->assertEquals($cc, decrypt($email->getOriginal('cc'))); - $this->assertEquals($bcc, decrypt($email->getOriginal('bcc'))); + $this->assertEquals($cc, decrypt($email->getRawDatabaseValue('cc'))); + $this->assertEquals($bcc, decrypt($email->getRawDatabaseValue('bcc'))); $this->assertEquals($cc, $email->getCc()); $this->assertEquals($bcc, $email->getBcc()); @@ -51,7 +51,7 @@ public function the_subject_should_be_encrypted_and_decrypted() { $email = $this->sendEmail(['subject' => 'test subject']); - $this->assertEquals('test subject', decrypt($email->getOriginal('subject'))); + $this->assertEquals('test subject', decrypt($email->getRawDatabaseValue('subject'))); $this->assertEquals('test subject', $email->getSubject()); } @@ -63,7 +63,7 @@ public function the_variables_should_be_encrypted_and_decrypted() $this->assertEquals( ['name' => 'Jane Doe'], - decrypt($email->getOriginal('variables')) + decrypt($email->getRawDatabaseValue('variables')) ); $this->assertEquals( @@ -79,7 +79,7 @@ public function the_body_should_be_encrypted_and_decrypted() $expectedBody = "Name: Jane Doe\n"; - $this->assertEquals($expectedBody, decrypt($email->getOriginal('body'))); + $this->assertEquals($expectedBody, decrypt($email->getRawDatabaseValue('body'))); $this->assertEquals($expectedBody, $email->getBody()); } @@ -94,7 +94,7 @@ public function from_should_be_encrypted_and_decrypted() 'name' => 'Marick', ]; - $this->assertEquals($expect, decrypt($email->getOriginal('from'))); + $this->assertEquals($expect, decrypt($email->getRawDatabaseValue('from'))); $this->assertEquals($expect, $email->getFrom()); } } diff --git a/tests/QueuedEmailsTest.php b/tests/QueuedEmailsTest.php index 6842b3f..340fdb2 100644 --- a/tests/QueuedEmailsTest.php +++ b/tests/QueuedEmailsTest.php @@ -11,8 +11,6 @@ class QueuedEmailsTest extends TestCase public function setUp(): void { parent::setUp(); - - Mail::getSwiftMailer()->registerPlugin(new TestingMailEventListener($this)); } /** @test */ diff --git a/tests/SendEmailsCommandTest.php b/tests/SendEmailsCommandTest.php index 21770bd..486f0e8 100644 --- a/tests/SendEmailsCommandTest.php +++ b/tests/SendEmailsCommandTest.php @@ -39,8 +39,6 @@ public function an_email_should_not_be_sent_once_it_is_marked_as_sent() $this->assertNotNull($firstSend = $email->fresh()->getSendDate()); - sleep(1); - $this->artisan('email:send'); $this->assertEquals(1, $email->fresh()->getAttempts()); @@ -50,14 +48,14 @@ public function an_email_should_not_be_sent_once_it_is_marked_as_sent() /** @test */ public function if_an_email_fails_to_be_sent_it_should_be_logged_in_the_database() { - $this->app['config']['mail.driver'] = 'does-not-exist'; - $email = $this->sendEmail(); + $email->update(['recipient' => 'asdf']); + $this->artisan('email:send'); $this->assertTrue($email->fresh()->hasFailed()); - $this->assertStringContains('Driver [does-not-exist] not supported.', $email->fresh()->getError()); + $this->assertStringContains('Swift_RfcComplianceException', $email->fresh()->getError()); } /** @test */ diff --git a/tests/SenderTest.php b/tests/SenderTest.php index 9d9f54d..504154b 100644 --- a/tests/SenderTest.php +++ b/tests/SenderTest.php @@ -24,8 +24,7 @@ public function it_sends_an_email() { $this->sendEmail(); - Mail::shouldReceive('send') - ->once(); + Mail::shouldReceive('send')->once(); $this->artisan('email:send'); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 01b8e2a..a2ddf40 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -92,6 +92,8 @@ protected function getEnvironmentSetUp($app) 'prefix' => '', 'strict' => true, ]); + + $app['config']->set('mail.driver', 'log'); } public function createEmail($overwrite = [])