diff --git a/framework/yii/base/MailEvent.php b/framework/yii/base/MailEvent.php new file mode 100644 index 0000000..6e9da2e --- /dev/null +++ b/framework/yii/base/MailEvent.php @@ -0,0 +1,35 @@ + + * @since 2.0 + */ +class MailEvent extends Event +{ + + /** + * @var \yii\mail\MessageInterface mail message being send + */ + public $message; + /** + * @var boolean if message send was successful + */ + public $isSuccessful; + /** + * @var boolean whether to continue send. Event handlers of + * [[\yii\mail\BaseMailer::EVENT_BEFORE_SEND]] may set this property to decide whether + * to continue send or not. + */ + public $isValid = true; +} diff --git a/framework/yii/mail/BaseMailer.php b/framework/yii/mail/BaseMailer.php index 90565c9..baccbe2 100644 --- a/framework/yii/mail/BaseMailer.php +++ b/framework/yii/mail/BaseMailer.php @@ -12,6 +12,7 @@ use yii\base\Component; use yii\base\InvalidConfigException; use yii\base\ViewContextInterface; use yii\web\View; +use yii\base\MailEvent; /** * BaseMailer serves as a base class that implements the basic functions required by [[MailerInterface]]. @@ -28,6 +29,16 @@ use yii\web\View; */ abstract class BaseMailer extends Component implements MailerInterface, ViewContextInterface { + + /** + * @event \yii\base\MailEvent an event raised right before send. + * You may set [[\yii\base\MailEvent::isValid]] to be false to cancel the send. + */ + const EVENT_BEFORE_SEND = 'beforeSend'; + /** + * @event \yii\base\MailEvent an event raised right after send. + */ + const EVENT_AFTER_SEND = 'afterSend'; /** * @var string directory containing view files for this email messages. * This can be specified as an absolute path or path alias. @@ -206,6 +217,10 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont */ public function send($message) { + if (!$this->beforeSend($message)) { + return false; + } + $address = $message->getTo(); if (is_array($address)) { $address = implode(', ', array_keys($address)); @@ -213,10 +228,12 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont Yii::info('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); if ($this->useFileTransport) { - return $this->saveMessage($message); + $isSuccessful = $this->saveMessage($message); } else { - return $this->sendMessage($message); + $isSuccessful = $this->sendMessage($message); } + $this->afterSend($message, $isSuccessful); + return $isSuccessful; } /** @@ -297,4 +314,31 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont { return Yii::getAlias($this->viewPath) . DIRECTORY_SEPARATOR . $view; } + + /** + * This method is invoked right before mail send. + * You may override this method to do last-minute preparation for the message. + * If you override this method, please make sure you call the parent implementation first. + * @param MessageInterface $message + */ + public function beforeSend($message) + { + $event = new MailEvent(['message' => $message]); + $this->trigger(self::EVENT_BEFORE_SEND, $event); + return $event->isValid; + } + + /** + * This method is invoked right after mail was send. + * You may override this method to do some postprocessing or logging based on mail send status. + * If you override this method, please make sure you call the parent implementation first. + * @param MessageInterface $message + * @param boolean $isSuccessful + */ + public function afterSend($message, $isSuccessful) + { + $event = new MailEvent(['message' => $message, 'isSuccessful' => $isSuccessful]); + $this->trigger(self::EVENT_AFTER_SEND, $event); + } + } diff --git a/tests/unit/framework/mail/BaseMailerTest.php b/tests/unit/framework/mail/BaseMailerTest.php index 1c3ee22..54a7952 100644 --- a/tests/unit/framework/mail/BaseMailerTest.php +++ b/tests/unit/framework/mail/BaseMailerTest.php @@ -230,6 +230,17 @@ class BaseMailerTest extends TestCase $this->assertTrue(is_file($file)); $this->assertEquals($message->toString(), file_get_contents($file)); } + + public function testBeforeSendEvent() + { + $message = new Message(); + + $mailerMock = $this->getMockBuilder('yiiunit\framework\mail\Mailer')->setMethods(['beforeSend','afterSend'])->getMock(); + $mailerMock->expects($this->once())->method('beforeSend')->with($message)->will($this->returnValue(true)); + $mailerMock->expects($this->once())->method('afterSend')->with($message,true); + $mailerMock->send($message); + } + } /** @@ -243,6 +254,7 @@ class Mailer extends BaseMailer protected function sendMessage($message) { $this->sentMessages[] = $message; + return true; } }