Refactor confirmation email sending

Aspect mock stopped working for me so I had to create a separate service
for sending confirmation emails.

[MAILPOET-1522]
This commit is contained in:
Pavel Dohnal
2018-10-11 12:06:49 +02:00
parent 4249c7a2cb
commit 70debcc828
7 changed files with 172 additions and 114 deletions

View File

@ -7,6 +7,7 @@ use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\SendConfirmationEmail;
use MailPoet\Subscribers\SendNewSubscriberNotification;
use MailPoet\Subscribers\Source;
use MailPoet\Tasks\Sending;
@ -254,7 +255,8 @@ class API {
}
protected function _sendConfirmationEmail(Subscriber $subscriber) {
return $subscriber->sendConfirmationEmail();
$sender = new SendConfirmationEmail();
return $sender->sendConfirmationEmail($subscriber);
}
protected function _scheduleWelcomeNotification(Subscriber $subscriber, array $segments) {

View File

@ -2,6 +2,7 @@
namespace MailPoet\Models;
use MailPoet\Mailer\Mailer;
use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Subscribers\SendConfirmationEmail;
use MailPoet\Subscribers\SendNewSubscriberNotification;
use MailPoet\Subscribers\Source;
use MailPoet\Util\Helpers;
@ -83,71 +84,6 @@ class Subscriber extends Model {
return self::where('wp_user_id', $wp_user->ID)->findOne();
}
function sendConfirmationEmail() {
$signup_confirmation = Setting::getValue('signup_confirmation');
if((bool)$signup_confirmation['enabled'] === false) {
return false;
}
$segments = $this->segments()->findMany();
$segment_names = array_map(function($segment) {
return $segment->name;
}, $segments);
$body = nl2br($signup_confirmation['body']);
// replace list of segments shortcode
$body = str_replace(
'[lists_to_confirm]',
'<strong>'.join(', ', $segment_names).'</strong>',
$body
);
// replace activation link
$body = Helpers::replaceLinkTags(
$body,
Subscription\Url::getConfirmationUrl($this),
array('target' => '_blank'),
'activation_link'
);
// build email data
$email = array(
'subject' => $signup_confirmation['subject'],
'body' => array(
'html' => $body,
'text' => $body
)
);
// convert subscriber to array
$subscriber = $this->asArray();
// set from
$from = (
!empty($signup_confirmation['from'])
&& !empty($signup_confirmation['from']['address'])
) ? $signup_confirmation['from']
: false;
// set reply to
$reply_to = (
!empty($signup_confirmation['reply_to'])
&& !empty($signup_confirmation['reply_to']['address'])
) ? $signup_confirmation['reply_to']
: false;
// send email
try {
$mailer = new Mailer(false, $from, $reply_to);
return $mailer->send($email, $subscriber);
} catch(\Exception $e) {
$this->setError($e->getMessage());
return false;
}
}
static function generateToken($email = null) {
if($email !== null) {
$auth_key = '';
@ -216,8 +152,8 @@ class Subscriber extends Model {
// link subscriber to segments
SubscriberSegment::subscribeToSegments($subscriber, $segment_ids);
// signup confirmation
$subscriber->sendConfirmationEmail();
$sender = new SendConfirmationEmail();
$sender->sendConfirmationEmail($subscriber);
if($subscriber->status === self::STATUS_SUBSCRIBED) {
$sender = new SendNewSubscriberNotification();

View File

@ -0,0 +1,91 @@
<?php
namespace MailPoet\Subscribers;
use MailPoet\Mailer\Mailer;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
use MailPoet\Subscription\Url;
use MailPoet\Util\Helpers;
class SendConfirmationEmail {
/** @var Mailer */
private $mailer;
/**
* @param Mailer|null $mailer
*/
function __construct($mailer = null) {
if($mailer) {
$this->mailer = $mailer;
}
}
function sendConfirmationEmail(Subscriber $subscriber) {
$signup_confirmation = Setting::getValue('signup_confirmation');
if((bool)$signup_confirmation['enabled'] === false) {
return false;
}
$segments = $subscriber->segments()->findMany();
$segment_names = array_map(function($segment) {
return $segment->name;
}, $segments);
$body = nl2br($signup_confirmation['body']);
// replace list of segments shortcode
$body = str_replace(
'[lists_to_confirm]',
'<strong>'.join(', ', $segment_names).'</strong>',
$body
);
// replace activation link
$body = Helpers::replaceLinkTags(
$body,
Url::getConfirmationUrl($subscriber),
array('target' => '_blank'),
'activation_link'
);
// build email data
$email = array(
'subject' => $signup_confirmation['subject'],
'body' => array(
'html' => $body,
'text' => $body
)
);
// set from
$from = (
!empty($signup_confirmation['from'])
&& !empty($signup_confirmation['from']['address'])
) ? $signup_confirmation['from']
: false;
// set reply to
$reply_to = (
!empty($signup_confirmation['reply_to'])
&& !empty($signup_confirmation['reply_to']['address'])
) ? $signup_confirmation['reply_to']
: false;
// send email
try {
if(!$this->mailer) {
$this->mailer = new Mailer(false, $from, $reply_to);
}
$this->mailer->getSenderNameAndAddress($from);
$this->mailer->getReplyToNameAndAddress($reply_to);
return $this->mailer->send($email, $subscriber);
} catch(\Exception $e) {
$subscriber->setError($e->getMessage());
return false;
}
}
}

View File

@ -33,7 +33,7 @@ class SendNewSubscriberNotification {
if($mailer) {
$this->mailer = $mailer;
} else {
$this->mailer = new \MailPoet\Mailer\Mailer();
$this->mailer = new \MailPoet\Mailer\Mailer(false, $this->constructSenderEmail());
}
}

View File

@ -59,7 +59,8 @@ $kernel->init(
array(
'debug' => true,
'cacheDir' => $cacheDir,
'includePaths' => [__DIR__ . '/../lib']
'includePaths' => [__DIR__ . '/../lib'],
'appDir' => __DIR__ . '/../'
)
);

View File

@ -1,7 +1,6 @@
<?php
namespace MailPoet\Test\Models;
use AspectMock\Test as Mock;
use Carbon\Carbon;
use Codeception\Util\Fixtures;
use MailPoet\Models\CustomField;
@ -1120,48 +1119,6 @@ class SubscriberTest extends \MailPoetTest {
);
}
function testItSendsConfirmationEmail() {
Mock::double('MailPoet\Mailer\Mailer', [
'__construct' => null,
'send' => function($email) {
return $email;
}
]);
Mock::double('MailPoet\Subscription\Url', [
'getConfirmationUrl' => 'http://example.com'
]);
$segment = Segment::createOrUpdate(
array(
'name' => 'Test segment'
)
);
SubscriberSegment::subscribeToSegments(
$this->subscriber,
array($segment->id)
);
$result = $this->subscriber->sendConfirmationEmail();
// email contains subscriber's lists
expect($result['body']['html'])->contains('<strong>Test segment</strong>');
// email contains activation link
expect($result['body']['html'])->contains('<a target="_blank" href="http://example.com">Click here to confirm your subscription.</a>');
}
function testItSetsErrorsWhenConfirmationEmailCannotBeSent() {
Mock::double('MailPoet\Mailer\Mailer', [
'__construct' => null,
'send' => function() {
throw new \Exception('send error');
}
]);
$this->subscriber->sendConfirmationEmail();
// error is set on the subscriber model object
expect($this->subscriber->getErrors()[0])->equals('send error');
}
function _after() {
\ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);

View File

@ -0,0 +1,71 @@
<?php
namespace MailPoet\Subscribers;
use AspectMock\Test as Mock;
use Codeception\Stub;
use MailPoet\Mailer\Mailer;
use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
class SendConfirmationEmailTest extends \MailPoetTest {
function testItSendsConfirmationEmail() {
Mock::double('MailPoet\Subscription\Url', [
'getConfirmationUrl' => 'http://example.com'
]);
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com'
]);
$mailer = Stub::makeEmpty(Mailer::class, [
'send' =>
Stub\Expected::once(function($email) {
expect($email['body']['html'])->contains('<strong>Test segment</strong>');
expect($email['body']['html'])->contains('<a target="_blank" href="http://example.com">Click here to confirm your subscription.</a>');
}),
], $this);
$sender = new SendConfirmationEmail($mailer);
$segment = Segment::createOrUpdate(
array(
'name' => 'Test segment'
)
);
SubscriberSegment::subscribeToSegments(
$subscriber,
array($segment->id)
);
$sender->sendConfirmationEmail($subscriber);
}
function testItSetsErrorsWhenConfirmationEmailCannotBeSent() {
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com'
]);
$mailer = Stub::makeEmpty(Mailer::class, [
'send' =>
Stub\Expected::once(function () {
throw new \Exception('send error');
}),
], $this);
$sender = new SendConfirmationEmail($mailer);
$sender->sendConfirmationEmail($subscriber);
// error is set on the subscriber model object
expect($subscriber->getErrors()[0])->equals('send error');
}
}