Commit 5700a416 authored by Kevin von Spiczak's avatar Kevin von Spiczak
Browse files

Merge branch 'master' into Feature_ImproveFinishers

parents d15c53a0 7d8b50f7
......@@ -332,7 +332,9 @@ class MailController extends ActionController {
if (\count($ccAddresses) > 0) {
foreach ($ccAddresses as $ccAddress) {
if (!filter_var($ccAddress, FILTER_VALIDATE_EMAIL) && trim($ccAddress) !== '') {
if (!(strpos($ccAddress, '{') !== FALSE
&& strpos($ccAddress, '{') < strpos($ccAddress, '}'))
&& !filter_var($ccAddress, FILTER_VALIDATE_EMAIL) && trim($ccAddress) !== '') {
$message = LocalizationUtility::translate('backend.error_cc', 'sg_mail');
$this->addFlashMessage($message, '', FlashMessage::WARNING);
......@@ -344,7 +346,9 @@ class MailController extends ActionController {
$bccAddresses = GeneralUtility::trimExplode(',', $parameter['bcc']);
if (\count($bccAddresses) > 0) {
foreach ($bccAddresses as $bccAddress) {
if (!filter_var($bccAddress, FILTER_VALIDATE_EMAIL) && trim($bccAddress) !== '') {
if (!(strpos($bccAddress, '{') !== FALSE
&& strpos($bccAddress, '{') < strpos($bccAddress, '}'))
&& !filter_var($bccAddress, FILTER_VALIDATE_EMAIL) && trim($bccAddress) !== '') {
$message = LocalizationUtility::translate('backend.error_bcc', 'sg_mail');
$this->addFlashMessage($message, '', FlashMessage::WARNING);
......@@ -379,7 +383,6 @@ class MailController extends ActionController {
foreach ((array) $parameters['templates'] as $key => $template) {
$mailTemplateService->setLanguage($key);
$mailTemplateService->setToAddresses($parameters['emailAddress']);
$mailTemplateService->setFromAddress($template['fromMail']);
$mailTemplateService->setTemplateName($parameters['selectedTemplate']);
$mailTemplateService->setExtensionKey($parameters['selectedExtension']);
$mailTemplateService->setPreviewMarkers();
......
......@@ -391,7 +391,9 @@ class NewsletterController extends ActionController {
if (\count($ccAddresses) > 0) {
foreach ($ccAddresses as $ccAddress) {
if (!filter_var($ccAddress, FILTER_VALIDATE_EMAIL) && trim($ccAddress) !== '') {
if (!(strpos($ccAddress, '{') !== FALSE
&& strpos($ccAddress, '{') < strpos($ccAddress, '}'))
&& !filter_var($ccAddress, FILTER_VALIDATE_EMAIL) && trim($ccAddress) !== '') {
$message = LocalizationUtility::translate('backend.error_cc', 'sg_mail');
$this->addFlashMessage($message, '', FlashMessage::WARNING);
......@@ -403,7 +405,9 @@ class NewsletterController extends ActionController {
$bccAddresses = GeneralUtility::trimExplode(',', $parameter['bcc']);
if (\count($bccAddresses) > 0) {
foreach ($bccAddresses as $bccAddress) {
if (!filter_var($bccAddress, FILTER_VALIDATE_EMAIL) && trim($bccAddress) !== '') {
if (!(strpos($bccAddress, '{') !== FALSE
&& strpos($bccAddress, '{') < strpos($bccAddress, '}'))
&& !filter_var($bccAddress, FILTER_VALIDATE_EMAIL) && trim($bccAddress) !== '') {
$message = LocalizationUtility::translate('backend.error_bcc', 'sg_mail');
$this->addFlashMessage($message, '', FlashMessage::WARNING);
......@@ -420,20 +424,23 @@ class NewsletterController extends ActionController {
);
$mailIsSend = FALSE;
$mailTemplateService->setSubject($parameter['subject']);
$mailTemplateService->setReplyToAddress($parameter['replyTo']);
$mailTemplateService->setTemplateName($parameters['selectedTemplate']);
$mailTemplateService->setExtensionKey($parameters['selectedExtension']);
$mailTemplateService->setFromAddress($parameter['fromMail']);
$mailTemplateService->setOverwrittenFromName($parameter['fromName']);
$mailTemplateService->setOverwrittenFromMail($parameter['fromMail']);
$mailTemplateService->setSubject($parameter['subject']);
$mailTemplateService->setOverwrittenReplyTo($parameter['replyTo']);
if (!$this->request->getArgument('sendRealEmails')) {
// Send test emails
$message = LocalizationUtility::translate('backend.success_mail', 'sg_mail');
foreach ((array) $parameters['templates'] as $key => $template) {
$mailTemplateService->setLanguage($key);
$mailTemplateService->setToAddresses($parameters['emailAddress']);
$mailTemplateService->setOverwrittenToAddresses($parameters['emailAddress']);
$mailTemplateService->setOverwrittenEmailBody($parameter['content']);
$mailTemplateService->setSubject($template['subject']);
$mailTemplateService->setOverWrittenFromName($template['fromName']);
$mailTemplateService->setOverWrittenFromMail($template['fromMail']);
$mailTemplateService->setMarkers([
'user' => [
'username' => 'username@example.com',
......@@ -470,9 +477,10 @@ class NewsletterController extends ActionController {
foreach ((array) $parameters['templates'] as $key => $template) {
$mailTemplateService->setLanguage($key);
$mailTemplateService->setOverwrittenEmailBody($parameter['content']);
$mailTemplateService->setBccAddresses($parameter['bcc']);
$mailTemplateService->setCcAddresses($parameter['cc']);
$mailTemplateService->setOverwrittenEmailBody($template['content']);
$mailTemplateService->setSubject($template['subject']);
$mailTemplateService->setOverwrittenBcc($template['bcc']);
$mailTemplateService->setOverwrittenCc($template['cc']);
foreach ($recipients as $recipient) {
......@@ -480,6 +488,7 @@ class NewsletterController extends ActionController {
$mailTemplateService->setToAddresses($recipient['email']);
$mailTemplateService->setMarkers(['user' => $recipient]);
// no real error handling here, one must check the MailQueue
$mailTemplateService->sendEmail(FALSE);
} catch (\Exception $e) {
// Invalid email address could not be loaded to queue
......
......@@ -181,7 +181,7 @@ class BackendService {
}
}
return $siteRoot['uid'];
return (int) $siteRoot['uid'];
}
/**
......
......@@ -63,6 +63,16 @@ class MailTemplateService {
const REGISTER_FILE = 'Register.php';
const CONFIG_PATH = 'Configuration/MailTemplates';
/**
* @var array
*/
private static $templateObjectCache = [];
/**
* @var array
*/
private static $mailObjectCache = [];
/**
* @var string $toAddresses
*/
......@@ -113,6 +123,36 @@ class MailTemplateService {
*/
private $overwrittenEmailBody = '';
/**
* @var string $overwrittenBcc
*/
private $overwrittenBcc;
/**
* @var string $overwrittenFromName
*/
private $overwrittenFromName;
/**
* @var string $overwrittenFromMail
*/
private $overwrittenFromMail;
/**
* @var string $overwrittenReplyTo
*/
private $overwrittenReplyTo;
/**
* @var string $overwrittenToAddresses
*/
private $overwrittenToAddresses;
/**
* @var string $overwrittenCc
*/
private $overwrittenCc;
/**
* @var string $extensionKey
*/
......@@ -173,6 +213,100 @@ class MailTemplateService {
*/
protected $resourceFactory;
/**
* @var string
*/
private $mailBodyToSend;
/**
* @var string
*/
private $subjectToSend;
/**
* @return string
*/
public function getOverwrittenBcc(): string {
return $this->overwrittenBcc;
}
/**
* @param string $overwrittenBcc
*/
public function setOverwrittenBcc(string $overwrittenBcc): void {
$this->overwrittenBcc = $overwrittenBcc;
}
/**
* @return string
*/
public function getOverwrittenCc(): string {
return $this->overwrittenCc;
}
/**
* @param string $overwrittenCc
*/
public function setOverwrittenCc(string $overwrittenCc): void {
$this->overwrittenCc = $overwrittenCc;
}
/**
* @return string
*/
public function getOverwrittenFromName(): string {
return $this->overwrittenFromName;
}
/**
* @param string $overwrittenFromName
*/
public function setOverwrittenFromName(string $overwrittenFromName): void {
$this->overwrittenFromName = $overwrittenFromName;
}
/**
* @return string
*/
public function getOverwrittenFromMail(): string {
return $this->overwrittenFromMail;
}
/**
* @param string $overwrittenFromMail
*/
public function setOverwrittenFromMail(string $overwrittenFromMail): void {
$this->overwrittenFromMail = $overwrittenFromMail;
}
/**
* @return string
*/
public function getOverwrittenReplyTo(): string {
return $this->overwrittenReplyTo;
}
/**
* @param string $overwrittenReplyTo
*/
public function setOverwrittenReplyTo(string $overwrittenReplyTo): void {
$this->overwrittenReplyTo = $overwrittenReplyTo;
}
/**
* @return string
*/
public function getOverwrittenToAddresses(): string {
return $this->overwrittenToAddresses;
}
/**
* @param string $overwrittenToAddresses
*/
public function setOverwrittenToAddresses(string $overwrittenToAddresses): void {
$this->overwrittenToAddresses = $overwrittenToAddresses;
}
/**
* MailTemplateService constructor.
*
......@@ -363,6 +497,34 @@ 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
......@@ -603,18 +765,27 @@ class MailTemplateService {
}
/**
* Send the Email
* Parses markers in an email View.
* !!! CHANGES THE SOURCE PATH AND IT SHOULD BE RESET BACK TO THE ORIGINAL!!!
*
* @param bool $isPreview
* @return bool email was sent or added to mail queue successfully?
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws \InvalidArgumentException
* @throws \BadFunctionCallException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \Exception
* @param string $text
* @param StandaloneView $emailView
* @return mixed
*/
public function sendEmail($isPreview = FALSE): bool {
$success = FALSE;
protected function parseMarkers($text, $emailView) {
if (strpos($text, '{') !== FALSE) {
$emailView->setTemplateSource($text);
return $emailView->render();
}
return $text;
}
/**
* Gets the current PageUid
*
* @return int
*/
protected function getPageUid(): int {
if (TYPO3_MODE === 'FE') {
/** @var TypoScriptFrontendController $typoscriptFrontendController */
$typoscriptFrontendController = $GLOBALS['TSFE'];
......@@ -628,35 +799,71 @@ class MailTemplateService {
}
if ($pageUid === 0) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages'
);
$rootPageRows = $queryBuilder->select('*')
->from('pages')
->where(
$queryBuilder->expr()->eq(
'is_siteroot', 1
)
$pageUid = $this->getAnyRootPageUid();
}
return $pageUid;
}
/**
* Gets the page uid of any root page in the page tree
*
* @return int
*/
private function getAnyRootPageUid() {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages'
);
$rootPageRows = $queryBuilder->select('*')
->from('pages')
->where(
$queryBuilder->expr()->eq(
'is_siteroot', 1
)
->andWhere(
$queryBuilder->expr()->eq(
'hidden', 0
)
)
->andWhere(
$queryBuilder->expr()->eq(
'hidden', 0
)
->execute()->fetchAll();
)
->execute()->fetchAll();
if ($rootPageRows && \count($rootPageRows)) {
$pageUid = (int) $rootPageRows[0]['uid'];
}
if ($rootPageRows && \count($rootPageRows)) {
$pageUid = (int) $rootPageRows[0]['uid'];
}
$siteRootId = BackendService::getSiteRoot($pageUid);
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
*
* @param int $siteRootId
* @return null|object|Template|FALSE
* @throws \Exception
*/
private function getTemplate($siteRootId) {
$isTemplateBlacklisted = self::isTemplateBlacklisted($this->extensionKey, $this->templateName, $siteRootId);
if ($isTemplateBlacklisted) {
// @TODO throw error or log ?
return FALSE;
throw new \Exception('The template is blacklisted');
}
$templateHash = $this->getTemplateHash($this->extensionKey, $this->templateName, $siteRootId, $this->language);
if (isset(self::$templateObjectCache[$templateHash])
&& self::$templateObjectCache[$templateHash] instanceof Template) {
return self::$templateObjectCache[$templateHash];
}
/** @var Template $template */
$template = $this->templateRepository->findOneByTemplate(
$this->extensionKey, $this->templateName, $this->language, $siteRootId
......@@ -667,52 +874,60 @@ class MailTemplateService {
$this->extensionKey, $this->templateName, 'default', $siteRootId
);
}
self::$templateObjectCache[$templateHash] = $template;
return $template;
}
// if there is a template, prefer those values
if ($template) {
$this->loadTemplateValues($template);
}
// get default template content from register array
$registerService = GeneralUtility::makeInstance(RegisterService::class);
/**
* Get the default content for this template
*
* @param Template|null $template
* @param RegisterService $registerService
* @return bool|false|string
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
protected function getDefaultTemplateContent($template, $registerService) {
$defaultTemplateContent =
$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templateContent'];
// If there is no template for this language, use the default template
if ($template === NULL) {
if ($defaultTemplateContent === NULL) {
$templatePath =
$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templatePath'];
if ($template === NULL && $defaultTemplateContent === NULL) {
$templatePath =
$registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['templatePath'];
// only standard template file is considered since version 4.1
$defaultTemplateFile = $templatePath . 'template.html';
if (\file_exists($defaultTemplateFile)) {
$defaultTemplateContent = \file_get_contents($defaultTemplateFile);
} else {
// use configured default html template
/** @var TypoScriptSettingsService $typoScriptSettingsService */
$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
$defaultTemplateFile = GeneralUtility::getFileAbsFileName(
$tsSettings['mail']['defaultHtmlTemplate']
);
// only standard template file is considered since version 4.1
$defaultTemplateFile = $templatePath . 'template.html';
if (\file_exists($defaultTemplateFile)) {
$defaultTemplateContent = \file_get_contents($defaultTemplateFile);
} else {
// use configured default html template
/** @var TypoScriptSettingsService $typoScriptSettingsService */
$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
$defaultTemplateFile = GeneralUtility::getFileAbsFileName(
$tsSettings['mail']['defaultHtmlTemplate']
);
if (\file_exists($defaultTemplateFile)) {
$defaultTemplateContent = \file_get_contents($defaultTemplateFile);
} else {
return FALSE;
}
return FALSE;
}
}
} elseif (\filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) {
$this->setToAddresses(\trim($template->getToAddress()));
}
if ($isPreview) {
$this->setIgnoreMailQueue(TRUE);
}
return $defaultTemplateContent;
}
/**
* Sets the values to send the mail with from the template or register service
*
* @param Template|null $template
* @param RegisterService $registerService
* @param string $defaultTemplateContent
* @param int $siteRootId
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
protected function extractValuesForMail($template, RegisterService $registerService, $defaultTemplateContent, $siteRootId): void {
/** @var StandaloneView $emailView */
$emailView = $this->objectManager->get(StandaloneView::class);
$emailView->assignMultiple($this->markers);
......@@ -724,18 +939,16 @@ class MailTemplateService {
$overwrittenSubject = $this->subject;
}
// parse markers
if ($template !== NULL) {
$emailView->setTemplateSource(
\trim(empty($overwrittenSubject) ? $template->getSubject() : $overwrittenSubject)
$subject = $this->parseMarkers(
trim(empty($overwrittenSubject) ? $template->getSubject() : $overwrittenSubject),
$emailView
);
$subject = $emailView->render();
$emailView->setTemplateSource(
$this->getTemplateSource(
empty($overwrittenEmailBody) ? $template->getContent() : $overwrittenEmailBody,
$template->getLayout(), $siteRootId
)
);
$layoutId = $template->getLayout();
$templateContent = $template->getContent();
$this->setSubjectToSend($subject);
} else {
$subject = $registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['subject'];
if (\is_array($subject)) {
......@@ -744,33 +957,140 @@ class MailTemplateService {
[$this->extensionKey][$this->templateName]['subject'][$this->language]
);
}
$subject = $this->parseMarkers(
(empty($overwrittenSubject) ? $subject : $overwrittenSubject),
$emailView
);
$emailView->setTemplateSource(empty($overwrittenSubject) ? $subject : $overwrittenSubject);
$subject = $emailView->render();
$layoutId = 0;
$templateContent = $defaultTemplateContent;
}
$this->setSubjectToSend($subject);
//TODO: is this object even in use somewhere?
$this->mailMessage->setSubject($subject);
$emailView->setTemplateSource(
$this->getTemplateSource(
empty($overwrittenEmailBody) ? $defaultTemplateContent : $overwrittenEmailBody,
0, $siteRootId
)
if ($this->fromAddress === '') {
$fromMail = $this->parseMarkers(
empty($this->overwrittenFromMail) ? $template->getFromMail() : $this->overwrittenFromMail,
$emailView
);
$this->setFromAddress($fromMail);
}
$this->mailMessage->setSubject($subject);
if ($this->fromName === '') {
$fromName = $this->parseMarkers(
(empty($this->overwrittenFromName) ? $template->getFromName() : $this->overwrittenFromName),
$emailView
);
$this->setFromName($fromName);
}
if ($this->replyToAddress === '') {
$replyTo = $this->parseMarkers(
(empty($this->overwrittenReplyTo) ? $template->getReplyTo() : $this->overwrittenReplyTo),
$emailView
);
$this->setReplyToAddress($replyTo);
}
if (empty($this->ccAddresses)) {
$cc = $this->parseMarkers(
(empty($this->overwrittenCc) ? $template->getCc() : $this->overwrittenCc),
$emailView
);
$this->setCcAddresses($cc);
}
if (empty($this->bccAddresses)) {
$bcc = $this->parseMarkers(
(empty($this->overwrittenBcc) ? $template->getBcc() : $this->overwrittenBcc),
$emailView
);
$this->setBccAddresses($bcc);
}