I know, I know, this is not how I’m supposed to do it, but I can't think of something better.

This commit is contained in:
2023-11-01 17:03:15 -04:00
commit 3b9d50d949
10 changed files with 1057 additions and 0 deletions

283
src/Client.php Normal file
View File

@@ -0,0 +1,283 @@
<?php
namespace Siteworx\Mail;
use Siteworx\Mail\Exceptions\ValidationException;
use Siteworx\Mail\Transports\TransportInterface;
/**
* Class Client
*
* @package Siteworx
*/
class Client
{
/**
* @var TransportInterface
*/
private $_transport;
/**
* @var array
*/
private $_to = [];
/**
* @var array
*/
private $_cc = [];
/**
* @var array
*/
private $_bcc = [];
/**
* @var array
*/
private $_files = [];
/**
* @var string
*/
private $_from = '';
/**
* @var string
*/
private $_subject = '(No Subject)';
/**
* @var string
*/
private $_body = '';
/**
* @var bool
*/
private $_isHtml = false;
/**
* @var bool
*/
private $_catch = false;
/**
* @var bool|\DateTimeInterface
*/
private $_sendTime = false;
/**
* Client constructor.
*
* @param TransportInterface $transport
*/
public function __construct(TransportInterface $transport)
{
$this->_transport = $transport;
}
/**
* @param string $to
* @throws ValidationException
*/
public function addTo(string $to)
{
if (!Validator::validateEmailAddress($to)) {
throw new ValidationException('Email address is invalid');
}
$this->_to[] = $to;
}
/**
* @param array $to
* @throws ValidationException
*/
public function setAllTo(array $to)
{
foreach ($to as $item) {
if (!Validator::validateEmailAddress($item)) {
throw new ValidationException('Email address is invalid');
}
}
$this->_to = $to;
}
/**
* @param string $cc
* @throws ValidationException
*/
public function addCc(string $cc)
{
if (!Validator::validateEmailAddress($cc)) {
throw new ValidationException('Email address is invalid');
}
$this->_cc[] = $cc;
}
/**
* @param string $bcc
* @throws ValidationException
*/
public function addBcc(string $bcc)
{
if (!Validator::validateEmailAddress($bcc)) {
throw new ValidationException('Email address is invalid');
}
$this->_bcc[] = $bcc;
}
/**
* @param string $body
* @param bool $isHtml
*/
public function setBody(string $body, bool $isHtml = false)
{
$this->_body = $body;
$this->_isHtml = $isHtml;
}
/**
* @param string $subject
*/
public function setSubject(string $subject)
{
$this->_subject = $subject;
}
/**
* @param string $from
*
* @throws ValidationException
*/
public function setFrom(string $from)
{
if (!Validator::validateEmailAddress($from)) {
throw new ValidationException('Email address is invalid');
}
$this->_from = $from;
}
/**
* @param bool $catch
* @throws ValidationException
* @return mixed
*/
public function send(bool $catch = false)
{
$this->_catch = $catch;
$payload = $this->_buildPayload();
return $this->_transport->sentMailPayload($payload);
}
/**
* @param string $uuid
* @return bool
*/
public function delete(string $uuid): bool
{
return $this->_transport->deleteEmail($uuid);
}
/**
* @throws ValidationException
* @return array
*/
private function _buildPayload(): array
{
$this->_validateFields();
$mailPayload = [
'Destination' => [
'ToAddresses' => $this->_to
],
'Message' => [
'Subject' => [
'Data' => $this->_subject
]
],
'Source' => $this->_from
];
if (!empty($this->_cc)) {
$mailPayload['Destination']['CcAddresses'] = $this->_cc;
}
if (!empty($this->_bcc)) {
$mailPayload['Destination']['BccAddresses'] = $this->_bcc;
}
if ($this->_isHtml) {
$mailPayload['Message']['Body']['Html']['Data'] = $this->_body;
$mailPayload['Message']['Body']['Text']['Data'] = htmlentities($this->_body);
} else {
$mailPayload['Message']['Body']['Text']['Data'] = $this->_body;
}
if ($this->_catch) {
$mailPayload['Catch'] = true;
}
if ($this->_sendTime !== false) {
$mailPayload['ScheduledTime'] = $this->_sendTime->format('Y-m-d H:i:s');
}
if (\count($this->_files) > 0) {
$files = [];
foreach ($this->_files as $file) {
$files[] = [
'FileName' => basename($file),
'Content' => base64_encode(file_get_contents($file))
];
}
$mailPayload['Attachments'] = $files;
}
return $mailPayload;
}
/**
* @throws ValidationException
*/
private function _validateFields()
{
if (empty($this->_to)) {
throw new ValidationException('To Address is required');
}
if (empty($this->_from)) {
throw new ValidationException('From Address is required');
}
}
/**
* @param string $fileLocation
*
* @throws ValidationException
*/
public function addAttachment(string $fileLocation)
{
if (!file_exists($fileLocation)) {
throw new ValidationException('File does not exist.');
}
$this->_files[] = $fileLocation;
}
/**
* @param \DateTimeInterface $sendTime
*/
public function sendTime(\DateTimeInterface $sendTime)
{
$this->_sendTime = $sendTime;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Siteworx\Mail\Exceptions;
use Throwable;
class ValidationException extends \Exception
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,249 @@
<?php
namespace Siteworx\Mail\Transports;
use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
class ApiTransport implements TransportInterface
{
/**
* @var string
*/
private $_apiEndpoint = 'https://email.siteworxpro.com';
/**
* @var string
*/
private $_clientId = '';
/**
* @var string
*/
private $_clientSecret = '';
/**
* @var string
*/
private $_accessToken = '';
/**
* @var Guzzle
*/
private $_client;
/**
* @var CacheInterface
*/
private $_cache = null;
/**
* @var LoggerInterface
*/
private $_logger = null;
/**
* Client constructor.
*
* @param array $config
* @param Guzzle|null $guzzle
* @throws \Exception
*/
public function __construct(array $config = [], Guzzle $guzzle = null)
{
if (!isset($config['client_id'])) {
throw new \Exception('Client ID is missing.');
}
if (!isset($config['client_secret'])) {
throw new \Exception('Client Secret missing.');
}
$this->_client = $guzzle ?? new Guzzle();
$this->_clientId = $config['client_id'];
$this->_clientSecret = $config['client_secret'];
}
/**
* @param mixed $Cache
*/
public function setCache(CacheInterface $Cache)
{
$this->_cache = $Cache;
}
/**
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->_logger = $logger;
}
/**
* @return string
*/
public function getAccessToken(): string
{
return $this->_accessToken;
}
/**
* @param string $clientId
*/
public function setClientId(string $clientId)
{
$this->_clientId = $clientId;
}
/**
* @param string $clientSecret
*/
public function setClientSecret(string $clientSecret)
{
$this->_clientSecret = $clientSecret;
}
/**
* @param array $payload
* @return \stdClass
*/
public function sentMailPayload(array $payload)
{
$this->setToken();
if ($this->_logger !== null) {
$this->_logger->info('Sending Email.');
}
try {
$result = $this->_client->post($this->_apiEndpoint . '/api/email', [
'form_params' => $payload,
'headers' => [
'Authorization' => 'Bearer ' . $this->_accessToken
]
]);
$body = $result->getBody()->getContents();
$data = json_decode($body);
if ($this->_logger !== null) {
$this->_logger->info('Success!');
$this->_logger->debug(\json_encode($body));
}
} catch (ServerException $exception) {
$result = $exception->getResponse();
$body = $result->getBody()->getContents();
$data = json_decode($body);
if ($this->_logger !== null) {
$this->_logger->warning('An error occurred sending the email! (' . $result->getStatusCode() . ')');
$this->_logger->debug(\json_encode($body));
}
} catch (RequestException $exception) {
$result = $exception->getResponse();
$body = $result->getBody()->getContents();
$data = json_decode($body);
if ($this->_logger !== null) {
$this->_logger->warning('An error occurred sending the email! (' . $result->getStatusCode() . ')');
$this->_logger->debug(\json_encode($body));
}
}
return $data;
}
private function setToken()
{
if ($this->_cache !== null) {
$this->_accessToken = $this->_cache->get('access_token');
} else {
if ($this->_logger !== null) {
$this->_logger->notice('No cache available for client. Providing a cache interface can improve client response times.');
}
}
if (empty($this->_accessToken)) {
$this->refreshToken();
}
}
/**
* @return \stdClass
*/
private function refreshToken()
{
$params = [
'scope' => 'default',
'grant_type' => 'client_credentials',
'client_id' => $this->_clientId,
'client_secret' => $this->_clientSecret
];
try {
$result = $this->_client->post($this->_apiEndpoint . '/access_token', [
'form_params' => $params
]);
$body = $result->getBody()->getContents();
$data = json_decode($body);
$this->_accessToken = $data->access_token;
if ($this->_cache !== null) {
$this->_cache->set('access_token', $this->_accessToken, $data->expires_in);
}
} catch (ServerException $exception) {
$result = $exception->getResponse();
$body = $result->getBody()->getContents();
$data = json_decode($body);
} catch (RequestException $exception) {
$result = $exception->getResponse();
$body = $result->getBody()->getContents();
$data = json_decode($body);
}
return $data;
}
public function deleteEmail(string $uuid): bool
{
$this->setToken();
try {
$response = $this->_client->delete($this->_apiEndpoint .'/api/email/' . $uuid, [
'headers' => [
'Authorization' => 'Bearer ' . $this->_accessToken
]
]);
return $response->getStatusCode() === 200;
} catch (RequestException $exception) {
return false;
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Siteworx\Mail\Transports;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
interface TransportInterface
{
public function setCache(CacheInterface $cache);
public function setLogger(LoggerInterface $logger);
public function sentMailPayload(array $payload);
public function deleteEmail(string $uuid): bool;
}

31
src/Validator.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace Siteworx\Mail;
/**
* Class Validator
*
* @package Siteworx
*/
class Validator
{
/**
* @param string $email
* @return bool
*/
public static function validateEmailAddress(string $email): bool
{
return filter_var(self::extractEmailAddress($email), FILTER_VALIDATE_EMAIL) !== false;
}
private static function extractEmailAddress(string $email): string
{
$matches = [];
preg_match('^<[a-zA-Z@.\-_]+>^', $email, $matches);
return \count($matches) > 0 ? str_replace(['<', '>'], '', $matches[0]) : $email;
}
}