Commit a5a994a1 authored by Tim Wagner's avatar Tim Wagner
Browse files

[TASK] Fix email template & layout rendering

parent 3c5058ba
......@@ -43,6 +43,11 @@ class Layout extends AbstractEntity {
*/
protected $content = '';
/**
* @var string
*/
protected $headContent = '';
/**
* @return string
*/
......@@ -70,4 +75,18 @@ class Layout extends AbstractEntity {
public function setContent($content) {
$this->content = $content;
}
/**
* @return string
*/
public function getHeadContent(): string {
return $this->headContent;
}
/**
* @param string $headContent
*/
public function setHeadContent(string $headContent) {
$this->headContent = $headContent;
}
}
......@@ -26,6 +26,7 @@ namespace SGalinski\SgMail\Domain\Repository;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use SGalinski\SgMail\Domain\Model\Layout;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
......@@ -60,7 +61,7 @@ class LayoutRepository extends Repository {
* @param int $uid
* @param int $pid
* @param int $languageUid
* @return array|NULL
* @return Layout
*/
public function findByUidOrDefault(int $uid, int $pid, int $languageUid = 0) {
$query = $this->createQuery();
......@@ -70,18 +71,22 @@ class LayoutRepository extends Repository {
$query->setLimit(1);
if ($uid > 0) {
$result = $query->matching($query->equals('uid', $uid))->execute(TRUE)[0] ?? NULL;
if ($result) {
return $result;
}
$result = $query->matching($query->equals('uid', $uid))->execute();
} else {
$result = $query->matching(
$query->logicalAnd(
[
$query->equals('pid', $pid),
$query->equals('default', 1)
]
)
)->execute();
}
return $query->matching(
$query->logicalAnd([
$query->equals('pid', $pid),
$query->equals('default', 1)
])
)->execute(TRUE)[0] ?? NULL;
/** @var Layout $layout */
$layout = $result->getFirst();
return $layout;
}
/**
......
......@@ -27,6 +27,7 @@ namespace SGalinski\SgMail\Service;
***************************************************************/
use DateTime;
use SGalinski\SgMail\Domain\Model\Layout;
use SGalinski\SgMail\Domain\Model\Mail;
use SGalinski\SgMail\Domain\Model\Template;
use SGalinski\SgMail\Domain\Repository\LayoutRepository;
......@@ -72,117 +73,94 @@ class MailTemplateService {
* @var array
*/
private static $mailObjectCache = [];
/**
* @var \SGalinski\SgMail\Domain\Repository\TemplateRepository
*/
protected $templateRepository;
/**
* @var \SGalinski\SgMail\Domain\Repository\LayoutRepository
*/
protected $layoutRepository;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
*/
protected $persistenceManager;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
*/
protected $objectManager;
/**
* @var TYPO3\CMS\Core\Resource\ResourceFactory
*/
protected $resourceFactory;
/**
* @var string $toAddresses
*/
private $toAddresses = '';
/**
* @var string $fromAddress
*/
private $fromAddress = '';
/**
* @var string $ccAddresses
*/
private $ccAddresses;
/**
* @var string $replyToAddress
*/
private $replyToAddress = '';
/**
* @var string $language
*/
private $language = 'default';
/**
* @var boolean $ignoreMailQueue
*/
private $ignoreMailQueue = FALSE;
/**
* @var \TYPO3\CMS\Core\Mail\MailMessage $mailMessage
*/
private $mailMessage;
/**
* @var string $templateName
*/
private $templateName;
/**
* @var string $subject
*/
private $subject;
/**
* @var string $overwrittenEmailBody
*/
private $overwrittenEmailBody = '';
/**
* @var string $extensionKey
*/
private $extensionKey;
/**
* @var array $markers
*/
private $markers;
/**
* @var array $markerLabels
*/
private $markerLabels;
/**
* @var string $bccAddresses
*/
private $bccAddresses;
/**
* @var int
*/
private $priority = Mail::PRIORITY_LOWEST;
/**
* @var int
*/
private $pid;
/**
* @var string
*/
private $fromName = '';
/**
* @var \SGalinski\SgMail\Domain\Repository\TemplateRepository
*/
protected $templateRepository;
/**
* @var \SGalinski\SgMail\Domain\Repository\LayoutRepository
*/
protected $layoutRepository;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
*/
protected $persistenceManager;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
*/
protected $objectManager;
/**
* @var TYPO3\CMS\Core\Resource\ResourceFactory
*/
protected $resourceFactory;
/**
* @var string
*/
......@@ -272,13 +250,6 @@ class MailTemplateService {
}
}
/**
* @param string $fromName
*/
public function setFromName($fromName) {
$this->fromName = $fromName;
}
/**
* Provides translation for the marker data type
*
......@@ -304,59 +275,32 @@ class MailTemplateService {
}
/**
* @param string $toAddresses
* @return MailTemplateService
*/
public function setToAddresses($toAddresses): MailTemplateService {
$normalizedToAddresses = trim(preg_replace('~\x{00a0}~iu', ' ', $toAddresses));
$this->toAddresses = $normalizedToAddresses;
$addressesArray = GeneralUtility::trimExplode(',', $normalizedToAddresses, TRUE);
if (\count($addressesArray) > 1) {
$normalizedToAddresses = $addressesArray;
}
$this->mailMessage->setTo($normalizedToAddresses);
return $this;
}
/**
* @param string $fromAddress
* @param string $fromName
* @return MailTemplateService
*/
public function setFromAddress($fromAddress, $fromName = ''): MailTemplateService {
if ($fromAddress) {
$this->fromAddress = $fromAddress;
$this->mailMessage->setFrom($fromAddress, $fromName);
}
return $this;
}
/**
* @param string $ccAddresses
* @return MailTemplateService
* Return default markers for sg_mail
*
* @param string $translationKey
* @param array $marker
* @param string $extensionKey
* @return array
*/
public function setCcAddresses($ccAddresses): MailTemplateService {
if ($ccAddresses) {
$this->ccAddresses = $ccAddresses;
$this->mailMessage->setCc(GeneralUtility::trimExplode(',', $this->ccAddresses));
public static function getDefaultTemplateMarker($translationKey, array $marker, $extensionKey = 'sg_mail'): array {
$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang.xlf:' . $translationKey;
// Need the key for translations
if (\trim($extensionKey) === '') {
return [];
}
return $this;
}
/**
* @param string $replyToAddress
* @return MailTemplateService
*/
public function setReplyToAddress($replyToAddress): MailTemplateService {
if ($replyToAddress) {
$this->replyToAddress = $replyToAddress;
$this->mailMessage->setReplyTo($replyToAddress);
$generatedMarker = [];
foreach ($marker as $markerName) {
$generatedMarker[] = [
'marker' => $markerName,
'value' => $languagePath . '.example.' . $markerName,
'description' => $languagePath . '.description.' . $markerName,
'backend_translation_key' => $translationKey . '.example.' . $markerName,
'extension_key' => $extensionKey
];
}
return $this;
return $generatedMarker;
}
/**
......@@ -368,15 +312,6 @@ class MailTemplateService {
return $this;
}
/**
* @param boolean $ignoreMailQueue
* @return MailTemplateService
*/
public function setIgnoreMailQueue($ignoreMailQueue): MailTemplateService {
$this->ignoreMailQueue = $ignoreMailQueue;
return $this;
}
/**
* @param string $templateName
* @return MailTemplateService
......@@ -395,34 +330,6 @@ class MailTemplateService {
return $this;
}
/**
* @return string|string[]|null
*/
public function getMailBodyToSend() {
return $this->mailBodyToSend;
}
/**
* @param string|string[]|null $mailBodyToSend
*/
public function setMailBodyToSend($mailBodyToSend): void {
$this->mailBodyToSend = $mailBodyToSend;
}
/**
* @return string
*/
public function getSubjectToSend(): string {
return $this->subjectToSend;
}
/**
* @param string $subjectToSend
*/
public function setSubjectToSend(string $subjectToSend): void {
$this->subjectToSend = $subjectToSend;
}
/**
* @param array $markers
* @return MailTemplateService
......@@ -448,19 +355,6 @@ class MailTemplateService {
return $this;
}
/**
* @param string $bccAddresses
* @return MailTemplateService
*/
public function setBccAddresses($bccAddresses): MailTemplateService {
if ($bccAddresses) {
$this->bccAddresses = $bccAddresses;
$this->mailMessage->setBcc(GeneralUtility::trimExplode(',', $this->bccAddresses));
}
return $this;
}
/**
* @param int $priority
* @return MailTemplateService
......@@ -473,6 +367,7 @@ class MailTemplateService {
/**
* IMPORTANT: make sure to set $this->>ignoreMailQueue(TRUE), if you're using this method to add an attachment!
* Otherwise the attachment is ignored when sending the mail via mail queue.
*
* @param Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
......@@ -548,26 +443,6 @@ class MailTemplateService {
return $this;
}
/**
* Checks if a template is blacklisted for a given siteroot id
*
* @param string $extensionKey
* @param string $templateName
* @param int $siteRootId
* @return boolean
* @throws \InvalidArgumentException
* @throws \BadFunctionCallException
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
public static function isTemplateBlacklisted($extensionKey, $templateName, $siteRootId): bool {
$nonBlacklistedTemplates = BackendService::getNonBlacklistedTemplates($siteRootId);
if ($nonBlacklistedTemplates[$extensionKey]) {
return $nonBlacklistedTemplates[$extensionKey][$templateName] ? FALSE : TRUE;
}
return TRUE;
}
/**
* @return string
*/
......@@ -582,49 +457,6 @@ class MailTemplateService {
$this->subject = $subject;
}
/**
* @return string
*/
public function getOverwrittenEmailBody(): string {
return $this->overwrittenEmailBody;
}
/**
* @param string $overwrittenEmailBody
*/
public function setOverwrittenEmailBody(string $overwrittenEmailBody) {
$this->overwrittenEmailBody = $overwrittenEmailBody;
}
/**
* Return default markers for sg_mail
*
* @param string $translationKey
* @param array $marker
* @param string $extensionKey
* @return array
*/
public static function getDefaultTemplateMarker($translationKey, array $marker, $extensionKey = 'sg_mail'): array {
$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang.xlf:' . $translationKey;
// Need the key for translations
if (\trim($extensionKey) === '') {
return [];
}
$generatedMarker = [];
foreach ($marker as $markerName) {
$generatedMarker[] = [
'marker' => $markerName,
'value' => $languagePath . '.example.' . $markerName,
'description' => $languagePath . '.description.' . $markerName,
'backend_translation_key' => $translationKey . '.example.' . $markerName,
'extension_key' => $extensionKey
];
}
return $generatedMarker;
}
/**
* Set preview markers for the template editor
*
......@@ -665,21 +497,86 @@ class MailTemplateService {
}
/**
* Parses markers in an email View.
* !!! CHANGES THE SOURCE PATH AND IT SHOULD BE RESET BACK TO THE ORIGINAL!!!
* Send the Email
*
* @param string $text
* @param StandaloneView $emailView
* @return mixed
* @param bool $isPreview
* @param Template|null $template
* @return bool email was sent or added to mail queue successfully?
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException
*/
protected function parseMarkers($text, $emailView) {
$text = (string) $text;
if (strpos($text, '{') !== FALSE) {
$emailView->setTemplateSource($text);
return $emailView->render();
public function sendEmail($isPreview = FALSE, $isNewsletter = FALSE): bool {
if ($isPreview) { //TODO: remove this from here
$this->setIgnoreMailQueue(TRUE);
}
$success = FALSE;
return $text;
// Get page ID
// TODO: this doesn't belong here. The API user needs to provide the UID
$siteRootId = $this->getSiteRootId();
try {
$template = $this->getTemplate($siteRootId);
} catch (\Exception $e) {
return FALSE;
}
$registerService = GeneralUtility::makeInstance(RegisterService::class);
// Load the values from the template if they are set
if (!$isNewsletter && $template !== NULL) {
$this->loadTemplateValues($template);
}
// get default template content from register array
$defaultTemplateContent = $this->getDefaultTemplateContent($template, $registerService);
// set the ToAddress if there are no placeholders in it
// TODO: does this belong here?
if ($template !== NULL && \filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) {
$this->setToAddresses(\trim($template->getToAddress()));
}
$this->parseValuesForMail($template, $registerService, $defaultTemplateContent, $siteRootId);
$mail = $this->addMailToMailQueue(
$this->extensionKey, $this->templateName, $this->getSubjectToSend(), $this->getMailBodyToSend(),
$this->priority,
0, 0, $this->language, $siteRootId
);
self::$mailObjectCache[$mail->getUid()] = $mail; // add it to cache to avoid extra DB queries
if ($this->ignoreMailQueue) {
$success = $this->sendMailFromQueue($mail->getUid());
}
//TODO: this can be avoided if the sending logic is decoupled from this function
if ($isPreview) {
$mailRepository = $this->objectManager->get(MailRepository::class);
$mailRepository->remove($mail);
$this->persistenceManager->persistAll();
}
return $success;
}
/**
* @param boolean $ignoreMailQueue
* @return MailTemplateService
*/
public function setIgnoreMailQueue($ignoreMailQueue): MailTemplateService {
$this->ignoreMailQueue = $ignoreMailQueue;
return $this;
}
/**
* Get site root ID
*
* @return int
*/
public function getSiteRootId(): int {
$pageUid = $this->getPageUid();
return BackendService::getSiteRoot($pageUid);
}
/**
......@@ -735,19 +632,6 @@ class MailTemplateService {
return $pageUid;
}
/**
* Get the hash for the object cache
*
* @param $extensionKey
* @param $templateName
* @param $siteRootId
* @param $languageId
* @return string
*/
private function getTemplateHash($extensionKey, $templateName, $siteRootId, $languageId) {
return md5($extensionKey . '_' . $templateName . '_' . $siteRootId . '_' . $languageId);
}
/**
* Get the template object
*
......@@ -780,6 +664,144 @@ class MailTemplateService {
return $template;
}
/**
* Checks if a template is blacklisted for a given siteroot id
*
* @param string $extensionKey
* @param string $templateName
* @param int $siteRootId
* @return boolean
* @throws \InvalidArgumentException
* @throws \BadFunctionCallException
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
public static function isTemplateBlacklisted($extensionKey, $templateName, $siteRootId): bool {
$nonBlacklistedTemplates = BackendService::getNonBlacklistedTemplates($siteRootId);
if ($nonBlacklistedTemplates[$extensionKey]) {
return $nonBlacklistedTemplates[$extensionKey][$templateName] ? FALSE : TRUE;
}
return TRUE;
}
/**
* Get the hash for the object cache
*
* @param $extensionKey
* @param $templateName
* @param $siteRootId
* @param $languageId
* @return string
*/
private function getTemplateHash($extensionKey, $templateName, $siteRootId, $languageId) {
return md5($extensionKey . '_' . $templateName . '_' . $siteRootId . '_' . $languageId);
}
/**
* use all values from the given template
*