Skip to content

Commit

Permalink
Merge pull request #21 from WebFiori/dev
Browse files Browse the repository at this point in the history
feat: Improved Testing Mode
  • Loading branch information
usernane authored Apr 8, 2024
2 parents b3dc487 + 427d117 commit 0fafcf3
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 34 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ composer.lock
php-cs-fixer-v2.phar
.idea/*
php-cs-fixer.phar
clover.xml
tests/webfiori/tests/mail/Hello Email Message/*
.php_cs.cache
108 changes: 108 additions & 0 deletions tests/webfiori/tests/mail/EmailMessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
use PHPUnit\Framework\TestCase;
use webfiori\email\Email;
use webfiori\email\exceptions\SMTPException;
use webfiori\email\SendMode;
use webfiori\email\SMTPAccount;
use webfiori\email\SMTPServer;
use webfiori\file\exceptions\FileException;
use webfiori\file\File;
/**
* A test class for testing the class 'webfiori\framework\mail\EmailMessage'.
Expand Down Expand Up @@ -433,4 +435,110 @@ public function testTemplate03() {
. '</html>'.SMTPServer::NL, $message.'');

}
/**
* @test
*/
public function testStoreMode00() {
$message = new Email();
$this->assertEquals(SendMode::PROD, $message->getMode());
$this->assertTrue($message->setMode(SendMode::TEST_STORE, [
'store-path' => __DIR__
]));
$this->assertEquals(SendMode::TEST_STORE, $message->getMode());
$message->send();
$this->assertTrue(File::isFileExist(__DIR__.DIRECTORY_SEPARATOR.$message->getSubject().DIRECTORY_SEPARATOR.date('Y-m-d H-i-s').'.html'));
}
/**
* @test
*/
public function testStoreMode01() {
$this->expectException(FileException::class);
$this->expectExceptionMessage('Store path is not set for mode SendMode::TEST_STORE.');
$message = new Email();
$this->assertEquals(SendMode::PROD, $message->getMode());
$this->assertTrue($message->setMode(SendMode::TEST_STORE, [

]));
$this->assertEquals(SendMode::TEST_STORE, $message->getMode());
$message->send();
$this->assertTrue(File::isFileExist(__DIR__.DIRECTORY_SEPARATOR.$message->getSubject().DIRECTORY_SEPARATOR.date('Y-m-d H-i-s').'.html'));
}
/**
* @test
*/
public function testStoreMode02() {
$this->expectException(FileException::class);
$this->expectExceptionMessage('Store path does not exist: \''.__DIR__.DIRECTORY_SEPARATOR.'inv_p\'');
$message = new Email();
$this->assertEquals(SendMode::PROD, $message->getMode());
$this->assertTrue($message->setMode(SendMode::TEST_STORE, [
'store-path' => __DIR__.DIRECTORY_SEPARATOR.'inv_p'
]));
$this->assertEquals(SendMode::TEST_STORE, $message->getMode());
$message->send();
}
/**
* @test
*/
public function testSendMode00() {
$message = new Email(new SMTPAccount($this->acc01));
$this->assertTrue($message->setMode(SendMode::TEST_SEND, [
'send-addresses' => [
'[email protected]'
]
]));
$this->assertEquals(SendMode::TEST_SEND, $message->getMode());
$message->send();
$this->assertEquals([
'command' => 'QUIT',
'code' => 221,
'message' => '221 gator4189.hostgator.com closing connection',
'time' => date('Y-m-d H:i:s'),
], $message->getSMTPServer()->getLastLogEntry());
$this->assertTrue(true);
}
/**
* @test
*/
public function testSendMode01() {
$message = new Email(new SMTPAccount($this->acc01));
$this->assertTrue($message->setMode(SendMode::TEST_SEND, [
'send-addresses' => '[email protected]'
]));
$this->assertEquals(SendMode::TEST_SEND, $message->getMode());
$message->send();
$this->assertEquals([
'command' => 'QUIT',
'code' => 221,
'message' => '221 gator4189.hostgator.com closing connection',
'time' => date('Y-m-d H:i:s'),
], $message->getSMTPServer()->getLastLogEntry());
$this->assertTrue(true);
}
/**
* @test
*/
public function testSendMode02() {
$this->expectException(SMTPException::class);
$this->expectExceptionMessage('Recipients are not set for mode SendMode::TEST_SEND.');
$message = new Email(new SMTPAccount($this->acc01));
$this->assertTrue($message->setMode(SendMode::TEST_SEND, [

]));
$this->assertEquals(SendMode::TEST_SEND, $message->getMode());
$message->send();
}
}













159 changes: 125 additions & 34 deletions webfiori/email/Email.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace webfiori\email;

use TypeError;
use webfiori\email\exceptions\SMTPException;
use webfiori\file\exceptions\FileException;
use webfiori\file\File;
Expand Down Expand Up @@ -58,6 +59,8 @@ class Email {
private $inReplyTo;

private $log;
private $mode;
private $modeConfig;
private $priority;
/**
*
Expand Down Expand Up @@ -107,6 +110,8 @@ public function __construct(SMTPAccount $sendAccount = null) {
$this->beforeSendPool = [];
$this->afterSendPool = [];
$this->document = new HTMLDoc();
$this->mode = SendMode::PROD;
$this->modeConfig = [];

if ($sendAccount !== null) {
$this->setSMTPAccount($sendAccount);
Expand Down Expand Up @@ -371,6 +376,41 @@ public function getLang() {
public function getLog() : array {
return $this->getSMTPServer()->getLog();
}
/**
* Returns the mode at which the message will use when the method 'send' is called.
*
* @return string The method will return one of 3 values:
*
* <ul>
* <li><b>SendMode::PROD</b>: This is the default mode. The message will be
* sent to its recipients.</li>
* <li><b>SendMode::TEST_SEND</b>: This mode indicates that the message will be
* sent to a set of specified addresses by <b>$config</b> with meta-data
* of the message. Used to mimic actual process of sending a message.</li>
* <li><b>SendMode::TEST_STORE</b>: The message including its meta-data will
* be stored as HTML web page in specific path specified by <b>$confing</b>.</li>
* </ul>
*/
public function getMode() : string {
return $this->mode;
}
/**
* Returns an array that holds the configuration of send mode of the message.
*
* Possible indices of the are:
* <ul>
* <li><b>store-path</b>: Represents the location at which the
* message will be stored at when the mode <b>SendMode::TEST_STORE</b> is used.</li>
* <li><b>send-addresses</b>: Represents an array that holds
* the addresses at which the message will be sent to when the
* mode <b>SendMode::TEST_SEND</b> is used.</li>
* </ul>
*
* @return array An associative array.
*/
public function getModeConfig() : array {
return $this->modeConfig;
}
/**
* Returns the priority of the message.
*
Expand Down Expand Up @@ -541,52 +581,52 @@ public function removeAllRecipients() {
/**
* Sends the message.
*
* Note that if in testing environment, the method will attempt to store
* the email as HTML web page. Testing environment is set when the constant
* EMAIL_TESTING is defined and set to true in addition to having the
* constant EMAIL_TESTING_PATH defined.
*
* Additionally, the email can be sent to specific address by
* defining the constant EMAIL_TESTING_ADDRESS.
*
*/
public function send() {
$this->invokeBeforeSend();

if (defined('EMAIL_TESTING') && EMAIL_TESTING === true) {
$isStore = defined('EMAIL_TESTING_PATH') && File::isDirectory(EMAIL_TESTING_PATH, true);
$isSend = defined('EMAIL_TESTING_ADDRESS');
$this->setupBeoreTesting();
$sendMode = $this->getMode();

if ($isSend) {
$this->removeAllRecipients();
$addresees = explode(';', EMAIL_TESTING_ADDRESS);
if ($sendMode == SendMode::TEST_STORE) {
$config = $this->getModeConfig();

foreach ($addresees as $addr) {
$trimmed = trim($addr);
if (!isset($config['store-path'])) {
throw new FileException('Store path is not set for mode SendMode::TEST_STORE.');
}
$path = $config['store-path'];

if (strlen($trimmed) != 0) {
$this->addTo($trimmed);
}
}
if (!File::isDirectory($path)) {
throw new FileException('Store path does not exist: \''.$path.'\'');
}
$this->setupBeoreTesting();
$this->storeEmail($path);
$this->invokeAfterSend();

if ($isStore && File::isDirectory(EMAIL_TESTING_PATH, true)) {
$this->storeEmail(EMAIL_TESTING_PATH);
} else {
throw new FileException('"EMAIL_TESTING_PATH" is not valid.');
return;
} else if ($sendMode == SendMode::TEST_SEND) {
$config = $this->getModeConfig();

if (!isset($config['send-addresses'])) {
throw new SMTPException('Recipients are not set for mode SendMode::TEST_SEND.');
}
$rcpt = $config['send-addresses'];

if (gettype($rcpt) == 'string') {
$rcpt = explode(';', $rcpt);
}
$this->setupBeoreTesting();
$this->removeAllRecipients();

if (!$isSend) {
$this->invokeAfterSend();
foreach ($rcpt as $addr) {
$trimmed = trim($addr);

return;
if (strlen($trimmed) != 0) {
$this->addTo($trimmed);
}
}
}
}

$acc = $this->getSMTPAccount();


$server = $this->getSMTPServer();

if ($this->rcptCount() == 0) {
Expand Down Expand Up @@ -644,6 +684,45 @@ public function setLang(string $langCode = 'EN') : Email {

return $this;
}
/**
* Sets the mode at which the message will use when the send method is called.
*
* @param string $mode This can be one of 3 values:
* <ul>
* <li><b>SendMode::PROD</b>: This is the default mode. The message will be
* sent to its recipients.</li>
* <li><b>SendMode::TEST_SEND</b>: This mode indicates that the message will be
* sent to a set of specified addresses by <b>$config</b> with meta-data
* of the message. Used to mimic actual process of sending a message.</li>
* <li><b>SendMode::TEST_STORE</b>: The message including its meta-data will
* be stored as HTML web page in specific path specified by <b>$confing</b>.</li>
* </ul>
*
* @param array $config An array that holds send option configuration.
* The array can have following indices:
* <ul>
* <li><b>store-path</b>: Represents the location at which the
* message will be stored at when the mode <b>SendMode::TEST_STORE</b> is used.</li>
* <li><b>send-addresses</b>: Represents an array that holds
* the addresses at which the message will be sent to when the
* mode <b>SendMode::TEST_SEND</b> is used.</li>
* </ul>
*
* @return bool If the mode successfully updated, true is returned.
* Other than that, false is returned.
*/
public function setMode(string $mode, array $config = []) : bool {
$trimmed = strtolower(trim($mode));

if ($mode == SendMode::PROD || $mode == SendMode::TEST_SEND || $mode == SendMode::TEST_STORE) {
$this->mode = $trimmed;
$this->modeConfig = $config;

return true;
}

return false;
}
/**
* Sets the priority of the message.
*
Expand Down Expand Up @@ -790,7 +869,10 @@ private function priorityCommandHelper(): string {
} else {
$importanceHeaderVal = 'normal';
}
$this->getSMTPServer()->sendCommand('Priority: '.$priorityHeaderVal);
try {
$this->getSMTPServer()->sendCommand('Priority: '.$priorityHeaderVal);
} catch (TypeError $ex) {
}

return $importanceHeaderVal;
}
Expand All @@ -806,11 +888,20 @@ private function receiversCommandHelper($type) {
}
}
private function setupBeoreTesting() {
$acc = $this->getSMTPAccount();
try {
$acc = $this->getSMTPAccount();
} catch (TypeError $ex) {
$acc = null;
}

$headersTable = new HeadersTable();
$headersTable->addHeader('Importance', $this->priorityCommandHelper());
$headersTable->addHeader('From', $acc->getSenderName().' <'.$acc->getAddress().'>');

if ($acc !== null) {
$headersTable->addHeader('From', $acc->getSenderName().' <'.$acc->getAddress().'>');
} else {
$headersTable->addHeader('From', ' <NOT SPECIFIED>');
}
$headersTable->addHeader('To', $this->getReceiversStrHelper('to', false));
$headersTable->addHeader('CC', $this->getReceiversStrHelper('cc', false));
$headersTable->addHeader('BCC', $this->getReceiversStrHelper('bcc', false));
Expand Down
26 changes: 26 additions & 0 deletions webfiori/email/SendMode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
namespace webfiori\email;

/**
* Class that holds the constants used to set sending mode of an email message
* instance.
*
* @author Ibrahim
*/
class SendMode {
/**
* The default mode. Used to send the message to its recipients.
*/
const PROD = 'send';
/**
* This mode indicates that the message will be sent to a set of specified
* addresses as test including meta-data of the message. Used to mimic actual
* process of sending the message (similar to staging or QA env).
*/
const TEST_SEND = 'test_send';
/**
* This mode indicates that the message will be stored as HTML in specific
* path.
*/
const TEST_STORE = 'store';
}

0 comments on commit 0fafcf3

Please sign in to comment.