From 925a8bb4a7a9200adade54f92995e56aa0bfcf70 Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Mon, 11 Jan 2016 00:24:10 -0600 Subject: [PATCH] added email sender for sendgrid --- composer.json | 3 +- composer.lock | 409 +++++++++++------- .../src/travi/framework/email/EmailSender.php | 28 +- .../travi/framework/email/SendGridMapper.php | 43 ++ .../travi/framework/email/SendGridSender.php | 50 +++ .../travi/framework/email/SendMailSender.php | 39 +- test/php/unit/email/SendGridMapperTest.php | 62 +++ test/php/unit/email/SendGridSenderTest.php | 77 ++++ test/php/unit/email/SendMailSenderTest.php | 14 +- 9 files changed, 532 insertions(+), 193 deletions(-) create mode 100644 php/framework/src/travi/framework/email/SendGridMapper.php create mode 100644 php/framework/src/travi/framework/email/SendGridSender.php create mode 100644 test/php/unit/email/SendGridMapperTest.php create mode 100644 test/php/unit/email/SendGridSenderTest.php diff --git a/composer.json b/composer.json index 82fe467a..2232d24e 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "require": { "smarty/smarty": "3.1.27", "html2text/html2text": "1.0.0", - "mustangostang/spyc": "0.5.1" + "mustangostang/spyc": "0.5.1", + "sendgrid/sendgrid": "^4.0" }, "require-dev": { "phpunit/phpunit": "4.4.*", diff --git a/composer.lock b/composer.lock index 4c94c987..59786d3c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,104 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "acbae90e8890df7a1c0be6b5326b79ae", - "content-hash": "00b492686f97aa38407756925d8811e9", + "hash": "f28b55105cf043605618bf3f525a660e", + "content-hash": "5e34275be09f2bdb839c08a724258911", "packages": [ + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-03-18 18:23:50" + }, { "name": "html2text/html2text", "version": "1.0.0", @@ -84,6 +179,101 @@ ], "time": "2013-02-21 10:52:01" }, + { + "name": "sendgrid/sendgrid", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sendgrid/sendgrid-php.git", + "reference": "ebf68af9d4158450b6d673bf6d31ff5297057882" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sendgrid/sendgrid-php/zipball/ebf68af9d4158450b6d673bf6d31ff5297057882", + "reference": "ebf68af9d4158450b6d673bf6d31ff5297057882", + "shasum": "" + }, + "require": { + "guzzle/guzzle": "~3.9", + "php": ">=5.3", + "sendgrid/smtpapi": "~0.5" + }, + "replace": { + "sendgrid/sendgrid-php": "*" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.4", + "vlucas/phpdotenv": "~1.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "SendGrid": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "This library allows you to quickly and easily send emails through SendGrid using PHP.", + "homepage": "http://github.com/sendgrid/sendgrid-php", + "keywords": [ + "email", + "grid", + "send", + "sendgrid" + ], + "time": "2015-12-15 17:04:40" + }, + { + "name": "sendgrid/smtpapi", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/sendgrid/smtpapi-php.git", + "reference": "05ccf57bad5d1524e479b6dc0a2dfade88b3fbe5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sendgrid/smtpapi-php/zipball/05ccf57bad5d1524e479b6dc0a2dfade88b3fbe5", + "reference": "05ccf57bad5d1524e479b6dc0a2dfade88b3fbe5", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "replace": { + "sendgrid/smtpapi-php": "*" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Smtpapi": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Build SendGrid X-SMTPAPI headers in PHP.", + "homepage": "http://github.com/sendgrid/smtpapi-php", + "keywords": [ + "X-SMTP", + "api", + "email", + "grid", + "send", + "sendgrid", + "smtp", + "smtpapi", + "xsmtp" + ], + "time": "2015-04-14 02:37:45" + }, { "name": "smarty/smarty", "version": "v3.1.27", @@ -138,6 +328,66 @@ "templating" ], "time": "2015-06-18 00:55:59" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc", + "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2015-10-30 20:15:42" } ], "packages-dev": [ @@ -318,101 +568,6 @@ ], "time": "2015-06-14 21:17:01" }, - { - "name": "guzzle/guzzle", - "version": "v3.9.3", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle3.git", - "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", - "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "php": ">=5.3.3", - "symfony/event-dispatcher": "~2.1" - }, - "replace": { - "guzzle/batch": "self.version", - "guzzle/cache": "self.version", - "guzzle/common": "self.version", - "guzzle/http": "self.version", - "guzzle/inflection": "self.version", - "guzzle/iterator": "self.version", - "guzzle/log": "self.version", - "guzzle/parser": "self.version", - "guzzle/plugin": "self.version", - "guzzle/plugin-async": "self.version", - "guzzle/plugin-backoff": "self.version", - "guzzle/plugin-cache": "self.version", - "guzzle/plugin-cookie": "self.version", - "guzzle/plugin-curlauth": "self.version", - "guzzle/plugin-error-response": "self.version", - "guzzle/plugin-history": "self.version", - "guzzle/plugin-log": "self.version", - "guzzle/plugin-md5": "self.version", - "guzzle/plugin-mock": "self.version", - "guzzle/plugin-oauth": "self.version", - "guzzle/service": "self.version", - "guzzle/stream": "self.version" - }, - "require-dev": { - "doctrine/cache": "~1.3", - "monolog/monolog": "~1.0", - "phpunit/phpunit": "3.7.*", - "psr/log": "~1.0", - "symfony/class-loader": "~2.1", - "zendframework/zend-cache": "2.*,<2.3", - "zendframework/zend-log": "2.*,<2.3" - }, - "suggest": { - "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.9-dev" - } - }, - "autoload": { - "psr-0": { - "Guzzle": "src/", - "Guzzle\\Tests": "tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Guzzle Community", - "homepage": "https://github.com/guzzle/guzzle/contributors" - } - ], - "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "time": "2015-03-18 18:23:50" - }, { "name": "pdepend/pdepend", "version": "2.0.6", @@ -1763,66 +1918,6 @@ "homepage": "https://symfony.com", "time": "2015-12-26 13:37:56" }, - { - "name": "symfony/event-dispatcher", - "version": "v2.8.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc", - "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0,>=2.0.5|~3.0.0", - "symfony/dependency-injection": "~2.6|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/stopwatch": "~2.3|~3.0.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2015-10-30 20:15:42" - }, { "name": "symfony/filesystem", "version": "v3.0.1", diff --git a/php/framework/src/travi/framework/email/EmailSender.php b/php/framework/src/travi/framework/email/EmailSender.php index 8292d002..55eac014 100644 --- a/php/framework/src/travi/framework/email/EmailSender.php +++ b/php/framework/src/travi/framework/email/EmailSender.php @@ -2,7 +2,7 @@ namespace travi\framework\email; -abstract class EmailSender +interface EmailSender { /** * @param $to @@ -10,32 +10,10 @@ abstract class EmailSender * @param $subject * @param $content */ - public function send($to, $from, $subject, $content) - { - $this->mail($to, $subject, $content, $this->formatFromHeader($from)); - } + public function send($to, $from, $subject, $content); /** * @param $email Email */ - public function sendEmail($email) - { - $this->mail( - $email->getTo()->getAddress(), - $email->getSubject(), - $email->getMessage(), - $this->formatFromHeader($email->getFrom()) - ); - } - - protected abstract function mail($to, $subject, $message, $headers); - - /** - * @param $from - * @return string - */ - private function formatFromHeader($from) - { - return "From: " . $from->getName() . " <" . $from->getAddress() . ">"; - } + public function sendEmail($email); } \ No newline at end of file diff --git a/php/framework/src/travi/framework/email/SendGridMapper.php b/php/framework/src/travi/framework/email/SendGridMapper.php new file mode 100644 index 00000000..46451f54 --- /dev/null +++ b/php/framework/src/travi/framework/email/SendGridMapper.php @@ -0,0 +1,43 @@ +addTo($to) + ->setFrom($from->getAddress()) + ->setFromName($from->getName()) + ->setSubject($subject) + ->setText($message); + + return $email; + } + + /** + * @param $email Email + * @return \SendGrid\Email + */ + public function mapEmail($email) + { + $sendGridEmail = new \SendGrid\Email(); + $sendGridEmail->addTo($email->getTo()->getAddress()) + ->setFrom($email->getFrom()->getAddress()) + ->setFromName($email->getFrom()->getName()) + ->setSubject($email->getSubject()) + ->setText($email->getMessage()); + + return $sendGridEmail; + } +} \ No newline at end of file diff --git a/php/framework/src/travi/framework/email/SendGridSender.php b/php/framework/src/travi/framework/email/SendGridSender.php new file mode 100644 index 00000000..b1c85e92 --- /dev/null +++ b/php/framework/src/travi/framework/email/SendGridSender.php @@ -0,0 +1,50 @@ +sendgrid->send($this->mapper->mapParameters($to, $from, $subject, $content)); + } + + /** + * @param $email Email + */ + public function sendEmail($email) + { + $this->sendgrid->send($this->mapper->mapEmail($email)); + } + + /** + * @PdInject new:travi\framework\email\SendGridMapper + * @param $mapper + */ + public function setMapper($mapper) + { + $this->mapper = $mapper; + } + + /** + * @PdInject SendGridInstance + * @param sendgrid + */ + public function setSendGrid($sendgrid) + { + $this->sendgrid = $sendgrid; + } +} \ No newline at end of file diff --git a/php/framework/src/travi/framework/email/SendMailSender.php b/php/framework/src/travi/framework/email/SendMailSender.php index 07de0af3..0b71b435 100644 --- a/php/framework/src/travi/framework/email/SendMailSender.php +++ b/php/framework/src/travi/framework/email/SendMailSender.php @@ -4,12 +4,45 @@ use travi\framework\exception\EmailNotAcceptedForDeliveryException; -class SendMailSender extends EmailSender +class SendMailSender implements EmailSender { - protected function mail($to, $subject, $message, $headers) + /** + * @param $to + * @param $from EmailAddress + * @param $subject + * @param $content + */ + public function send($to, $from, $subject, $content) { - if (false === mail($to, $subject, $message, $headers)) { + $this->mail($to, $this->formatFromHeader($from), $subject, $content); + } + + /** + * @param $email Email + */ + public function sendEmail($email) + { + $this->mail( + $email->getTo()->getAddress(), + $this->formatFromHeader($email->getFrom()), + $email->getSubject(), + $email->getMessage() + ); + } + + protected function mail($to, $from, $subject, $message) + { + if (false === mail($to, $subject, $message, $this->formatFromHeader($from))) { throw new EmailNotAcceptedForDeliveryException(); } } + + /** + * @param $from EmailAddress + * @return string + */ + private function formatFromHeader($from) + { + return "From: " . $from->getName() . " <" . $from->getAddress() . ">"; + } } \ No newline at end of file diff --git a/test/php/unit/email/SendGridMapperTest.php b/test/php/unit/email/SendGridMapperTest.php new file mode 100644 index 00000000..c1ad5e0a --- /dev/null +++ b/test/php/unit/email/SendGridMapperTest.php @@ -0,0 +1,62 @@ +mapper = new SendGridMapper(); + + $this->from = new EmailAddress(); + $this->from->setName(self::NAME); + $this->from->setAddress(self::EMAIL); + } + + public function testThatParametersMappedToSendGridEmail() + { + $sendGridEmail = $this->mapper->mapParameters(self::TO, $this->from, self::SUBJECT, self::MESSAGE); + + $this->assertThatSendGridEmailPopulatedProperly($sendGridEmail); + } + + public function testThatEmailMappedToSendGridEmail() + { + $email = new Email(); + $to = new EmailAddress(); + $to->setAddress(self::TO); + $email->setTo($to); + $email->setSubject(self::SUBJECT); + $email->setMessage(self::MESSAGE); + $email->setFrom($this->from); + + $sendGridEmail = $this->mapper->mapEmail($email); + + $this->assertThatSendGridEmailPopulatedProperly($sendGridEmail); + } + + /** + * @param $sendGridEmail + */ + private function assertThatSendGridEmailPopulatedProperly($sendGridEmail) + { + $this->assertEquals(self::TO, $sendGridEmail->to[0]); + $this->assertEquals($this->from->getAddress(), $sendGridEmail->from); + $this->assertEquals($this->from->getName(), $sendGridEmail->fromName); + $this->assertEquals(self::SUBJECT, $sendGridEmail->subject); + $this->assertEquals(self::MESSAGE, $sendGridEmail->text); + } +} \ No newline at end of file diff --git a/test/php/unit/email/SendGridSenderTest.php b/test/php/unit/email/SendGridSenderTest.php new file mode 100644 index 00000000..6701b72b --- /dev/null +++ b/test/php/unit/email/SendGridSenderTest.php @@ -0,0 +1,77 @@ +sender = new SendGridSender(); + $this->email = new \SendGrid\Email(); + + $this->mapper = $this->getMock('\\travi\\framework\\email\\SendGridMapper'); + $this->sender->setMapper($this->mapper); + + $this->sendgrid = $this->getMock('SendGrid'); + $this->sender->setSendGrid($this->sendgrid); + + $this->from = new EmailAddress(); + $this->from->setName(self::NAME); + $this->from->setAddress(self::EMAIL); + } + + public function testThatMailIsSentFromMultipleParams() + { + $this->mapper->expects($this->once()) + ->method('mapParameters') + ->with(self::TO, $this->from, self::SUBJECT, self::MESSAGE) + ->will($this->returnValue($this->email)); + $this->sendgrid->expects($this->once()) + ->method('send') + ->with($this->email); + + $this->sender->send(self::TO, $this->from, self::SUBJECT, self::MESSAGE); + } + + public function testThatMailIsSentFromEmailObject() + { +// $this->mailer->expects($this->once()) +// ->method('mail') +// ->with(self::TO, self::SUBJECT, self::MESSAGE, "From: " . self::NAME . " <" . self::EMAIL . ">"); + + $email = new Email(); + $to = new EmailAddress(); + $to->setAddress(self::TO); + $email->setTo($to); + $email->setSubject(self::SUBJECT); + $email->setMessage(self::MESSAGE); + $email->setFrom($this->from); + + $this->mapper->expects($this->once()) + ->method('mapEmail') + ->with($email) + ->will($this->returnValue($this->email)); + $this->sendgrid->expects($this->once()) + ->method('send') + ->with($this->email); + + $this->sender->sendEmail($email); + } +} \ No newline at end of file diff --git a/test/php/unit/email/SendMailSenderTest.php b/test/php/unit/email/SendMailSenderTest.php index 9e412f45..a0dbec4f 100644 --- a/test/php/unit/email/SendMailSenderTest.php +++ b/test/php/unit/email/SendMailSenderTest.php @@ -19,9 +19,9 @@ class SendMailSenderTest extends PHPUnit_Framework_TestCase { public function setUp() { - $this->sender = new EmailSenderShunt(); + $this->sender = new SendMailSenderShunt(); - $this->mailer = $this->getMock('MailerToMock'); + $this->mailer = $this->getMock('SendMailerToMock'); $this->sender->setMailer($this->mailer); $this->from = new EmailAddress(); @@ -56,14 +56,14 @@ public function testThatMailIsSentFromEmailObject() } } -class EmailSenderShunt extends SendMailSender +class SendMailSenderShunt extends SendMailSender { - /** @var MailerToMock */ + /** @var SendMailerToMock */ private $mailer; - protected function mail($to, $subject, $message, $headers) + protected function mail($to, $from, $subject, $message) { - $this->mailer->mail($to, $subject, $message, $headers); + $this->mailer->mail($to, $subject, $message, $from); } public function setMailer($mailer) @@ -72,7 +72,7 @@ public function setMailer($mailer) } } -class MailerToMock +class SendMailerToMock { public function mail($to, $subject, $message, $headers) {