diff --git a/MailQueue.php b/MailQueue.php index ee8c301..5acaa34 100644 --- a/MailQueue.php +++ b/MailQueue.php @@ -19,24 +19,24 @@ * Configuration is the same as in `yii\switmailer\Mailer` with some additional properties to control the mail queue * * ~~~ - * 'components' => [ - * ... - * 'mailqueue' => [ - * 'class' => 'nterms\mailqueue\MailQueue', - * 'table' => '{{%mail_queue}}', - * 'mailsPerRound' => 10, - * 'maxAttempts' => 3, - * 'transport' => [ - * 'class' => 'Swift_SmtpTransport', - * 'host' => 'localhost', - * 'username' => 'username', - * 'password' => 'password', - * 'port' => '587', - * 'encryption' => 'tls', - * ], - * ], - * ... - * ], + * 'components' => [ + * ... + * 'mailqueue' => [ + * 'class' => 'nterms\mailqueue\MailQueue', + * 'table' => '{{%mail_queue}}', + * 'mailsPerRound' => 10, + * 'maxAttempts' => 3, + * 'transport' => [ + * 'class' => 'Swift_SmtpTransport', + * 'host' => 'localhost', + * 'username' => 'username', + * 'password' => 'password', + * 'port' => '587', + * 'encryption' => 'tls', + * ], + * ], + * ... + * ], * ~~~ * * @see http://www.yiiframework.com/doc-2.0/yii-swiftmailer-mailer.html @@ -48,90 +48,97 @@ */ class MailQueue extends Mailer { - const NAME = 'mailqueue'; - - /** - * @var string message default class name. - */ - public $messageClass = 'nterms\mailqueue\Message'; - - /** - * @var string the name of the database table to store the mail queue. - */ - public $table = '{{%mail_queue}}'; - - /** - * @var integer the default value for the number of mails to be sent out per processing round. - */ - public $mailsPerRound = 10; - - /** - * @var integer maximum number of attempts to try sending an email out. - */ - public $maxAttempts = 3; - - - /** - * @var boolean Purges messages from queue after sending - */ - public $autoPurge = true; - - /** - * Initializes the MailQueue component. - */ - public function init() - { - parent::init(); - } - - /** - * Sends out the messages in email queue and update the database. - * - * @return boolean true if all messages are successfully sent out - */ - public function process() - { - if (Yii::$app->db->getTableSchema($this->table) == null) { - throw new \yii\base\InvalidConfigException('"' . $this->table . '" not found in database. Make sure the db migration is properly done and the table is created.'); - } - - $success = true; - - $items = Queue::find()->where(['and', ['sent_time' => NULL], ['<', 'attempts', $this->maxAttempts], ['<=', 'time_to_send', date('Y-m-d H:i:s')]])->orderBy(['created_at' => SORT_ASC])->limit($this->mailsPerRound); - foreach ($items->each() as $item) { - if ($message = $item->toMessage()) { - $attributes = ['attempts', 'last_attempt_time']; - if ($this->send($message)) { - $item->sent_time = new \yii\db\Expression('NOW()'); - $attributes[] = 'sent_time'; - } else { - $success = false; - } - - $item->attempts++; - $item->last_attempt_time = new \yii\db\Expression('NOW()'); - - $item->updateAttributes($attributes); - } - } - - // Purge messages now? - if ($this->autoPurge) { - $this->purge(); - } - - return $success; - } - - - /** - * Deletes sent messages from queue. - * - * @return int Number of rows deleted - */ - - public function purge() - { - return Queue::deleteAll('sent_time IS NOT NULL'); - } + const NAME = 'mailqueue'; + + /** + * @var string message default class name. + */ + public $messageClass = 'nterms\mailqueue\Message'; + + /** + * @var string the name of the database table to store the mail queue. + */ + public $table = '{{%mail_queue}}'; + + /** + * @var integer the default value for the number of mails to be sent out per processing round. + */ + public $mailsPerRound = 10; + + /** + * @var integer maximum number of attempts to try sending an email out. + */ + public $maxAttempts = 3; + + + /** + * @var boolean Purges messages from queue after sending + */ + public $autoPurge = true; + + /** + * Initializes the MailQueue component. + */ + public function init() + { + parent::init(); + } + + /** + * Sends out the messages in email queue and update the database. + * + * @return boolean true if all messages are successfully sent out + */ + public function process() + { + if (Yii::$app->db->getTableSchema($this->table) == null) { + throw new \yii\base\InvalidConfigException('"' . $this->table . '" not found in database. Make sure the db migration is properly done and the table is created.'); + } + + $success = true; + + $items = Queue::find() + ->where(['and', ['sent_time' => NULL], ['<', 'attempts', $this->maxAttempts], ['<=', 'time_to_send', date('Y-m-d H:i:s')]]) + ->orderBy([ + 'priority' => SORT_ASC, + 'created_at' => SORT_ASC + ]) + ->limit($this->mailsPerRound); + + foreach ($items->each() as $item) { + if ($message = $item->toMessage()) { + $attributes = ['attempts', 'last_attempt_time']; + if ($this->send($message)) { + $item->sent_time = new \yii\db\Expression('NOW()'); + $attributes[] = 'sent_time'; + } else { + $success = false; + } + + $item->attempts++; + $item->last_attempt_time = new \yii\db\Expression('NOW()'); + + $item->updateAttributes($attributes); + } + } + + // Purge messages now? + if ($this->autoPurge) { + $this->purge(); + } + + return $success; + } + + + /** + * Deletes sent messages from queue. + * + * @return int Number of rows deleted + */ + + public function purge() + { + return Queue::deleteAll('sent_time IS NOT NULL'); + } } diff --git a/Message.php b/Message.php index 2ced2d0..76a10d7 100644 --- a/Message.php +++ b/Message.php @@ -17,6 +17,14 @@ */ class Message extends \yii\swiftmailer\Message { + + public $priority = 1000; + + public function setQueuePriority($priority = 1000) + { + $this->priority = $priority; + } + /** * Enqueue the message storing it in database. * @@ -25,16 +33,17 @@ class Message extends \yii\swiftmailer\Message */ public function queue($time_to_send = 'now') { - if($time_to_send == 'now') { + if ($time_to_send == 'now') { $time_to_send = time(); } - $item = new Queue(); - - $item->subject = $this->getSubject(); - $item->attempts = 0; - $item->swift_message = base64_encode(serialize($this)); - $item->time_to_send = date('Y-m-d H:i:s', $time_to_send); + $item = new Queue([ + 'priority' => $this->priority, + 'subject' => $this->getSubject(), + 'attempts' => 0, + 'swift_message' => base64_encode(serialize($this)), + 'time_to_send' => date('Y-m-d H:i:s', $time_to_send), + ]); return $item->save(); } diff --git a/README.md b/README.md index e74aa6a..4e6c491 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,27 @@ Yii::$app->mailqueue->compose('contact/html') ->send(); ``` +Priorities +---------- + +You can set a priority to the message: + +```php +Yii::$app->mailqueue->compose('contact/html') + ->setQueuePriority(500) + ->setFrom('from@domain.com') + ->setTo($form->email) + ->setSubject($form->subject) + ->setTextBody($form->body) + ->queue(); +``` + +Default priority is 1000 so passing any lower number will make that that emails gets sent before others. + +In the same way, if you pass a number bigger than 1000, those messages are going to have very low priority in the queue. + +Why 1000 as default? Just to give enough room to accomodate at most 999 other priorities. + License ------- diff --git a/migrations/m210718_062540_add_priority_column_to_mail_queue_table.php b/migrations/m210718_062540_add_priority_column_to_mail_queue_table.php new file mode 100644 index 0000000..0bb25e7 --- /dev/null +++ b/migrations/m210718_062540_add_priority_column_to_mail_queue_table.php @@ -0,0 +1,26 @@ +addColumn(Yii::$app->get(MailQueue::NAME)->table, 'priority', $this->integer()->notNull()->defaultValue(1000)); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropColumn(Yii::$app->get(MailQueue::NAME)->table, 'priority'); + } +} diff --git a/models/Queue.php b/models/Queue.php index 269d196..fb06fb8 100644 --- a/models/Queue.php +++ b/models/Queue.php @@ -17,6 +17,7 @@ * @property integer $sent_time * @property string $time_to_send * @property string $swift_message + * @property integer $priority */ class Queue extends ActiveRecord { @@ -51,7 +52,7 @@ public function behaviors() public function rules() { return [ - [['created_at', 'attempts', 'last_attempt_time', 'sent_time'], 'integer'], + [['created_at', 'attempts', 'last_attempt_time', 'sent_time', 'integer'], 'integer'], [['time_to_send', 'swift_message'], 'required'], [['subject'], 'safe'], ];