From 153bf13c9f9f95a029383cf40c6f2676e1ef5494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20St=C5=99=C3=ADbrn=C3=BD?= Date: Wed, 26 Jul 2017 10:09:30 +0200 Subject: [PATCH 1/5] Implement BackgroundQueueMailer --- composer.json | 8 ++++++- src/Mailer.php | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/Mailer.php diff --git a/composer.json b/composer.json index 2a299ee..b8ab8e2 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,12 @@ }, "minimum-stability": "stable", "require": { - "adt/background-queue": "^3.1" + "adt/background-queue": "^3.1", + "tracy/tracy": "^2.3" + }, + "autoload": { + "psr-4": { + "ADT\\Mail\\BackgroundQueueMailer\\": "src/" + } } } diff --git a/src/Mailer.php b/src/Mailer.php new file mode 100644 index 0000000..a5e215b --- /dev/null +++ b/src/Mailer.php @@ -0,0 +1,60 @@ +next = $next; + $this->backgroundQueueService = $backgroundQueueService; + $this->callbackName = $callbackName; + } + + public function send(Mail\Message $mail) { + $entity = new BackgroundQueue\Entity\QueueEntity; + $entity->setCallbackName($this->callbackName); + $entity->setParameters([ + 'mail' => json_encode(serialize($mail)), + ]); + + $this->backgroundQueueService + ->publish($entity); + } + + public function process(BackgroundQueue\Entity\QueueEntity $entity) { + if ($entity->getCallbackName() !== $this->callbackName) { + Debugger::log("Callback names do not match, expected: '{$this->callbackName}' but got: '{$entity->getCallbackName()}'; skipping'", Debugger::WARNING); + return FALSE; // repeatable error + } + + $mail = unserialize(json_decode($entity->getParameters()['mail'])); + + try { + $this->next->send($mail); + return TRUE; // done + } catch (Mail\SendException $e) { + return FALSE; // repeatable error + } + + // everything else is unrepeatable error (logged in BackgroundQueue) + } + +} \ No newline at end of file From 8caab2a52c8dadaf23287fc04b4e490b2347ac8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20St=C5=99=C3=ADbrn=C3=BD?= Date: Wed, 26 Jul 2017 10:09:37 +0200 Subject: [PATCH 2/5] Add readme --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..9066e96 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# BackgroundQueueMailer + +Delegates sending emails to [adt/background-queue](https://github.com/AppsDevTeam/BackgroundQueue). + +## Installation +composer: +``` +composer require adt/background-queue-mailer +``` + +If you're not familiar with [adt/background-queue](https://github.com/AppsDevTeam/BackgroundQueue), +you should head there in the first place. + +## Usage + +To use BackgroundQueueMailer as buffer between your application and SmtpMailer, register +it in your `config.neon`: + +```neon +services: + smtpMailer: + class: \Nette\Mail\SmtpMailer + autowired: no # this is important + + nette.mailer: \ADT\Mail\BackgroundQueueMailer(@smtpMailer, @backgroundQueue.service, 'backgroundMail') + +backgroundQueue: + callbacks: + backgroundMail: @nette.mailer::process +``` + +where `@smtpMailer` is outgoing mailer, `@backgroundQueue.service` is dependency on BackgroundQueue, +and `backgroundMail` is unique callback name. + +Callback name has to be same in both mailer definition and BackgroundQueue callback list. If they +are not, warning is logged using Tracy. This should get resolved [here](https://github.com/AppsDevTeam/BackgroundQueue/issues/8). + +The `autowired: no` option is important because Nette DI container would not know +which `\Nette\Mail\IMailer` to inject in your application. By setting `autowired: no` on +SMTP mailer only one instance of `IMailer` interface remains. + +You cannot set `autowired: no` on `nette.mailer` because your application +would not be able to inject it. + +It is also important that you autowire `\Nette\Mail\IMailer` throughout your application. \ No newline at end of file From 2dc6839e2cbfe2ba9f9f25b554aecd93ab6d1c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20St=C5=99=C3=ADbrn=C3=BD?= Date: Wed, 26 Jul 2017 10:13:50 +0200 Subject: [PATCH 3/5] Add JSON encoding comment --- src/Mailer.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mailer.php b/src/Mailer.php index a5e215b..155e2a0 100644 --- a/src/Mailer.php +++ b/src/Mailer.php @@ -32,6 +32,8 @@ public function send(Mail\Message $mail) { $entity = new BackgroundQueue\Entity\QueueEntity; $entity->setCallbackName($this->callbackName); $entity->setParameters([ + // Parameters are stored as LONGTEXT, so they cannot contain binary data. + // This should be fine if we encode mail as JSON. 'mail' => json_encode(serialize($mail)), ]); From 9607b063e0e4312d037b2ad38dc88b899c74ff83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20St=C5=99=C3=ADbrn=C3=BD?= Date: Wed, 26 Jul 2017 10:17:32 +0200 Subject: [PATCH 4/5] Use safer JSON encoding/decoding --- src/Mailer.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Mailer.php b/src/Mailer.php index 155e2a0..c10aba3 100644 --- a/src/Mailer.php +++ b/src/Mailer.php @@ -4,6 +4,7 @@ use ADT\BackgroundQueue; use Nette\Mail; +use Nette\Utils\JSON; use Tracy\Debugger; @@ -32,9 +33,9 @@ public function send(Mail\Message $mail) { $entity = new BackgroundQueue\Entity\QueueEntity; $entity->setCallbackName($this->callbackName); $entity->setParameters([ - // Parameters are stored as LONGTEXT, so they cannot contain binary data. + // Parameters are stored as LONGTEXT UTF-8, so they cannot contain binary data. // This should be fine if we encode mail as JSON. - 'mail' => json_encode(serialize($mail)), + 'mail' => JSON::encode(serialize($mail)), ]); $this->backgroundQueueService @@ -47,7 +48,8 @@ public function process(BackgroundQueue\Entity\QueueEntity $entity) { return FALSE; // repeatable error } - $mail = unserialize(json_decode($entity->getParameters()['mail'])); + $parameters = $entity->getParameters(); + $mail = unserialize(JSON::decode($parameters['mail'])); try { $this->next->send($mail); From d8f0914e02134c48ab780da9c00f73e76a445a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20St=C5=99=C3=ADbrn=C3=BD?= Date: Wed, 26 Jul 2017 10:32:33 +0200 Subject: [PATCH 5/5] Swap callbackName and backgroundQueueService arguments to allow autowiring --- README.md | 5 ++--- src/Mailer.php | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9066e96..5d9616c 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,14 @@ services: class: \Nette\Mail\SmtpMailer autowired: no # this is important - nette.mailer: \ADT\Mail\BackgroundQueueMailer(@smtpMailer, @backgroundQueue.service, 'backgroundMail') + nette.mailer: \ADT\Mail\BackgroundQueueMailer(@smtpMailer, 'backgroundMail') backgroundQueue: callbacks: backgroundMail: @nette.mailer::process ``` -where `@smtpMailer` is outgoing mailer, `@backgroundQueue.service` is dependency on BackgroundQueue, -and `backgroundMail` is unique callback name. +where `@smtpMailer` is outgoing mailer, and `backgroundMail` is unique callback name. Callback name has to be same in both mailer definition and BackgroundQueue callback list. If they are not, warning is logged using Tracy. This should get resolved [here](https://github.com/AppsDevTeam/BackgroundQueue/issues/8). diff --git a/src/Mailer.php b/src/Mailer.php index c10aba3..28b33d5 100644 --- a/src/Mailer.php +++ b/src/Mailer.php @@ -13,20 +13,20 @@ class Mailer extends \Nette\Object implements Mail\IMailer { /** @var Mail\IMailer */ protected $next; - /** @var BackgroundQueue\Service */ - protected $backgroundQueueService; - /** @var string */ protected $callbackName; + /** @var BackgroundQueue\Service */ + protected $backgroundQueueService; + public function __construct( Mail\IMailer $next, - BackgroundQueue\Service $backgroundQueueService, - $callbackName + $callbackName, + BackgroundQueue\Service $backgroundQueueService ) { $this->next = $next; - $this->backgroundQueueService = $backgroundQueueService; $this->callbackName = $callbackName; + $this->backgroundQueueService = $backgroundQueueService; } public function send(Mail\Message $mail) {