Browse Source

Email components hierarchy created.

SwiftMailer applied as email solution.
tags/2.0.0-beta
Paul Klimov 11 years ago
parent
commit
492f35621c
  1. 2
      .travis.yml
  2. 125
      framework/yii/email/BaseMailer.php
  3. 125
      framework/yii/email/BaseMessage.php
  4. 34
      framework/yii/email/Message.php
  5. 180
      framework/yii/email/swift/Mailer.php
  6. 116
      framework/yii/email/swift/Message.php
  7. 9
      framework/yii/email/swift/autoload.php
  8. 97
      tests/unit/framework/email/BaseMailerTest.php
  9. 90
      tests/unit/framework/email/swift/MailerTest.php
  10. 40
      tests/unit/framework/email/swift/MessageTest.php

2
.travis.yml

@ -18,7 +18,7 @@ before_script:
- tests/unit/data/travis/cubrid-setup.sh
script:
- phpunit --coverage-clover tests/unit/runtime/coveralls/clover.xml --verbose --exclude-group mssql,oci,wincache,xcache,zenddata
- phpunit --coverage-clover tests/unit/runtime/coveralls/clover.xml --verbose --exclude-group mssql,oci,wincache,xcache,zenddata,swiftmailer
after_script:
- php vendor/bin/coveralls

125
framework/yii/email/BaseMailer.php

@ -0,0 +1,125 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\email;
use yii\base\Component;
use yii\base\InvalidConfigException;
use Yii;
/**
* BaseMailer provides the basic interface for the email mailer application component.
* It provides the default configuration for the email messages.
* Particular implementation of mailer should provide implementation for the [[send()]] method.
*
* @see BaseMessage
*
* @property array $view view instance or its array configuration.
* @property array $defaultMessageConfig configuration, which should be applied by default to any
* new created email message instance.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
abstract class BaseMailer extends Component
{
/**
* @var \yii\base\View|array view instance or its array configuration.
*/
private $_view = [];
/**
* @var array configuration, which should be applied by default to any new created
* email message instance.
* For example:
* ~~~
* array(
* 'encoding' => 'UTF-8',
* 'from' => 'noreply@mydomain.com',
* 'bcc' => 'email.test@mydomain.com',
* )
* ~~~
*/
private $_defaultMessageConfig = [];
/**
* @param array|\yii\base\View $view view instance or its array configuration.
* @throws \yii\base\InvalidConfigException on invalid argument.
*/
public function setView($view)
{
if (!is_array($view) && !is_object($view)) {
throw new InvalidConfigException('"' . get_class($this) . '::view" should be either object or array, "' . gettype($view) . '" given.');
}
$this->_view = $view;
}
/**
* @return \yii\base\View view instance.
*/
public function getView()
{
if (!is_object($this->_view)) {
$this->_view = $this->createView($this->_view);
}
return $this->_view;
}
/**
* @param array $defaultMessageConfig default message config
*/
public function setDefaultMessageConfig(array $defaultMessageConfig)
{
$this->_defaultMessageConfig = $defaultMessageConfig;
}
/**
* @return array default message config
*/
public function getDefaultMessageConfig()
{
return $this->_defaultMessageConfig;
}
/**
* Creates view instance from given configuration.
* @param array $config view configuration.
* @return \yii\base\View view instance.
*/
protected function createView(array $config)
{
if (!array_key_exists('class', $config)) {
$config['class'] = '\yii\base\View';
}
$config['context'] = $this;
return Yii::createObject($config);
}
/**
* Sends the given email message.
* @param object $message email message instance
* @return boolean whether the message has been sent.
*/
abstract public function send($message);
/**
* Sends a couple of messages at once.
* Note: some particular mailers may benefit from sending messages as batch,
* saving resources, for example on open/close connection operations,
* they may override this method to create their specific implementation.
* @param array $messages list of email messages, which should be sent.
* @return integer number of successfull sends
*/
public function sendMultiple(array $messages) {
$successCount = 0;
foreach ($messages as $message) {
if ($this->send($message)) {
$successCount++;
}
}
return $successCount;
}
}

125
framework/yii/email/BaseMessage.php

@ -0,0 +1,125 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\email;
use yii\base\InvalidParamException;
use yii\base\Object;
use yii\helpers\FileHelper;
use Yii;
/**
* BaseMessage represent the single email message.
* It functionality depends on application component 'email',
* which should provide the actual email sending functionality as well as
* default message configuration.
*
* @see BaseMailer
*
* @property \yii\email\BaseMailer $mailer mailer component instance. This property is read-only.
* @property string|array $from sender email address, if array is given, its first element should
* be sender email address, second - sender name.
* @property string|array $to receiver email address, if array is given, its first element should
* be receiver email address, second - receiver name.
* @property string $subject message subject.
* @property string $text message plain text content.
* @property string $html message HTML content.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
abstract class BaseMessage extends Object
{
/**
* @return \yii\email\BaseMailer
*/
public function getMailer()
{
return Yii::$app->getComponent('email');
}
/**
* Initializes the object.
* This method is invoked at the end of the constructor after the object is initialized with the
* given configuration.
*/
public function init()
{
Yii::configure($this, $this->getMailer()->getDefaultMessageConfig());
}
/**
* Sends this email message.
* @return boolean success.
*/
public function send()
{
return $this->getMailer()->send($this);
}
/**
* Sets message sender.
* @param string|array $from sender email address, if array is given,
* its first element should be sender email address, second - sender name.
*/
abstract public function setFrom($from);
/**
* Sets message receiver.
* @param string|array $to receiver email address, if array is given,
* its first element should be receiver email address, second - receiver name.
*/
abstract public function setTo($to);
/**
* Sets message subject.
* @param string $subject message subject
*/
abstract public function setSubject($subject);
/**
* Sets message plain text content.
* @param string $text message plain text content.
*/
abstract public function setText($text);
/**
* Sets message HTML content.
* @param string $html message HTML content.
*/
abstract public function setHtml($html);
/**
* Create file attachment for the email message.
* @param string $content attachment file content.
* @param string $fileName attachment file name.
* @param string $contentType MIME type of the attachment file, by default 'application/octet-stream' will be used.
*/
abstract public function createAttachment($content, $fileName, $contentType = 'application/octet-stream');
/**
* Attaches existing file to the email message.
* @param string $fileName full file name
* @param string $contentType MIME type of the attachment file, if empty it will be suggested automatically.
* @param string $attachFileName name, which should be used for attachment, if empty file base name will be used.
* @throws \yii\base\InvalidParamException if given file does not exist.
*/
public function attachFile($fileName, $contentType = null, $attachFileName = null)
{
if (!file_exists($fileName)) {
throw new InvalidParamException('Unable to attach file "' . $fileName . '": file does not exists!');
}
if (empty($contentType)) {
$contentType = FileHelper::getMimeType($fileName);
}
if (empty($attachFileName)) {
$attachFileName = basename($fileName);
}
$content = file_get_contents($fileName);
$this->createAttachment($content, $attachFileName, $contentType);
}
}

34
framework/yii/email/Message.php

@ -0,0 +1,34 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\email;
use yii\email\swift\Message as SwiftMessage;
/**
* Message provides the email message sending functionality.
*
* Usage:
* ~~~
* $email = new Message();
* $email->from = 'sender@domain.com';
* $email->to = 'receiver@domain.com';
* $email->subject = 'Message Subject';
* $email->text = 'Message Content';
* $email->send();
* ~~~
*
* This particular class uses 'SwiftMailer' library to perform the message sending.
* Note: you can replace usage of this class by your own one, using [[Yii::$classMap]]:
* ~~~
* Yii::$classMap['yii\email\Message'] = '/path/to/my/email/Message.php'
* ~~~
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class Message extends SwiftMessage {}

180
framework/yii/email/swift/Mailer.php

@ -0,0 +1,180 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\email\swift;
use yii\base\InvalidConfigException;
use yii\email\BaseMailer;
/**
* Mailer based on SwiftMailer library.
*
* By default PHP 'mail' function will be used as default email transport.
* You can setup different email transport via [[vendorMailer]] property:
* ~~~
* 'components' => array(
* ...
* 'email' => array(
* 'class' => 'yii\email\swift\Mailer',
* 'transport' => [
* 'class' => 'Swift_SmtpTransport',
* 'host' => 'localhost',
* 'username' => 'username',
* 'password' => 'password',
* 'port' => '587',
* 'encryption' => 'tls',
* ],
* ),
* ...
* ),
* ~~~
*
* @see http://swiftmailer.org
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class Mailer extends BaseMailer
{
/**
* @var string|callback SwiftMailer autoloader callback or path to autoloader file.
* If the SwiftMailer classes autoloading is already managed in some other place,
* for example via Composer, you should leave this field blank.
*/
public $autoload;
/**
* @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 \yii\base\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
*/
public function init()
{
$this->setupSwiftMailerAutoload();
}
/**
* Sets up the SwiftMailer autoloader, if it is specified.
*/
protected function setupSwiftMailerAutoload()
{
if (!class_exists('Swift', false)) {
if (empty($this->autoload)) {
$this->autoload = __DIR__ . '/autoload.php';
}
if (is_string($this->autoload)) {
if (file_exists($this->autoload)) {
require_once($this->autoload);
} elseif (function_exists($this->autoload)) {
spl_autoload_register($this->autoload);
} else {
throw new InvalidConfigException('"' . get_class($this) . '::autoload" value "' . $this->autoload . '" is invalid: no such function or file exists.');
}
} else {
spl_autoload_register($this->autoload);
}
}
}
/**
* @inheritdoc
*/
public function send($message)
{
return ($this->getSwiftMailer()->send($message->getSwiftMessage()) > 0);
}
/**
* Creates Swift mailer instance.
* @return \Swift_Mailer mailer instance.
*/
protected function createSwiftMailer()
{
return \Swift_Mailer::newInstance($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 (array_key_exists('class', $config)) {
$className = $config['class'];
unset($config['class']);
} else {
$className = 'Swift_MailTransport';
}
$transport = call_user_func([$className, 'newInstance']);
if (!empty($config)) {
foreach ($config as $name => $value) {
if (property_exists($transport, $name)) {
$transport->$name = $value;
} else {
$setter = 'set' . $name;
if (method_exists($transport, $setter)) {
$transport->$setter($value);
} else {
throw new InvalidConfigException('Setting unknown property: ' . get_class($transport) . '::' . $name);
}
}
}
}
return $transport;
}
/**
* Creates the Swift email message instance.
* @return \Swift_Message email message instance.
*/
public function createSwiftMessage()
{
return new \Swift_Message();
}
}

116
framework/yii/email/swift/Message.php

@ -0,0 +1,116 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\email\swift;
use yii\email\BaseMessage;
/**
* Email message based on SwiftMailer library.
*
* @see http://swiftmailer.org/docs/messages.html
* @see \yii\email\swift\Mailer
*
* @method \yii\email\swift\Mailer getMailer() returns mailer instance.
* @property \Swift_Message $swiftMessage vendor message instance.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class Message extends BaseMessage
{
/**
* @var \Swift_Message Swift message instance.
*/
private $_swiftMessage;
/**
* @return \Swift_Message Swift message instance.
*/
public function getSwiftMessage()
{
if (!is_object($this->_swiftMessage)) {
$this->_swiftMessage = $this->getMailer()->createSwiftMessage();
}
return $this->_swiftMessage;
}
/**
* Sets message sender.
* @param string|array $from sender email address, if array is given,
* its first element should be sender email address, second - sender name.
*/
public function setFrom($from)
{
if (is_array($from)) {
list ($address, $name) = $from;
} else {
$address = $from;
$name = null;
}
$this->getSwiftMessage()->setFrom($address, $name);
$this->getSwiftMessage()->setReplyTo($address, $name);
}
/**
* Sets message receiver.
* @param string|array $to receiver email address, if array is given,
* its first element should be receiver email address, second - receiver name.
*/
public function setTo($to)
{
if (is_array($to)) {
list ($address, $name) = $to;
} else {
$address = $to;
$name = null;
}
$this->getSwiftMessage()->setTo($address, $name);
}
/**
* Sets message subject.
* @param string $subject message subject
*/
public function setSubject($subject)
{
$this->getSwiftMessage()->setSubject($subject);
}
/**
* Sets message plain text content.
* @param string $text message plain text content.
*/
public function setText($text)
{
$this->getSwiftMessage()->setBody($text, 'text/plain');
}
/**
* Sets message HTML content.
* @param string $html message HTML content.
*/
public function setHtml($html)
{
$this->getSwiftMessage()->setBody($html, 'text/html');
}
/**
* Create file attachment for the email message.
* @param string $content - attachment file content.
* @param string $fileName - attachment file name.
* @param string $contentType - MIME type of the attachment file, by default 'application/octet-stream' will be used.
*/
public function createAttachment($content, $fileName, $contentType = 'application/octet-stream')
{
if (empty($contentType)) {
$contentType = 'application/octet-stream';
}
$attachment = \Swift_Attachment::newInstance($content, $fileName, $contentType);
$this->getSwiftMessage()->attach($attachment);
}
}

9
framework/yii/email/swift/autoload.php

@ -0,0 +1,9 @@
<?php
/**
* This file attempts to register autoloader for the Swift library, assuming
* it is located under the 'vendor' path.
*
* @var $this \yii\email\swift\Mailer
*/
$swiftMailerLibPath = Yii::getAlias('@vendor/swiftmailer/swiftmailer/lib');
require_once $swiftMailerLibPath . '/swift_required.php';

97
tests/unit/framework/email/BaseMailerTest.php

@ -0,0 +1,97 @@
<?php
namespace yiiunit\framework\email;
use Yii;
use yii\base\View;
use yii\email\BaseMailer;
use yii\email\BaseMessage;
use yiiunit\TestCase;
/**
* @group email
*/
class BaseMailerTest extends TestCase
{
public function setUp()
{
$this->mockApplication();
Yii::$app->setComponent('email', $this->createTestEmailComponent());
}
/**
* @return Mailer test email component instance.
*/
protected function createTestEmailComponent()
{
$component = new Mailer();
return $component;
}
// Tests :
public function testSetupView()
{
$mailer = new Mailer();
$view = new View();
$mailer->setView($view);
$this->assertEquals($view, $mailer->getView(), 'Unable to setup view!');
}
public function testGetDefaultView()
{
$mailer = new Mailer();
$view = $mailer->getView();
$this->assertTrue(is_object($view), 'Unable to get default view!');
}
public function testDefaultMessageConfig()
{
$defaultMessageConfig = array(
'id' => 'test-id',
'encoding' => 'test-encoding',
);
Yii::$app->getComponent('email')->setDefaultMessageConfig($defaultMessageConfig);
$message = new Message();
foreach ($defaultMessageConfig as $name => $value) {
$this->assertEquals($value, $message->$name);
}
}
}
/**
* Test Mailer class
*/
class Mailer extends BaseMailer
{
public $sentMessages = array();
public function send($message)
{
$this->sentMessages[] = $message;
}
}
/**
* Test Message class
*/
class Message extends BaseMessage
{
public $id;
public $encoding;
public function setFrom($from) {}
public function setTo($to) {}
public function setSubject($subject) {}
public function setText($text) {}
public function setHtml($html) {}
public function createAttachment($content, $fileName, $contentType = 'application/octet-stream') {}
}

90
tests/unit/framework/email/swift/MailerTest.php

@ -0,0 +1,90 @@
<?php
namespace yiiunit\framework\email\swift;
use Yii;
use yii\email\swift\Mailer;
use yii\email\swift\Message;
use yiiunit\TestCase;
/**
* @group email
* @group swiftmailer
*/
class MailerTest extends TestCase
{
public function setUp()
{
$this->mockApplication(array(
'vendorPath' => Yii::getAlias('@yiiunit/vendor')
));
Yii::$app->setComponent('email', $this->createTestEmailComponent());
}
/**
* @return Mailer test email component instance.
*/
protected function createTestEmailComponent()
{
$component = new Mailer();
return $component;
}
// Tests :
public function testSetupTransport()
{
$mailer = new Mailer();
$transport = \Swift_MailTransport::newInstance();
$mailer->setTransport($transport);
$this->assertEquals($transport, $mailer->getTransport(), 'Unable to setup transport!');
}
/**
* @depends testSetupTransport
*/
public function testConfigureTransport()
{
$mailer = new Mailer();
$transportConfig = [
'class' => 'Swift_SmtpTransport',
'host' => 'localhost',
];
$mailer->setTransport($transportConfig);
$transport = $mailer->getTransport();
$this->assertTrue(is_object($transport), 'Unable to setup transport via config!');
$this->assertEquals($transportConfig['class'], get_class($transport), 'Invalid transport class!');
$this->assertEquals($transportConfig['host'], $transport->getHost(), 'Invalid transport host!');
}
public function testGetSwiftMailer()
{
$mailer = new Mailer();
$this->assertTrue(is_object($mailer->getSwiftMailer()), 'Unable to get Swift mailer instance!');
}
public function testCreateSwiftMessage()
{
$mailer = new Mailer();
$message = $mailer->createSwiftMessage();
$this->assertTrue(is_object($message), 'Unable to create Swift message instance!');
}
/**
* @depends testGetSwiftMailer
* @depends testCreateSwiftMessage
*/
public function testSend()
{
$emailAddress = 'someuser@somedomain.com';
$message = new Message();
$message->setTo($emailAddress);
$message->setFrom($emailAddress);
$message->setSubject('Yii Swift Test');
$message->setText('Yii Swift Test body');
$message->send();
$this->assertTrue(true);
}
}

40
tests/unit/framework/email/swift/MessageTest.php

@ -0,0 +1,40 @@
<?php
namespace yiiunit\framework\email\swift;
use Yii;
use yii\email\swift\Mailer;
use yii\email\swift\Message;
use yiiunit\TestCase;
/**
* @group email
* @group swiftmailer
*/
class MessageTest extends TestCase
{
public function setUp()
{
$this->mockApplication(array(
'vendorPath' => Yii::getAlias('@yiiunit/vendor')
));
Yii::$app->setComponent('email', $this->createTestEmailComponent());
}
/**
* @return Mailer test email component instance.
*/
protected function createTestEmailComponent()
{
$component = new Mailer();
return $component;
}
// Tests :
public function testGetSwiftMessage()
{
$message = new Message();
$this->assertTrue(is_object($message->getSwiftMessage()), 'Unable to get Swift message!');
}
}
Loading…
Cancel
Save