diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
new file mode 100644
index 0000000..811a793
--- /dev/null
+++ b/.github/workflows/run-tests.yml
@@ -0,0 +1,74 @@
+name: Run tests
+
+on:
+ push:
+ schedule:
+ - cron: '0 0 * * *'
+
+jobs:
+ php-tests:
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ matrix:
+ php: [7.4, 7.3, 7.2]
+ laravel: [6.*, 5.8.*, 5.7.*, 5.6.*]
+ os: [ubuntu-latest]
+ include:
+ - laravel: 6.*
+ testbench: 4.*
+ - laravel: 5.8.*
+ testbench: 3.8.*
+ - laravel: 5.7.*
+ testbench: 3.7.*
+ - laravel: 5.6.*
+ testbench: 3.6.*
+ exclude:
+ - laravel: 5.7.*
+ php: 7.4
+ - laravel: 5.6.*
+ php: 7.4
+ - laravel: 5.5.*
+ php: 7.4
+
+ name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
+
+ services:
+ mysql:
+ image: mysql:5.7.27
+ env:
+ MYSQL_USER: root
+ MYSQL_ROOT_PASSWORD: root
+ MYSQL_PASSWORD:
+ MYSQL_ALLOW_EMPTY_PASSWORD: true
+ MYSQL_DATABASE: test
+ ports:
+ - 3307:3306
+ volumes:
+ - $HOME/mysql:/var/lib/mysql
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v1
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v1
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: mbstring, dom, fileinfo, mysql
+ coverage: none
+
+ - name: Install dependencies
+ run: |
+ composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
+ composer update --prefer-stable --prefer-dist --no-interaction --no-suggest
+ - name: Execute tests
+ env:
+ CI_DB_DRIVER: mysql
+ CI_DB_HOST: 127.0.0.1
+ CI_DB_PORT: 3307
+ CI_DB_DATABASE: test
+ CI_DB_USERNAME: root
+ CI_DB_PASSWORD: root
+ run: vendor/bin/phpunit
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b3aec00..4218a0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
vendor/
.DS_Store
composer.lock
+.phpunit.result.cache
\ No newline at end of file
diff --git a/.styleci.yml b/.styleci.yml
deleted file mode 100644
index 6894532..0000000
--- a/.styleci.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-preset: laravel
-
-enabled:
- - concat_with_spaces
-
-disabled:
- - concat_without_spaces
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 545e6f9..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-language: php
-
-sudo: false
-
-services:
- - mysql
-
-matrix:
- fast_finish: true
- include:
- # SQLite
- - php: 7.0
- env: CI_DB_DRIVER="sqlite" CI_DB_DATABASE=":memory:"
- - php: 7.1
- env: CI_DB_DRIVER="sqlite" CI_DB_DATABASE=":memory:"
- # MySQL 5.7
- - php: 7.0
- env: CI_DB_DRIVER="mysql" CI_DB_HOST="127.0.0.1" CI_DB_DATABASE="travis" CI_DB_USERNAME="root"
- - php: 7.1
- env: CI_DB_DRIVER="mysql" CI_DB_HOST="127.0.0.1" CI_DB_DATABASE="travis" CI_DB_USERNAME="root"
- # MariaDB
- - php: 7.0
- env: CI_DB_DRIVER="mysql" CI_DB_HOST="127.0.0.1" CI_DB_DATABASE="travis" CI_DB_USERNAME="root"
- addons:
- mariadb: 10.0
- - php: 7.1
- env: CI_DB_DRIVER="mysql" CI_DB_HOST="127.0.0.1" CI_DB_DATABASE="travis" CI_DB_USERNAME="root"
- addons:
- mariadb: 10.0
-
-install: travis_retry composer install --no-interaction --prefer-source
-
-script:
- - mysql --version
- - vendor/bin/phpunit --verbose
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 953843e..1037001 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 4.1.1 - 2020-01-11
+
+**Fixed**
+
+- Fixed inline attachments could not be stored
+- Fixed PHP 7.4 issue when reading empty Mailable from address
+
## 4.1.0 - 2019-07-13
**Added**
diff --git a/README.md b/README.md
index 98a5d9c..8d1ae45 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-
+
diff --git a/composer.json b/composer.json
index 1e4e728..c505a69 100644
--- a/composer.json
+++ b/composer.json
@@ -25,14 +25,13 @@
]
}
},
+ "require": {
+ "ext-json": "*"
+ },
"require-dev": {
- "illuminate/database": "5.5.*",
- "illuminate/console": "5.5.*",
- "illuminate/validation": "5.5.*",
- "orchestra/testbench": "^3.5",
- "orchestra/database": "^3.5",
- "phpunit/phpunit": "^6.0",
- "mockery/mockery": "^1.0",
- "dompdf/dompdf": "^0.8.2"
+ "mockery/mockery": "^1.2",
+ "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0",
+ "symfony/console": "^4.4",
+ "tecnickcom/tcpdf": "^6.3"
}
}
diff --git a/src/HasEncryptedAttributes.php b/src/HasEncryptedAttributes.php
index ce782ac..a73984d 100644
--- a/src/HasEncryptedAttributes.php
+++ b/src/HasEncryptedAttributes.php
@@ -32,7 +32,6 @@ trait HasEncryptedAttributes
'cc',
'bcc',
'variables',
- 'attachments',
];
/**
@@ -61,6 +60,25 @@ public function getAttribute($key)
}
}
+ // BC fix for attachments in 4.1.0 and lower.
+ // Attachments were stored json encoded.
+ // Because this doesn't work for raw attachments, value is now serialized.
+ // Check if value is json encoded or serialized, and decode or unserialize accordingly.
+ if ($key == 'attachments') {
+ if (substr($value, 0, 2) === 'a:') {
+ $unserialized = @unserialize($value);
+ if ($value !== false) {
+ $value = $unserialized;
+ }
+ } else {
+ $decoded = json_decode($value, true);
+
+ if (! is_null($decoded)) {
+ $value = $decoded;
+ }
+ }
+ }
+
return $value;
}
}
diff --git a/src/MailableReader.php b/src/MailableReader.php
index a8f35da..38c4872 100644
--- a/src/MailableReader.php
+++ b/src/MailableReader.php
@@ -68,6 +68,10 @@ private function readFrom(EmailComposer $composer)
{
$from = reset($composer->getData('mailable')->from);
+ if (!$from) {
+ return;
+ }
+
$composer->from(
$from['address'],
$from['name']
diff --git a/src/Preparer.php b/src/Preparer.php
index b4e98fd..e2fba6b 100644
--- a/src/Preparer.php
+++ b/src/Preparer.php
@@ -198,7 +198,7 @@ private function prepareAttachments(EmailComposer $composer)
}
$composer->getEmail()->fill([
- 'attachments' => json_encode($attachments),
+ 'attachments' => serialize($attachments),
]);
}
diff --git a/tests/DatabaseInteractionTest.php b/tests/DatabaseInteractionTest.php
index 2f65045..034fc4c 100644
--- a/tests/DatabaseInteractionTest.php
+++ b/tests/DatabaseInteractionTest.php
@@ -2,8 +2,9 @@
namespace Tests;
-use Dompdf\Dompdf;
+use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
+use TCPDF;
class DatabaseInteractionTest extends TestCase
{
@@ -85,9 +86,10 @@ public function scheduled_date_should_be_saved_correctly()
$this->assertNull(DB::table('emails')->find(1)->scheduled_at);
$this->assertNull($email->getScheduledDate());
+ Carbon::setTestNow(Carbon::create(2019, 1, 1, 1, 2, 3));
$email = $this->scheduleEmail('+2 weeks');
$this->assertNotNull(DB::table('emails')->find(2)->scheduled_at);
- $this->assertEquals(date('Y-m-d H:i:s', strtotime('+2 weeks')), $email->getScheduledDate());
+ $this->assertEquals('2019-01-15 01:02:03', $email->getScheduledDate());
}
/** @test */
@@ -156,7 +158,9 @@ public function attempts_should_be_zero()
/** @test */
public function the_scheduled_date_should_be_saved_correctly()
{
- $scheduledFor = date('Y-m-d H:i:s', strtotime('+2 weeks'));
+ Carbon::setTestNow(Carbon::now());
+
+ $scheduledFor = date('Y-m-d H:i:s', Carbon::now()->addWeek(2)->timestamp);
$email = $this->scheduleEmail('+2 weeks');
@@ -205,12 +209,13 @@ public function attachments_should_be_saved_correctly()
/** @test */
public function in_memory_attachments_should_be_saved_correctly()
{
- $pdf = new Dompdf;
- $pdf->loadHtml('Hello CI!');
- $pdf->setPaper('A4', 'landscape');
+ $pdf = new TCPDF;
+ $pdf->Write(0, 'Hello CI!');
+
+ $rawData = $pdf->Output('generated.pdf', 'S');
$email = $this->composeEmail()
- ->attachData($pdf->outputHtml(), 'generated.pdf', [
+ ->attachData($rawData, 'generated.pdf', [
'mime' => 'application/pdf',
])
->send();
@@ -218,6 +223,6 @@ public function in_memory_attachments_should_be_saved_correctly()
$this->assertCount(1, $email->getAttachments());
$this->assertEquals('rawAttachment', $email->getAttachments()[0]['type']);
- $this->assertEquals($pdf->outputHtml(), $email->getAttachments()[0]['attachment']['data']);
+ $this->assertEquals(md5($rawData), md5($email->getAttachments()[0]['attachment']['data']));
}
}
diff --git a/tests/EncryptionTest.php b/tests/EncryptionTest.php
index c4087e2..d023c88 100644
--- a/tests/EncryptionTest.php
+++ b/tests/EncryptionTest.php
@@ -4,7 +4,7 @@
class EncryptionTest extends TestCase
{
- public function setUp()
+ public function setUp(): void
{
parent::setUp();
diff --git a/tests/SendEmailsCommandTest.php b/tests/SendEmailsCommandTest.php
index fbbf3fd..21770bd 100644
--- a/tests/SendEmailsCommandTest.php
+++ b/tests/SendEmailsCommandTest.php
@@ -37,7 +37,9 @@ public function an_email_should_not_be_sent_once_it_is_marked_as_sent()
$this->artisan('email:send');
- $this->assertEquals($firstSend = date('Y-m-d H:i:s'), $email->fresh()->getSendDate());
+ $this->assertNotNull($firstSend = $email->fresh()->getSendDate());
+
+ sleep(1);
$this->artisan('email:send');
@@ -55,7 +57,7 @@ public function if_an_email_fails_to_be_sent_it_should_be_logged_in_the_database
$this->artisan('email:send');
$this->assertTrue($email->fresh()->hasFailed());
- $this->assertContains('Driver [does-not-exist] not supported.', $email->fresh()->getError());
+ $this->assertStringContains('Driver [does-not-exist] not supported.', $email->fresh()->getError());
}
/** @test */
diff --git a/tests/SenderTest.php b/tests/SenderTest.php
index cd16a0e..9d9f54d 100644
--- a/tests/SenderTest.php
+++ b/tests/SenderTest.php
@@ -2,18 +2,17 @@
namespace Tests;
-use Dompdf\Dompdf;
use Swift_Events_SendEvent;
use Illuminate\Support\Facades\Mail;
use Stackkit\LaravelDatabaseEmails\Email;
-use Stackkit\LaravelDatabaseEmails\Config;
+use TCPDF;
class SenderTest extends TestCase
{
/** @var Swift_Events_SendEvent[] */
public $sent = [];
- public function setUp()
+ public function setUp(): void
{
parent::setUp();
@@ -194,12 +193,13 @@ public function attachments_are_not_added_if_the_data_is_not_valid()
/** @test */
public function raw_attachments_are_added_to_the_email()
{
- $pdf = new Dompdf;
- $pdf->loadHtml('Hello CI!');
- $pdf->setPaper('A4');
+ $pdf = new TCPDF;
+ $pdf->Write(0, 'Hello CI!');
+
+ $rawData = $pdf->Output('generated.pdf', 'S');
$this->composeEmail()
- ->attachData($pdf->outputHtml(), 'hello-ci.pdf', [
+ ->attachData($rawData, 'hello-ci.pdf', [
'mime' => 'application/pdf',
])
->send();
@@ -211,7 +211,22 @@ public function raw_attachments_are_added_to_the_email()
$this->assertCount(1, $attachments);
$this->assertEquals('attachment; filename=hello-ci.pdf', $attachment->getHeaders()->get('content-disposition')->getFieldBody());
$this->assertEquals('application/pdf', $attachment->getContentType());
- $this->assertContains('Hello CI!', $attachment->getBody());
+ $this->assertTrue(md5($attachment->getBody()) == md5($rawData));
+ }
+
+ /** @test */
+ public function old_json_encoded_attachments_can_still_be_read()
+ {
+ $email = $this->sendEmail();
+ $email->attachments = json_encode([1, 2, 3]);
+ $email->save();
+
+ $this->assertEquals([1, 2, 3], $email->fresh()->getAttachments());
+
+ $email->attachments = serialize([4, 5, 6]);
+ $email->save();
+
+ $this->assertEquals([4, 5, 6], $email->fresh()->getAttachments());
}
/** @test */
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 1e7aa16..1565e14 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -9,7 +9,7 @@ class TestCase extends \Orchestra\Testbench\TestCase
{
protected $invalid;
- public function setUp()
+ public function setUp(): void
{
parent::setUp();
@@ -25,10 +25,10 @@ function () {
},
];
- $this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
-
view()->addNamespace('tests', __DIR__ . '/views');
+ $this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
+
Email::truncate();
}
@@ -65,7 +65,6 @@ protected function schema()
protected function getPackageProviders($app)
{
return [
- \Orchestra\Database\ConsoleServiceProvider::class,
\Stackkit\LaravelDatabaseEmails\LaravelDatabaseEmailsServiceProvider::class,
];
}
@@ -86,6 +85,7 @@ protected function getEnvironmentSetUp($app)
$app['config']->set('database.connections.testbench', [
'driver' => getenv('CI_DB_DRIVER'),
'host' => getenv('CI_DB_HOST'),
+ 'port' => getenv('CI_DB_PORT'),
'database' => getenv('CI_DB_DATABASE'),
'username' => getenv('CI_DB_USERNAME'),
'password' => getenv('CI_DB_PASSWORD'),
@@ -130,4 +130,13 @@ public function scheduleEmail($scheduledFor, $overwrite = [])
{
return $this->createEmail($overwrite)->schedule($scheduledFor);
}
+
+ public function assertStringContains($needle, $haystack)
+ {
+ if (method_exists($this, 'assertStringContainsString')) {
+ $this->assertStringContainsString($needle, $haystack);
+ } else {
+ $this->assertContains($needle, $haystack);
+ }
+ }
}
diff --git a/tests/ValidatorTest.php b/tests/ValidatorTest.php
index beca390..0646c70 100644
--- a/tests/ValidatorTest.php
+++ b/tests/ValidatorTest.php
@@ -8,59 +8,54 @@
class ValidatorTest extends TestCase
{
- /**
- * @test
- * @expectedException InvalidArgumentException
- */
+ /** @test */
public function a_label_cannot_contain_more_than_255_characters()
{
+ $this->expectException(InvalidArgumentException::class);
+
Email::compose()
->label(str_repeat('a', 256))
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage No recipient specified
- */
+ /** @test */
public function a_recipient_is_required()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('No recipient specified');
+
Email::compose()
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage No recipient specified
- */
+ /** @test */
public function a_recipient_cannot_be_empty()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('No recipient specified');
+
Email::compose()
->recipient([])
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage E-mail address [not-a-valid-email-address] is invalid
- */
+ /** @test */
public function the_recipient_email_must_be_valid()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('E-mail address [not-a-valid-email-address] is invalid');
+
Email::compose()
->recipient('not-a-valid-email-address')
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage E-mail address [not-a-valid-email-address] is invalid
- */
+ /** @test */
public function cc_must_contain_valid_email_addresses()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('E-mail address [not-a-valid-email-address] is invalid');
+
Email::compose()
->recipient('john@doe.com')
->cc([
@@ -70,13 +65,12 @@ public function cc_must_contain_valid_email_addresses()
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage E-mail address [not-a-valid-email-address] is invalid
- */
+ /** @test */
public function bcc_must_contain_valid_email_addresses()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('E-mail address [not-a-valid-email-address] is invalid');
+
Email::compose()
->recipient('john@doe.com')
->bcc([
@@ -86,25 +80,23 @@ public function bcc_must_contain_valid_email_addresses()
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage No subject specified
- */
+ /** @test */
public function a_subject_is_required()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('No subject specified');
+
Email::compose()
->recipient('john@doe.com')
->send();
}
- /**
- * @test
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage No view specified
- */
+ /** @test */
public function a_view_is_required()
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('No view specified');
+
Email::compose()
->recipient('john@doe.com')
->subject('test')