Skip to content

Commit

Permalink
feat: add Laravel 10 support
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Requires Laravel v10 or above

fix: phpstan ignore mocks

fix: add missing package

test: add test with attachments included

ci: only run supported versions of php

chore: clean up

fix: change method to set attachment headers

ci: change phpunit schema in runtime

fix: fix typing

fix: include phpunit and phpstan in composer.json

ci: update workflow

build: basic docker compose for local development

feat: Laravel 10 compatability
  • Loading branch information
albinhallen authored and adamczykpiotr committed Oct 8, 2024
1 parent a1f3a95 commit 9084df7
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 69 deletions.
45 changes: 14 additions & 31 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,19 @@ name: CI(PhpStan -> PhpUnit)

on:
pull_request:
branches:
- "*"
schedule:
- cron: '0 0 * * *'

jobs:
phpstan:
runs-on: ubuntu-latest
if: (!contains(github.event.head_commit.message, '[skip ci]'))
steps:
- uses: actions/checkout@v2
- uses: php-actions/composer@v6
- uses: php-actions/phpstan@v3
with:
memory_limit: 512M
configuration: ./phpstan.neon

php-tests:
if: (!contains(github.event.head_commit.message, '[skip ci]'))
needs: [phpstan]
strategy:
matrix:
os: [ubuntu-latest]
php: [8.1, 8.0, 7.4]
laravel: [7.*, 8.*, 9.*]
php: [8.1, 8.2, 8.3]
laravel: [10.*]
dependency-version: [prefer-lowest, prefer-stable]
include:
- laravel: 9.*
testbench: 7.*
- laravel: 8.*
testbench: 6.23
- laravel: 7.*
testbench: 5.*
exclude:
- laravel: 9.*
php: 7.4
# https://bytexd.com/fix-laravel-return-type-of-illuminatesupportcollectionoffsetexistskey/
- laravel: 7.*
php: 8.1
- laravel: 10.*
testbench: 8.*

runs-on: ${{ matrix.os }}

Expand All @@ -55,4 +29,13 @@ jobs:
coverage: none
- run: composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update --dev
- run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction
- run: vendor/bin/phpunit
- run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

- name: Static analysis
run: vendor/bin/phpstan --memory-limit=512M analyze

- name: Migrate phpunit schema
run: vendor/bin/phpunit --migrate-configuration

- name: Unit testing
run: vendor/bin/phpunit
13 changes: 9 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@
}
},
"require-dev": {
"orchestra/testbench": "^6.0"
"orchestra/testbench": "^8.0",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^10.0",
"spatie/temporary-directory": "^2.2"
},
"require": {
"php": "^7.3|^8.0",
"guzzlehttp/guzzle": "^7.0"
"php": "^8.1|^8.2|^8.3",
"guzzlehttp/guzzle": "^7.0",
"illuminate/contracts": "^10.0",
"symfony/mailer": "^6.2"
}
}
}
25 changes: 25 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
services:
php:
image: php:8.3-fpm # Or any other version you want
volumes:
- ./:/var/www/html # Mount the current directory to the container
working_dir: /var/www/html
ports:
- "8088:80"
depends_on:
- composer
networks:
- newsletter-driver-network

composer:
image: composer:latest
volumes:
- ./:/var/www/html # Same mount so composer can install dependencies
working_dir: /var/www/html
networks:
- newsletter-driver-network
entrypoint: ['composer']

networks:
newsletter-driver-network:
driver: bridge
80 changes: 46 additions & 34 deletions src/Transport/NewsletterTransport.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@

use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Mail\Transport\Transport;
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\Exception\TransportException;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Lundalogik\NewsletterDriver\Newsletter\AttachmentModel;
use Lundalogik\NewsletterDriver\Newsletter\SendingDomain;
use Lundalogik\NewsletterDriver\Newsletter\SendTransactionMailArgs;
use Lundalogik\NewsletterDriver\Newsletter\SendTransactionMailBatchArgs;
use Lundalogik\NewsletterDriver\Newsletter\TransactionMail;
use Swift_Mime_Attachment;
use Swift_Mime_SimpleMessage;
use Swift_TransportException;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mailer\SentMessage;

class NewsletterTransport extends Transport
class NewsletterTransport extends AbstractTransport
{
/**
* TransactionMail instance.
*
* @var TransactionMail
*/
protected $api;
protected TransactionMail $api;

/**
* Create a new NewsletterTransport instance.
Expand All @@ -32,53 +33,56 @@ class NewsletterTransport extends Transport
public function __construct(TransactionMail $api)
{
$this->api = $api;

parent::__construct();
}

/**
* {@inheritdoc}
* Send the given message.
* Triggered by parent::send()
*
* @param SentMessage $message
* @return void
*/
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
protected function doSend(SentMessage $message): void
{
$this->beforeSendPerformed($message);

try {
$this->api->sendBatch(
$this->getSendTransactionMailBatchArgs($message)
);
$originalMessage = $message->getOriginalMessage();
if ($originalMessage instanceof Email) {
$this->api->sendBatch(
$this->getSendTransactionMailBatchArgs($message->getEnvelope(), $originalMessage)
);
}
} catch (GuzzleException $e) {
throw new Swift_TransportException(
throw new TransportException(
'Request to Newsletter API failed.',
$e->getCode(),
new Exception($e)
);
}

$this->sendPerformed($message);

return $this->numberOfRecipients($message);
}


/**
* Get the SendTransactionMailBatchArgs from the message
*
* @param Swift_Mime_SimpleMessage $message
* @param Envelope $envelope
* @param Email $message
* @return SendTransactionMailBatchArgs
*/
protected function getSendTransactionMailBatchArgs(Swift_Mime_SimpleMessage $message)
protected function getSendTransactionMailBatchArgs(Envelope $envelope, Email $message): SendTransactionMailBatchArgs
{
$sendTransactionMailArgs = [];

$from = $message->getFrom();

[$fromEmail] = array_keys($from);
[$fromName] = array_values($from);
$fromEmail = $envelope->getSender()->getAddress();
$fromName = $envelope->getSender()->getName();

foreach ($message->getTo() as $toEmail => $toName) {
foreach ($envelope->getRecipients() as $index => $to) {
$sendTransactionMailArgs[] = (new SendTransactionMailArgs())
->to($toEmail, $toName)
->to($to->getAddress(), $to->getName())
->from($fromEmail, $fromName)
->subject($message->getSubject())
->htmlContent($message->getBody());
->htmlContent($message->getHtmlBody());
}

return new SendTransactionMailBatchArgs(
Expand All @@ -90,21 +94,29 @@ protected function getSendTransactionMailBatchArgs(Swift_Mime_SimpleMessage $mes
/**
* Get an array of AttachmentModel from the message
*
* @param Swift_Mime_SimpleMessage $message
* @param Email $message
* @return AttachmentModel[]
*/
protected function buildAttachmentModels(Swift_Mime_SimpleMessage $message)
protected function buildAttachmentModels(Email $message): array
{
return collect($message->getChildren())
->filter(function ($child) {
return $child->getHeaders()->get('content-disposition') !== null;
return collect($message->getAttachments())
->filter(function (DataPart $child) {
return $child->getPreparedHeaders()->get('Content-Disposition') !== null;
})
->map(function (Swift_Mime_Attachment $attachment) {
->map(function (DataPart $attachment) {
return (new AttachmentModel())
->fileData($attachment->getBody())
->fileNameWithExtension($attachment->getFilename())
->mimeType($attachment->getContentType());
})
->toArray();
}

/**
* @return string
*/
public function __toString(): string
{
return "newsletter";
}
}
65 changes: 65 additions & 0 deletions tests/Unit/NewsletterTransportTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Lundalogik\NewsletterDriver\Tests\Unit;

use Lundalogik\NewsletterDriver\Newsletter\SendTransactionMailBatchArgs;
use Lundalogik\NewsletterDriver\Newsletter\TransactionMail;
use PHPUnit\Framework\TestCase;
use Lundalogik\NewsletterDriver\Transport\NewsletterTransport;
use Mockery;
use Spatie\TemporaryDirectory\Exceptions\PathAlreadyExists;
use Spatie\TemporaryDirectory\TemporaryDirectory;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mime\Email;

class NewsletterTransportTest extends TestCase
{

/**
* @throws PathAlreadyExists
* @throws TransportExceptionInterface
*/
public function test_it_can_send_full_email_with_attachments(): void
{
$tempDir = (new TemporaryDirectory())
->deleteWhenDestroyed()
->create();

$tmpPath = $tempDir->path('test.txt');
file_put_contents($tmpPath, 'this is a test');

$message = new Email();
$message->from('[email protected]')
->to('[email protected]')
->subject('Test from laravel-newsletter-driver')
->html("<p>This is a test email from laravel-newsletter-driver</p>")
->attachFromPath($tmpPath, 'test.txt');

$api = Mockery::mock(TransactionMail::class);

/** @phpstan-ignore-next-line */
$api->shouldReceive('sendBatch')
->once()
->with(Mockery::on(function ($args) use ($message) {
$this->assertInstanceOf(SendTransactionMailBatchArgs::class, $args);

$batchArgs = $args->toArray();
$firstBatch = (object) $batchArgs['SendTransactionMailArgs'][0];

$this->assertEquals($firstBatch->RecipientEmail, $message->getTo()[0]->getAddress());
$this->assertEquals($firstBatch->RecipientName, $message->getTo()[0]->getName());
$this->assertEquals($firstBatch->FromEmail, $message->getFrom()[0]->getAddress());
$this->assertEquals($firstBatch->FromName, $message->getFrom()[0]->getName());
$this->assertEquals($firstBatch->Subject, $message->getSubject());
$this->assertNotEmpty($firstBatch->HtmlContent);

$firstBatchAttachments = $batchArgs['BatchAttachments'];
$this->assertEquals('test.txt', $firstBatchAttachments[0]['FileNameWithExtension']);

return 1 === count($batchArgs['SendTransactionMailArgs']);
}))->andReturn();

/** @phpstan-ignore-next-line */
(new NewsletterTransport($api))->send($message);
}
}

0 comments on commit 9084df7

Please sign in to comment.