From fc0ae4d38ec65eb4345d44b247b8cd86bb34fbb9 Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Wed, 31 Jan 2018 18:12:58 +0200 Subject: [PATCH] move source code to 'src' directory --- .travis.yml | 8 - Logger.php | 96 --------- Mailer.php | 253 ------------------------ Message.php | 578 ------------------------------------------------------- composer.json | 2 +- phpunit.xml.dist | 1 + src/Logger.php | 96 +++++++++ src/Mailer.php | 253 ++++++++++++++++++++++++ src/Message.php | 578 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 929 insertions(+), 936 deletions(-) delete mode 100644 Logger.php delete mode 100644 Mailer.php delete mode 100644 Message.php create mode 100644 src/Logger.php create mode 100644 src/Mailer.php create mode 100644 src/Message.php diff --git a/.travis.yml b/.travis.yml index f708ffe..2ba6283 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,11 +27,3 @@ before_script: script: - phpunit --verbose $PHPUNIT_FLAGS - -after_script: - - | - if [ $TRAVIS_PHP_VERSION = '5.6' ]; then - cd ../../.. - travis_retry wget https://scrutinizer-ci.com/ocular.phar - php ocular.phar code-coverage:upload --format=php-clover coverage.clover - fi diff --git a/Logger.php b/Logger.php deleted file mode 100644 index 646fd26..0000000 --- a/Logger.php +++ /dev/null @@ -1,96 +0,0 @@ - [ - * 'mailer' => [ - * 'class' => 'yii\swiftmailer\Mailer', - * 'enableSwiftMailerLogging' => true, - * ], - * ], - * // ... - * ], - * ``` - * - * - * In order to catch logs written by this class, you need to setup a log route for 'yii\swiftmailer\Logger::add' category. - * For example: - * - * ```php - * [ - * 'components' => [ - * 'log' => [ - * 'targets' => [ - * [ - * 'class' => 'yii\log\FileTarget', - * 'categories' => ['yii\swiftmailer\Logger::add'], - * ], - * ], - * ], - * // ... - * ], - * // ... - * ], - * ``` - * - * @author Paul Klimov - * @since 2.0.4 - */ -class Logger implements \Swift_Plugins_Logger -{ - /** - * @inheritdoc - */ - public function add($entry) - { - $categoryPrefix = substr($entry, 0, 2); - switch ($categoryPrefix) { - case '++': - $level = \yii\log\Logger::LEVEL_TRACE; - break; - case '>>': - case '<<': - $level = \yii\log\Logger::LEVEL_INFO; - break; - case '!!': - $level = \yii\log\Logger::LEVEL_WARNING; - break; - default: - $level = \yii\log\Logger::LEVEL_INFO; - } - - Yii::getLogger()->log($entry, $level, __METHOD__); - } - - /** - * @inheritdoc - */ - public function clear() - { - // do nothing - } - - /** - * @inheritdoc - */ - public function dump() - { - return ''; - } -} \ No newline at end of file diff --git a/Mailer.php b/Mailer.php deleted file mode 100644 index 9124be2..0000000 --- a/Mailer.php +++ /dev/null @@ -1,253 +0,0 @@ - [ - * 'mailer' => [ - * 'class' => 'yii\swiftmailer\Mailer', - * 'transport' => [ - * 'class' => 'Swift_SmtpTransport', - * 'host' => 'localhost', - * 'username' => 'username', - * 'password' => 'password', - * 'port' => '587', - * 'encryption' => 'tls', - * ], - * ], - * // ... - * ], - * // ... - * ], - * ``` - * - * You may also skip the configuration of the [[transport]] property. In that case, the default - * `\Swift_SendmailTransport` transport will be used to send emails. - * - * You specify the transport constructor arguments using 'constructArgs' key in the config. - * You can also specify the list of plugins, which should be registered to the transport using - * 'plugins' key. For example: - * - * ```php - * 'transport' => [ - * 'class' => 'Swift_SmtpTransport', - * 'constructArgs' => ['localhost', 25] - * 'plugins' => [ - * [ - * 'class' => 'Swift_Plugins_ThrottlerPlugin', - * 'constructArgs' => [20], - * ], - * ], - * ], - * ``` - * - * To send an email, you may use the following code: - * - * ```php - * Yii::$app->mailer->compose('contact/html', ['contactForm' => $form]) - * ->setFrom('from@domain.com') - * ->setTo($form->email) - * ->setSubject($form->subject) - * ->send(); - * ``` - * - * @see http://swiftmailer.org - * - * @property array|\Swift_Mailer $swiftMailer Swift mailer instance or array configuration. This property is - * read-only. - * @property array|\Swift_Transport $transport This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Mailer extends BaseMailer -{ - /** - * @var string message default class name. - */ - public $messageClass = 'yii\swiftmailer\Message'; - /** - * @var bool whether to enable writing of the SwiftMailer internal logs using Yii log mechanism. - * If enabled [[Logger]] plugin will be attached to the [[transport]] for this purpose. - * @see Logger - * @since 2.0.4 - */ - public $enableSwiftMailerLogging = false; - - /** - * @var \Swift_Mailer Swift mailer instance. - */ - private $_swiftMailer; - /** - * @var \Swift_Transport|array Swift transport instance or its array configuration. - */ - private $_transport = []; - - - /** - * @return array|\Swift_Mailer Swift mailer instance or array configuration. - */ - public function getSwiftMailer() - { - if (!is_object($this->_swiftMailer)) { - $this->_swiftMailer = $this->createSwiftMailer(); - } - - return $this->_swiftMailer; - } - - /** - * @param array|\Swift_Transport $transport - * @throws InvalidConfigException on invalid argument. - */ - public function setTransport($transport) - { - if (!is_array($transport) && !is_object($transport)) { - throw new InvalidConfigException('"' . get_class($this) . '::transport" should be either object or array, "' . gettype($transport) . '" given.'); - } - $this->_transport = $transport; - } - - /** - * @return array|\Swift_Transport - */ - public function getTransport() - { - if (!is_object($this->_transport)) { - $this->_transport = $this->createTransport($this->_transport); - } - - return $this->_transport; - } - - /** - * @inheritdoc - */ - protected function sendMessage($message) - { - /* @var $message Message */ - $address = $message->getTo(); - if (is_array($address)) { - $address = implode(', ', array_keys($address)); - } - Yii::info('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); - - return $this->getSwiftMailer()->send($message->getSwiftMessage()) > 0; - } - - /** - * Creates Swift mailer instance. - * @return \Swift_Mailer mailer instance. - */ - protected function createSwiftMailer() - { - return new \Swift_Mailer($this->getTransport()); - } - - /** - * Creates email transport instance by its array configuration. - * @param array $config transport configuration. - * @throws \yii\base\InvalidConfigException on invalid transport configuration. - * @return \Swift_Transport transport instance. - */ - protected function createTransport(array $config) - { - if (!isset($config['class'])) { - $config['class'] = 'Swift_SendmailTransport'; - } - if (isset($config['plugins'])) { - $plugins = $config['plugins']; - unset($config['plugins']); - } else { - $plugins = []; - } - - if ($this->enableSwiftMailerLogging) { - $plugins[] = [ - 'class' => 'Swift_Plugins_LoggerPlugin', - 'constructArgs' => [ - [ - 'class' => 'yii\swiftmailer\Logger' - ] - ], - ]; - } - - /* @var $transport \Swift_Transport */ - $transport = $this->createSwiftObject($config); - if (!empty($plugins)) { - foreach ($plugins as $plugin) { - if (is_array($plugin) && isset($plugin['class'])) { - $plugin = $this->createSwiftObject($plugin); - } - $transport->registerPlugin($plugin); - } - } - - return $transport; - } - - /** - * Creates Swift library object, from given array configuration. - * @param array $config object configuration - * @return Object created object - * @throws \yii\base\InvalidConfigException on invalid configuration. - */ - protected function createSwiftObject(array $config) - { - if (isset($config['class'])) { - $className = $config['class']; - unset($config['class']); - } else { - throw new InvalidConfigException('Object configuration must be an array containing a "class" element.'); - } - - if (isset($config['constructArgs'])) { - $args = []; - foreach ($config['constructArgs'] as $arg) { - if (is_array($arg) && isset($arg['class'])) { - $args[] = $this->createSwiftObject($arg); - } else { - $args[] = $arg; - } - } - unset($config['constructArgs']); - $object = Yii::createObject($className, $args); - } else { - $object = Yii::createObject($className); - } - - if (!empty($config)) { - $reflection = new \ReflectionObject($object); - foreach ($config as $name => $value) { - if ($reflection->hasProperty($name) && $reflection->getProperty($name)->isPublic()) { - $object->$name = $value; - } else { - $setter = 'set' . $name; - if ($reflection->hasMethod($setter) || $reflection->hasMethod('__call')) { - $object->$setter($value); - } else { - throw new InvalidConfigException('Setting unknown property: ' . $className . '::' . $name); - } - } - } - } - - return $object; - } -} diff --git a/Message.php b/Message.php deleted file mode 100644 index 2744e0c..0000000 --- a/Message.php +++ /dev/null @@ -1,578 +0,0 @@ - value]`. This property is write-only. - * @property int $priority Priority value as integer in range: `1..5`, where 1 is the highest priority and 5 - * is the lowest. - * @property string $readReceiptTo Receipt receive email addresses. Note that the type of this property - * differs in getter and setter. See [[getReadReceiptTo()]] and [[setReadReceiptTo()]] for details. - * @property string $returnPath The bounce email address. - * @property array|callable|\Swift_Signer $signature Signature specification. See [[addSignature()]] for - * details on how it should be specified. This property is write-only. - * @property \Swift_Message $swiftMessage Swift message instance. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Message extends BaseMessage -{ - /** - * @var \Swift_Message Swift message instance. - */ - private $_swiftMessage; - /** - * @var \Swift_Signer[] attached signers - */ - private $signers = []; - - - /** - * This method is called after the object is created by cloning an existing one. - * It ensures [[swiftMessage]] is also cloned. - * @since 2.0.7 - */ - public function __clone() - { - if (is_object($this->_swiftMessage)) { - $this->_swiftMessage = clone $this->_swiftMessage; - } - } - - /** - * @return \Swift_Message Swift message instance. - */ - public function getSwiftMessage() - { - if (!is_object($this->_swiftMessage)) { - $this->_swiftMessage = $this->createSwiftMessage(); - } - - return $this->_swiftMessage; - } - - /** - * @inheritdoc - */ - public function getCharset() - { - return $this->getSwiftMessage()->getCharset(); - } - - /** - * @inheritdoc - */ - public function setCharset($charset) - { - $this->getSwiftMessage()->setCharset($charset); - - return $this; - } - - /** - * @inheritdoc - */ - public function getFrom() - { - return $this->getSwiftMessage()->getFrom(); - } - - /** - * @inheritdoc - */ - public function setFrom($from) - { - $this->getSwiftMessage()->setFrom($from); - - return $this; - } - - /** - * @inheritdoc - */ - public function getReplyTo() - { - return $this->getSwiftMessage()->getReplyTo(); - } - - /** - * @inheritdoc - */ - public function setReplyTo($replyTo) - { - $this->getSwiftMessage()->setReplyTo($replyTo); - - return $this; - } - - /** - * @inheritdoc - */ - public function getTo() - { - return $this->getSwiftMessage()->getTo(); - } - - /** - * @inheritdoc - */ - public function setTo($to) - { - $this->getSwiftMessage()->setTo($to); - - return $this; - } - - /** - * @inheritdoc - */ - public function getCc() - { - return $this->getSwiftMessage()->getCc(); - } - - /** - * @inheritdoc - */ - public function setCc($cc) - { - $this->getSwiftMessage()->setCc($cc); - - return $this; - } - - /** - * @inheritdoc - */ - public function getBcc() - { - return $this->getSwiftMessage()->getBcc(); - } - - /** - * @inheritdoc - */ - public function setBcc($bcc) - { - $this->getSwiftMessage()->setBcc($bcc); - - return $this; - } - - /** - * @inheritdoc - */ - public function getSubject() - { - return $this->getSwiftMessage()->getSubject(); - } - - /** - * @inheritdoc - */ - public function setSubject($subject) - { - $this->getSwiftMessage()->setSubject($subject); - - return $this; - } - - /** - * @inheritdoc - */ - public function setTextBody($text) - { - $this->setBody($text, 'text/plain'); - - return $this; - } - - /** - * @inheritdoc - */ - public function setHtmlBody($html) - { - $this->setBody($html, 'text/html'); - - return $this; - } - - /** - * Sets the message body. - * If body is already set and its content type matches given one, it will - * be overridden, if content type miss match the multipart message will be composed. - * @param string $body body content. - * @param string $contentType body content type. - */ - protected function setBody($body, $contentType) - { - $message = $this->getSwiftMessage(); - $oldBody = $message->getBody(); - $charset = $message->getCharset(); - if (empty($oldBody)) { - $parts = $message->getChildren(); - $partFound = false; - foreach ($parts as $key => $part) { - if (!($part instanceof \Swift_Mime_Attachment)) { - /* @var $part \Swift_Mime_MimePart */ - if ($part->getContentType() == $contentType) { - $charset = $part->getCharset(); - unset($parts[$key]); - $partFound = true; - break; - } - } - } - if ($partFound) { - reset($parts); - $message->setChildren($parts); - $message->addPart($body, $contentType, $charset); - } else { - $message->setBody($body, $contentType); - } - } else { - $oldContentType = $message->getContentType(); - if ($oldContentType == $contentType) { - $message->setBody($body, $contentType); - } else { - $message->setBody(null); - $message->setContentType(null); - $message->addPart($oldBody, $oldContentType, $charset); - $message->addPart($body, $contentType, $charset); - } - } - } - - /** - * @inheritdoc - */ - public function attach($fileName, array $options = []) - { - $attachment = \Swift_Attachment::fromPath($fileName); - if (!empty($options['fileName'])) { - $attachment->setFilename($options['fileName']); - } - if (!empty($options['contentType'])) { - $attachment->setContentType($options['contentType']); - } - $this->getSwiftMessage()->attach($attachment); - - return $this; - } - - /** - * @inheritdoc - */ - public function attachContent($content, array $options = []) - { - $attachment = new \Swift_Attachment($content); - if (!empty($options['fileName'])) { - $attachment->setFilename($options['fileName']); - } - if (!empty($options['contentType'])) { - $attachment->setContentType($options['contentType']); - } - $this->getSwiftMessage()->attach($attachment); - - return $this; - } - - /** - * @inheritdoc - */ - public function embed($fileName, array $options = []) - { - $embedFile = \Swift_EmbeddedFile::fromPath($fileName); - if (!empty($options['fileName'])) { - $embedFile->setFilename($options['fileName']); - } - if (!empty($options['contentType'])) { - $embedFile->setContentType($options['contentType']); - } - - return $this->getSwiftMessage()->embed($embedFile); - } - - /** - * @inheritdoc - */ - public function embedContent($content, array $options = []) - { - $embedFile = new \Swift_EmbeddedFile($content); - if (!empty($options['fileName'])) { - $embedFile->setFilename($options['fileName']); - } - if (!empty($options['contentType'])) { - $embedFile->setContentType($options['contentType']); - } - - return $this->getSwiftMessage()->embed($embedFile); - } - - /** - * Sets message signature - * @param array|callable|\Swift_Signer $signature signature specification. - * See [[addSignature()]] for details on how it should be specified. - * @return $this self reference. - * @since 2.0.6 - */ - public function setSignature($signature) - { - if (!empty($this->signers)) { - // clear previously set signers - $swiftMessage = $this->getSwiftMessage(); - foreach ($this->signers as $signer) { - $swiftMessage->detachSigner($signer); - } - $this->signers = []; - } - return $this->addSignature($signature); - } - - /** - * Adds message signature. - * @param array|callable|\Swift_Signer $signature signature specification, this can be: - * - * - [[\Swift_Signer]] instance - * - callable, which returns [[\Swift_Signer]] instance - * - configuration array for the signer creation - * - * @return $this self reference - * @throws InvalidConfigException on invalid signature configuration - * @since 2.0.6 - */ - public function addSignature($signature) - { - if ($signature instanceof \Swift_Signer) { - $signer = $signature; - } elseif (is_callable($signature)) { - $signer = call_user_func($signature); - } elseif (is_array($signature)) { - $signer = $this->createSwiftSigner($signature); - } else { - throw new InvalidConfigException('Signature should be instance of "Swift_Signer", callable or array configuration'); - } - - $this->getSwiftMessage()->attachSigner($signer); - $this->signers[] = $signer; - - return $this; - } - - /** - * Creates signer from its configuration - * @param array $signature signature configuration - * @return \Swift_Signer signer instance - * @throws InvalidConfigException on invalid configuration provided - * @since 2.0.6 - */ - protected function createSwiftSigner($signature) - { - if (!isset($signature['type'])) { - throw new InvalidConfigException('Signature configuration should contain "type" key'); - } - switch (strtolower($signature['type'])) { - case 'dkim' : - $domain = ArrayHelper::getValue($signature, 'domain', null); - $selector = ArrayHelper::getValue($signature, 'selector', null); - if (isset($signature['key'])) { - $privateKey = $signature['key']; - } elseif (isset($signature['file'])) { - $privateKey = file_get_contents(Yii::getAlias($signature['file'])); - } else { - throw new InvalidConfigException("Either 'key' or 'file' signature option should be specified"); - } - return new \Swift_Signers_DKIMSigner($privateKey, $domain, $selector); - case 'opendkim' : - $domain = ArrayHelper::getValue($signature, 'domain', null); - $selector = ArrayHelper::getValue($signature, 'selector', null); - if (isset($signature['key'])) { - $privateKey = $signature['key']; - } elseif (isset($signature['file'])) { - $privateKey = file_get_contents(Yii::getAlias($signature['file'])); - } else { - throw new InvalidConfigException("Either 'key' or 'file' signature option should be specified"); - } - return new \Swift_Signers_OpenDKIMSigner($privateKey, $domain, $selector); - default: - throw new InvalidConfigException("Unrecognized signature type '{$signature['type']}'"); - } - } - - /** - * @inheritdoc - */ - public function toString() - { - return $this->getSwiftMessage()->toString(); - } - - /** - * Creates the Swift email message instance. - * @return \Swift_Message email message instance. - */ - protected function createSwiftMessage() - { - return new \Swift_Message(); - } - - // Headers setup : - - /** - * Adds custom header value to the message. - * Several invocations of this method with the same name will add multiple header values. - * @param string $name header name. - * @param string $value header value. - * @return $this self reference. - * @since 2.0.6 - */ - public function addHeader($name, $value) - { - $this->getSwiftMessage()->getHeaders()->addTextHeader($name, $value); - return $this; - } - - /** - * Sets custom header value to the message. - * @param string $name header name. - * @param string|array $value header value or values. - * @return $this self reference. - * @since 2.0.6 - */ - public function setHeader($name, $value) - { - $headerSet = $this->getSwiftMessage()->getHeaders(); - - if ($headerSet->has($name)) { - $headerSet->remove($name); - } - - foreach ((array)$value as $v) { - $headerSet->addTextHeader($name, $v); - } - - return $this; - } - - /** - * Returns all values for the specified header. - * @param string $name header name. - * @return array header values list. - * @since 2.0.6 - */ - public function getHeader($name) - { - $headerSet = $this->getSwiftMessage()->getHeaders(); - if (!$headerSet->has($name)) { - return []; - } - - $headers = []; - foreach ($headerSet->getAll($name) as $header) { - $headers[] = $header->getValue(); - } - return $headers; - } - - /** - * Sets custom header values to the message. - * @param array $headers headers in format: `[name => value]`. - * @return $this self reference. - * @since 2.0.7 - */ - public function setHeaders($headers) - { - foreach ($headers as $name => $value) { - $this->setHeader($name, $value); - } - return $this; - } - - // SwiftMessage shortcuts : - - /** - * Set the return-path (the bounce address) of this message. - * @param string $address the bounce email address. - * @return $this self reference. - * @since 2.0.6 - */ - public function setReturnPath($address) - { - $this->getSwiftMessage()->setReturnPath($address); - return $this; - } - - /** - * Returns the return-path (the bounce address) of this message. - * @return string the bounce email address. - * @since 2.0.6 - */ - public function getReturnPath() - { - return $this->getSwiftMessage()->getReturnPath(); - } - - /** - * Set the priority of this message. - * @param int $priority priority value, should be an integer in range: `1..5`, - * where 1 is the highest priority and 5 is the lowest. - * @return $this self reference. - * @since 2.0.6 - */ - public function setPriority($priority) - { - $this->getSwiftMessage()->setPriority($priority); - return $this; - } - - /** - * Returns the priority of this message. - * @return int priority value as integer in range: `1..5`, - * where 1 is the highest priority and 5 is the lowest. - * @since 2.0.6 - */ - public function getPriority() - { - return $this->getSwiftMessage()->getPriority(); - } - - /** - * Sets the ask for a delivery receipt from the recipient to be sent to $addresses. - * @param string|array $addresses receipt receive email address(es). - * @return $this self reference. - * @since 2.0.6 - */ - public function setReadReceiptTo($addresses) - { - $this->getSwiftMessage()->setReadReceiptTo($addresses); - return $this; - } - - /** - * Get the addresses to which a read-receipt will be sent. - * @return string receipt receive email addresses. - * @since 2.0.6 - */ - public function getReadReceiptTo() - { - return $this->getSwiftMessage()->getReadReceiptTo(); - } -} diff --git a/composer.json b/composer.json index 4ff4367..40bd970 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ } ], "autoload": { - "psr-4": { "yii\\swiftmailer\\": "" } + "psr-4": { "yii\\swiftmailer\\": "src" } }, "extra": { "branch-alias": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d93d427..5ca8862 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,7 @@ [ + * 'mailer' => [ + * 'class' => 'yii\swiftmailer\Mailer', + * 'enableSwiftMailerLogging' => true, + * ], + * ], + * // ... + * ], + * ``` + * + * + * In order to catch logs written by this class, you need to setup a log route for 'yii\swiftmailer\Logger::add' category. + * For example: + * + * ```php + * [ + * 'components' => [ + * 'log' => [ + * 'targets' => [ + * [ + * 'class' => 'yii\log\FileTarget', + * 'categories' => ['yii\swiftmailer\Logger::add'], + * ], + * ], + * ], + * // ... + * ], + * // ... + * ], + * ``` + * + * @author Paul Klimov + * @since 2.0.4 + */ +class Logger implements \Swift_Plugins_Logger +{ + /** + * @inheritdoc + */ + public function add($entry) + { + $categoryPrefix = substr($entry, 0, 2); + switch ($categoryPrefix) { + case '++': + $level = \yii\log\Logger::LEVEL_TRACE; + break; + case '>>': + case '<<': + $level = \yii\log\Logger::LEVEL_INFO; + break; + case '!!': + $level = \yii\log\Logger::LEVEL_WARNING; + break; + default: + $level = \yii\log\Logger::LEVEL_INFO; + } + + Yii::getLogger()->log($entry, $level, __METHOD__); + } + + /** + * @inheritdoc + */ + public function clear() + { + // do nothing + } + + /** + * @inheritdoc + */ + public function dump() + { + return ''; + } +} \ No newline at end of file diff --git a/src/Mailer.php b/src/Mailer.php new file mode 100644 index 0000000..9124be2 --- /dev/null +++ b/src/Mailer.php @@ -0,0 +1,253 @@ + [ + * 'mailer' => [ + * 'class' => 'yii\swiftmailer\Mailer', + * 'transport' => [ + * 'class' => 'Swift_SmtpTransport', + * 'host' => 'localhost', + * 'username' => 'username', + * 'password' => 'password', + * 'port' => '587', + * 'encryption' => 'tls', + * ], + * ], + * // ... + * ], + * // ... + * ], + * ``` + * + * You may also skip the configuration of the [[transport]] property. In that case, the default + * `\Swift_SendmailTransport` transport will be used to send emails. + * + * You specify the transport constructor arguments using 'constructArgs' key in the config. + * You can also specify the list of plugins, which should be registered to the transport using + * 'plugins' key. For example: + * + * ```php + * 'transport' => [ + * 'class' => 'Swift_SmtpTransport', + * 'constructArgs' => ['localhost', 25] + * 'plugins' => [ + * [ + * 'class' => 'Swift_Plugins_ThrottlerPlugin', + * 'constructArgs' => [20], + * ], + * ], + * ], + * ``` + * + * To send an email, you may use the following code: + * + * ```php + * Yii::$app->mailer->compose('contact/html', ['contactForm' => $form]) + * ->setFrom('from@domain.com') + * ->setTo($form->email) + * ->setSubject($form->subject) + * ->send(); + * ``` + * + * @see http://swiftmailer.org + * + * @property array|\Swift_Mailer $swiftMailer Swift mailer instance or array configuration. This property is + * read-only. + * @property array|\Swift_Transport $transport This property is read-only. + * + * @author Paul Klimov + * @since 2.0 + */ +class Mailer extends BaseMailer +{ + /** + * @var string message default class name. + */ + public $messageClass = 'yii\swiftmailer\Message'; + /** + * @var bool whether to enable writing of the SwiftMailer internal logs using Yii log mechanism. + * If enabled [[Logger]] plugin will be attached to the [[transport]] for this purpose. + * @see Logger + * @since 2.0.4 + */ + public $enableSwiftMailerLogging = false; + + /** + * @var \Swift_Mailer Swift mailer instance. + */ + private $_swiftMailer; + /** + * @var \Swift_Transport|array Swift transport instance or its array configuration. + */ + private $_transport = []; + + + /** + * @return array|\Swift_Mailer Swift mailer instance or array configuration. + */ + public function getSwiftMailer() + { + if (!is_object($this->_swiftMailer)) { + $this->_swiftMailer = $this->createSwiftMailer(); + } + + return $this->_swiftMailer; + } + + /** + * @param array|\Swift_Transport $transport + * @throws InvalidConfigException on invalid argument. + */ + public function setTransport($transport) + { + if (!is_array($transport) && !is_object($transport)) { + throw new InvalidConfigException('"' . get_class($this) . '::transport" should be either object or array, "' . gettype($transport) . '" given.'); + } + $this->_transport = $transport; + } + + /** + * @return array|\Swift_Transport + */ + public function getTransport() + { + if (!is_object($this->_transport)) { + $this->_transport = $this->createTransport($this->_transport); + } + + return $this->_transport; + } + + /** + * @inheritdoc + */ + protected function sendMessage($message) + { + /* @var $message Message */ + $address = $message->getTo(); + if (is_array($address)) { + $address = implode(', ', array_keys($address)); + } + Yii::info('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); + + return $this->getSwiftMailer()->send($message->getSwiftMessage()) > 0; + } + + /** + * Creates Swift mailer instance. + * @return \Swift_Mailer mailer instance. + */ + protected function createSwiftMailer() + { + return new \Swift_Mailer($this->getTransport()); + } + + /** + * Creates email transport instance by its array configuration. + * @param array $config transport configuration. + * @throws \yii\base\InvalidConfigException on invalid transport configuration. + * @return \Swift_Transport transport instance. + */ + protected function createTransport(array $config) + { + if (!isset($config['class'])) { + $config['class'] = 'Swift_SendmailTransport'; + } + if (isset($config['plugins'])) { + $plugins = $config['plugins']; + unset($config['plugins']); + } else { + $plugins = []; + } + + if ($this->enableSwiftMailerLogging) { + $plugins[] = [ + 'class' => 'Swift_Plugins_LoggerPlugin', + 'constructArgs' => [ + [ + 'class' => 'yii\swiftmailer\Logger' + ] + ], + ]; + } + + /* @var $transport \Swift_Transport */ + $transport = $this->createSwiftObject($config); + if (!empty($plugins)) { + foreach ($plugins as $plugin) { + if (is_array($plugin) && isset($plugin['class'])) { + $plugin = $this->createSwiftObject($plugin); + } + $transport->registerPlugin($plugin); + } + } + + return $transport; + } + + /** + * Creates Swift library object, from given array configuration. + * @param array $config object configuration + * @return Object created object + * @throws \yii\base\InvalidConfigException on invalid configuration. + */ + protected function createSwiftObject(array $config) + { + if (isset($config['class'])) { + $className = $config['class']; + unset($config['class']); + } else { + throw new InvalidConfigException('Object configuration must be an array containing a "class" element.'); + } + + if (isset($config['constructArgs'])) { + $args = []; + foreach ($config['constructArgs'] as $arg) { + if (is_array($arg) && isset($arg['class'])) { + $args[] = $this->createSwiftObject($arg); + } else { + $args[] = $arg; + } + } + unset($config['constructArgs']); + $object = Yii::createObject($className, $args); + } else { + $object = Yii::createObject($className); + } + + if (!empty($config)) { + $reflection = new \ReflectionObject($object); + foreach ($config as $name => $value) { + if ($reflection->hasProperty($name) && $reflection->getProperty($name)->isPublic()) { + $object->$name = $value; + } else { + $setter = 'set' . $name; + if ($reflection->hasMethod($setter) || $reflection->hasMethod('__call')) { + $object->$setter($value); + } else { + throw new InvalidConfigException('Setting unknown property: ' . $className . '::' . $name); + } + } + } + } + + return $object; + } +} diff --git a/src/Message.php b/src/Message.php new file mode 100644 index 0000000..2744e0c --- /dev/null +++ b/src/Message.php @@ -0,0 +1,578 @@ + value]`. This property is write-only. + * @property int $priority Priority value as integer in range: `1..5`, where 1 is the highest priority and 5 + * is the lowest. + * @property string $readReceiptTo Receipt receive email addresses. Note that the type of this property + * differs in getter and setter. See [[getReadReceiptTo()]] and [[setReadReceiptTo()]] for details. + * @property string $returnPath The bounce email address. + * @property array|callable|\Swift_Signer $signature Signature specification. See [[addSignature()]] for + * details on how it should be specified. This property is write-only. + * @property \Swift_Message $swiftMessage Swift message instance. This property is read-only. + * + * @author Paul Klimov + * @since 2.0 + */ +class Message extends BaseMessage +{ + /** + * @var \Swift_Message Swift message instance. + */ + private $_swiftMessage; + /** + * @var \Swift_Signer[] attached signers + */ + private $signers = []; + + + /** + * This method is called after the object is created by cloning an existing one. + * It ensures [[swiftMessage]] is also cloned. + * @since 2.0.7 + */ + public function __clone() + { + if (is_object($this->_swiftMessage)) { + $this->_swiftMessage = clone $this->_swiftMessage; + } + } + + /** + * @return \Swift_Message Swift message instance. + */ + public function getSwiftMessage() + { + if (!is_object($this->_swiftMessage)) { + $this->_swiftMessage = $this->createSwiftMessage(); + } + + return $this->_swiftMessage; + } + + /** + * @inheritdoc + */ + public function getCharset() + { + return $this->getSwiftMessage()->getCharset(); + } + + /** + * @inheritdoc + */ + public function setCharset($charset) + { + $this->getSwiftMessage()->setCharset($charset); + + return $this; + } + + /** + * @inheritdoc + */ + public function getFrom() + { + return $this->getSwiftMessage()->getFrom(); + } + + /** + * @inheritdoc + */ + public function setFrom($from) + { + $this->getSwiftMessage()->setFrom($from); + + return $this; + } + + /** + * @inheritdoc + */ + public function getReplyTo() + { + return $this->getSwiftMessage()->getReplyTo(); + } + + /** + * @inheritdoc + */ + public function setReplyTo($replyTo) + { + $this->getSwiftMessage()->setReplyTo($replyTo); + + return $this; + } + + /** + * @inheritdoc + */ + public function getTo() + { + return $this->getSwiftMessage()->getTo(); + } + + /** + * @inheritdoc + */ + public function setTo($to) + { + $this->getSwiftMessage()->setTo($to); + + return $this; + } + + /** + * @inheritdoc + */ + public function getCc() + { + return $this->getSwiftMessage()->getCc(); + } + + /** + * @inheritdoc + */ + public function setCc($cc) + { + $this->getSwiftMessage()->setCc($cc); + + return $this; + } + + /** + * @inheritdoc + */ + public function getBcc() + { + return $this->getSwiftMessage()->getBcc(); + } + + /** + * @inheritdoc + */ + public function setBcc($bcc) + { + $this->getSwiftMessage()->setBcc($bcc); + + return $this; + } + + /** + * @inheritdoc + */ + public function getSubject() + { + return $this->getSwiftMessage()->getSubject(); + } + + /** + * @inheritdoc + */ + public function setSubject($subject) + { + $this->getSwiftMessage()->setSubject($subject); + + return $this; + } + + /** + * @inheritdoc + */ + public function setTextBody($text) + { + $this->setBody($text, 'text/plain'); + + return $this; + } + + /** + * @inheritdoc + */ + public function setHtmlBody($html) + { + $this->setBody($html, 'text/html'); + + return $this; + } + + /** + * Sets the message body. + * If body is already set and its content type matches given one, it will + * be overridden, if content type miss match the multipart message will be composed. + * @param string $body body content. + * @param string $contentType body content type. + */ + protected function setBody($body, $contentType) + { + $message = $this->getSwiftMessage(); + $oldBody = $message->getBody(); + $charset = $message->getCharset(); + if (empty($oldBody)) { + $parts = $message->getChildren(); + $partFound = false; + foreach ($parts as $key => $part) { + if (!($part instanceof \Swift_Mime_Attachment)) { + /* @var $part \Swift_Mime_MimePart */ + if ($part->getContentType() == $contentType) { + $charset = $part->getCharset(); + unset($parts[$key]); + $partFound = true; + break; + } + } + } + if ($partFound) { + reset($parts); + $message->setChildren($parts); + $message->addPart($body, $contentType, $charset); + } else { + $message->setBody($body, $contentType); + } + } else { + $oldContentType = $message->getContentType(); + if ($oldContentType == $contentType) { + $message->setBody($body, $contentType); + } else { + $message->setBody(null); + $message->setContentType(null); + $message->addPart($oldBody, $oldContentType, $charset); + $message->addPart($body, $contentType, $charset); + } + } + } + + /** + * @inheritdoc + */ + public function attach($fileName, array $options = []) + { + $attachment = \Swift_Attachment::fromPath($fileName); + if (!empty($options['fileName'])) { + $attachment->setFilename($options['fileName']); + } + if (!empty($options['contentType'])) { + $attachment->setContentType($options['contentType']); + } + $this->getSwiftMessage()->attach($attachment); + + return $this; + } + + /** + * @inheritdoc + */ + public function attachContent($content, array $options = []) + { + $attachment = new \Swift_Attachment($content); + if (!empty($options['fileName'])) { + $attachment->setFilename($options['fileName']); + } + if (!empty($options['contentType'])) { + $attachment->setContentType($options['contentType']); + } + $this->getSwiftMessage()->attach($attachment); + + return $this; + } + + /** + * @inheritdoc + */ + public function embed($fileName, array $options = []) + { + $embedFile = \Swift_EmbeddedFile::fromPath($fileName); + if (!empty($options['fileName'])) { + $embedFile->setFilename($options['fileName']); + } + if (!empty($options['contentType'])) { + $embedFile->setContentType($options['contentType']); + } + + return $this->getSwiftMessage()->embed($embedFile); + } + + /** + * @inheritdoc + */ + public function embedContent($content, array $options = []) + { + $embedFile = new \Swift_EmbeddedFile($content); + if (!empty($options['fileName'])) { + $embedFile->setFilename($options['fileName']); + } + if (!empty($options['contentType'])) { + $embedFile->setContentType($options['contentType']); + } + + return $this->getSwiftMessage()->embed($embedFile); + } + + /** + * Sets message signature + * @param array|callable|\Swift_Signer $signature signature specification. + * See [[addSignature()]] for details on how it should be specified. + * @return $this self reference. + * @since 2.0.6 + */ + public function setSignature($signature) + { + if (!empty($this->signers)) { + // clear previously set signers + $swiftMessage = $this->getSwiftMessage(); + foreach ($this->signers as $signer) { + $swiftMessage->detachSigner($signer); + } + $this->signers = []; + } + return $this->addSignature($signature); + } + + /** + * Adds message signature. + * @param array|callable|\Swift_Signer $signature signature specification, this can be: + * + * - [[\Swift_Signer]] instance + * - callable, which returns [[\Swift_Signer]] instance + * - configuration array for the signer creation + * + * @return $this self reference + * @throws InvalidConfigException on invalid signature configuration + * @since 2.0.6 + */ + public function addSignature($signature) + { + if ($signature instanceof \Swift_Signer) { + $signer = $signature; + } elseif (is_callable($signature)) { + $signer = call_user_func($signature); + } elseif (is_array($signature)) { + $signer = $this->createSwiftSigner($signature); + } else { + throw new InvalidConfigException('Signature should be instance of "Swift_Signer", callable or array configuration'); + } + + $this->getSwiftMessage()->attachSigner($signer); + $this->signers[] = $signer; + + return $this; + } + + /** + * Creates signer from its configuration + * @param array $signature signature configuration + * @return \Swift_Signer signer instance + * @throws InvalidConfigException on invalid configuration provided + * @since 2.0.6 + */ + protected function createSwiftSigner($signature) + { + if (!isset($signature['type'])) { + throw new InvalidConfigException('Signature configuration should contain "type" key'); + } + switch (strtolower($signature['type'])) { + case 'dkim' : + $domain = ArrayHelper::getValue($signature, 'domain', null); + $selector = ArrayHelper::getValue($signature, 'selector', null); + if (isset($signature['key'])) { + $privateKey = $signature['key']; + } elseif (isset($signature['file'])) { + $privateKey = file_get_contents(Yii::getAlias($signature['file'])); + } else { + throw new InvalidConfigException("Either 'key' or 'file' signature option should be specified"); + } + return new \Swift_Signers_DKIMSigner($privateKey, $domain, $selector); + case 'opendkim' : + $domain = ArrayHelper::getValue($signature, 'domain', null); + $selector = ArrayHelper::getValue($signature, 'selector', null); + if (isset($signature['key'])) { + $privateKey = $signature['key']; + } elseif (isset($signature['file'])) { + $privateKey = file_get_contents(Yii::getAlias($signature['file'])); + } else { + throw new InvalidConfigException("Either 'key' or 'file' signature option should be specified"); + } + return new \Swift_Signers_OpenDKIMSigner($privateKey, $domain, $selector); + default: + throw new InvalidConfigException("Unrecognized signature type '{$signature['type']}'"); + } + } + + /** + * @inheritdoc + */ + public function toString() + { + return $this->getSwiftMessage()->toString(); + } + + /** + * Creates the Swift email message instance. + * @return \Swift_Message email message instance. + */ + protected function createSwiftMessage() + { + return new \Swift_Message(); + } + + // Headers setup : + + /** + * Adds custom header value to the message. + * Several invocations of this method with the same name will add multiple header values. + * @param string $name header name. + * @param string $value header value. + * @return $this self reference. + * @since 2.0.6 + */ + public function addHeader($name, $value) + { + $this->getSwiftMessage()->getHeaders()->addTextHeader($name, $value); + return $this; + } + + /** + * Sets custom header value to the message. + * @param string $name header name. + * @param string|array $value header value or values. + * @return $this self reference. + * @since 2.0.6 + */ + public function setHeader($name, $value) + { + $headerSet = $this->getSwiftMessage()->getHeaders(); + + if ($headerSet->has($name)) { + $headerSet->remove($name); + } + + foreach ((array)$value as $v) { + $headerSet->addTextHeader($name, $v); + } + + return $this; + } + + /** + * Returns all values for the specified header. + * @param string $name header name. + * @return array header values list. + * @since 2.0.6 + */ + public function getHeader($name) + { + $headerSet = $this->getSwiftMessage()->getHeaders(); + if (!$headerSet->has($name)) { + return []; + } + + $headers = []; + foreach ($headerSet->getAll($name) as $header) { + $headers[] = $header->getValue(); + } + return $headers; + } + + /** + * Sets custom header values to the message. + * @param array $headers headers in format: `[name => value]`. + * @return $this self reference. + * @since 2.0.7 + */ + public function setHeaders($headers) + { + foreach ($headers as $name => $value) { + $this->setHeader($name, $value); + } + return $this; + } + + // SwiftMessage shortcuts : + + /** + * Set the return-path (the bounce address) of this message. + * @param string $address the bounce email address. + * @return $this self reference. + * @since 2.0.6 + */ + public function setReturnPath($address) + { + $this->getSwiftMessage()->setReturnPath($address); + return $this; + } + + /** + * Returns the return-path (the bounce address) of this message. + * @return string the bounce email address. + * @since 2.0.6 + */ + public function getReturnPath() + { + return $this->getSwiftMessage()->getReturnPath(); + } + + /** + * Set the priority of this message. + * @param int $priority priority value, should be an integer in range: `1..5`, + * where 1 is the highest priority and 5 is the lowest. + * @return $this self reference. + * @since 2.0.6 + */ + public function setPriority($priority) + { + $this->getSwiftMessage()->setPriority($priority); + return $this; + } + + /** + * Returns the priority of this message. + * @return int priority value as integer in range: `1..5`, + * where 1 is the highest priority and 5 is the lowest. + * @since 2.0.6 + */ + public function getPriority() + { + return $this->getSwiftMessage()->getPriority(); + } + + /** + * Sets the ask for a delivery receipt from the recipient to be sent to $addresses. + * @param string|array $addresses receipt receive email address(es). + * @return $this self reference. + * @since 2.0.6 + */ + public function setReadReceiptTo($addresses) + { + $this->getSwiftMessage()->setReadReceiptTo($addresses); + return $this; + } + + /** + * Get the addresses to which a read-receipt will be sent. + * @return string receipt receive email addresses. + * @since 2.0.6 + */ + public function getReadReceiptTo() + { + return $this->getSwiftMessage()->getReadReceiptTo(); + } +}