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.* 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" } } 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/EmailComposer.php b/src/EmailComposer.php index a7d25ff..31e3397 100644 --- a/src/EmailComposer.php +++ b/src/EmailComposer.php @@ -194,6 +194,27 @@ public function later($scheduledAt) return $this->send(); } + /** + * 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, $delay = null) + { + $connection = $connection ?: config('queue.default'); + $queue = $queue ?: 'default'; + + $this->setData('queued', true); + $this->setData('connection', $connection); + $this->setData('queue', $queue); + $this->setData('delay', $delay); + + return $this->send(); + } + /** * Set the Mailable. * @@ -273,6 +294,15 @@ public function send() $this->email->refresh(); + if ($this->getData('queued', false) === true) { + dispatch(new SendEmailJob($this->email)) + ->onConnection($this->getData('connection')) + ->onQueue($this->getData('queue')) + ->delay($this->getData('delay')); + + 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..4ca3070 --- /dev/null +++ b/src/SendEmailJob.php @@ -0,0 +1,27 @@ +email = $email; + } + + public function handle() + { + (new Sender())->send($this->email); + } +} 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 new file mode 100644 index 0000000..340fdb2 --- /dev/null +++ b/tests/QueuedEmailsTest.php @@ -0,0 +1,100 @@ +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 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() + { + 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/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 1565e14..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 = []) @@ -131,6 +133,11 @@ public function scheduleEmail($scheduledFor, $overwrite = []) return $this->createEmail($overwrite)->schedule($scheduledFor); } + public function queueEmail($connection = null, $queue = null, $delay = null, $overwrite = []) + { + return $this->createEmail($overwrite)->queue($connection, $queue, $delay); + } + public function assertStringContains($needle, $haystack) { if (method_exists($this, 'assertStringContainsString')) {