RprtCli/app/src/Utils/Mailer/MailerService.php

179 lines
5.5 KiB
PHP

<?php
declare(strict_types=1);
// src/Utils/Mailer/MailerService.php
namespace RprtCli\Utils\Mailer;
use RprtCli\Utils\Configuration\ConfigurationInterface;
use RprtCli\Utils\PdfExport\PdfExportInterface;
use Symfony\Component\Mime\Email;
use \Exception;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
/**
* Send emails with invoices as attachments.
*
* https://symfony.com/doc/current/mailer.html
*/
class MailerService implements MailerInterface {
protected $config;
protected $pdf;
// Data properties.
protected $to;
protected $subject;
protected $text;
protected $attachment;
protected $templatePath;
protected $email;
public function __construct(ConfigurationInterface $config, PdfExportInterface $pdf) {
$this->config = $config;
$this->pdf = $pdf;
}
public function setRecipients(array $to): void
{
$this->to = $to;
}
public function setSubject(string $subject): void {
$this->subject = $subject;
}
public function setAttachment(string $path): void {
// @TODO - add some error handling.
$this->attachment = $path;
}
public function getProperty(string $property) {
// Only for simple value properies - string and numbers.
// from, to, subject.
if (!isset($this->{$property})) {
$value = $this->config->get('email.' . $property, FALSE);
if (!$value) {
$value = readline("Property {$property} is not configured. Enter value: ");
}
$this->{$property} = $value;
}
return $this->{$property};
}
protected function getRecipients() {
if (!isset($this->to)) {
$value = $this->config->get('email.to', FALSE);
if (!$value) {
$value = explode(',', readline('Provide recipients\' emails separated by a comma: '));
}
$this->to = $value;
}
return $this->to;
}
private function readPassword($prompt = "Enter Password:") {
echo $prompt;
system('stty -echo');
$password = trim(fgets(STDIN));
system('stty echo');
return $password;
}
protected function getPasswordProperty() {
if (!isset($this->password)) {
$value = $this->config->get('email.password', FALSE);
if (!$value) {
$value = $this->readPassword();
}
$this->password = $value;
}
return $this->password;
}
public function sendMail(string $from, array $to, string $subject, string $text, array $attachment = []): void {
$email = new Email();
$email->from($from);
$email->to(...$to);
// @TODO use twig for templates. Create new template service.
// https://github.com/symfony/mailer
$email->subject($subject);
$email->text($text);
if (!empty($attachment)) {
if (!isset($attachment['path'])) {
var_dump('Attachment path missing!');
}
else {
$email->attachFromPath($attachment['path'], $attachment['name'] ?? null, $attachment['type'] ?? null);
}
}
// Not sure whether it would be nicer to use class property instead of variable.
$transport = $this->getTransport();
$mailer = $this->getMailer($transport);
$mailer->send($email);
}
public function getTransport() {
// @TODO remove username and password from config.
$username = rawurlencode($this->getProperty('username'));
$password = rawurlencode($this->getPasswordProperty());
// If your credentials contain special characters, you must URL-encode them.
// $mailer_dsn = "gmail+smtp://{$username}:{$password}@default";
$mailer_dsn = "gmail://{$username}:{$password}@localhost?encryption=tls&auth_mode=oauth";
return Transport::fromDsn($mailer_dsn);
}
public function getMailer($transport) {
return new Mailer($transport);
}
public function sendDefaultMail(string $output): void {
$tokens = $this->pdf->gatherTokensForTemplate($this->getEmailTemplatePath(), FALSE, $this->getDefaultTokens(), 'email.tokens');
$text = $this->pdf->replaceTokensInTemplate($this->getEmailTemplatePath(), $tokens);
$this->sendMail(
$this->getProperty('from'),
$this->getProperty('to'),
$this->getProperty('subject'),
$text,
['path' => $output, 'Invoice', 'application/pdf']
);
}
public function getDefaultTokens(): array {
$tokens = [];
$date = strtotime('-1 month');
$tokens['month'] = date('F', $date);
$tokens['year'] = date('Y', $date);
return $tokens;
}
protected function getEmailTemplatePath(): ?string {
if (!isset($this->templatePath)) {
$template_path = $this->config->get('email.template_path', FALSE);
if (!$template_path) {
$template_path = readline('Enter template file path: ');
}
if (!file_exists($template_path)) {
throw new Exception('Template file not found!');
}
$this->templatePath = $template_path;
}
return $this->templatePath;
}
public function setEmailTemplatePath(string $path): void {
if (file_exists($path)) {
$this->templatePath = $path;
return;
}
throw new Exception('Email template file not found!');
}
}