| Current Path : /var/www/surf/TYPO3/vendor/typo3/cms-form/Classes/Domain/Finishers/ |
| Current File : /var/www/surf/TYPO3/vendor/typo3/cms-form/Classes/Domain/Finishers/EmailFinisher.php |
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Form\Domain\Finishers;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Mime\Address;
use TYPO3\CMS\Core\Mail\FluidEmail;
use TYPO3\CMS\Core\Mail\MailerInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Fluid\View\TemplatePaths;
use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
use TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload;
use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
use TYPO3\CMS\Form\Service\TranslationService;
use TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper;
/**
* This finisher sends an email to one recipient
*
* Options:
*
* - templateName (mandatory): Template name for the mail body
* - templateRootPaths: root paths for the templates
* - layoutRootPaths: root paths for the layouts
* - partialRootPaths: root paths for the partials
* - variables: associative array of variables which are available inside the Fluid template
*
* The following options control the mail sending. In all of them, placeholders in the form
* of {...} are replaced with the corresponding form value; i.e. {email} as senderAddress
* makes the recipient address configurable.
*
* - subject (mandatory): Subject of the email
* - recipients (mandatory): Email addresses and human-readable names of the recipients
* - senderAddress (mandatory): Email address of the sender
* - senderName: Human-readable name of the sender
* - replyToRecipients: Email addresses and human-readable names of the reply-to recipients
* - carbonCopyRecipients: Email addresses and human-readable names of the copy recipients
* - blindCarbonCopyRecipients: Email addresses and human-readable names of the blind copy recipients
* - title: The title of the email - If not set "subject" is used by default
*
* Scope: frontend
*/
class EmailFinisher extends AbstractFinisher
{
/**
* @var array
*/
protected $defaultOptions = [
'recipientName' => '',
'senderName' => '',
'addHtmlPart' => true,
'attachUploads' => true,
];
/**
* Executes this finisher
* @see AbstractFinisher::execute()
*
* @throws FinisherException
*/
protected function executeInternal()
{
$languageBackup = null;
// Flexform overrides write strings instead of integers so
// we need to cast the string '0' to false.
if (
isset($this->options['addHtmlPart'])
&& $this->options['addHtmlPart'] === '0'
) {
$this->options['addHtmlPart'] = false;
}
$subject = (string)$this->parseOption('subject');
$recipients = $this->getRecipients('recipients');
$senderAddress = $this->parseOption('senderAddress');
$senderAddress = is_string($senderAddress) ? $senderAddress : '';
$senderName = $this->parseOption('senderName');
$senderName = is_string($senderName) ? $senderName : '';
$replyToRecipients = $this->getRecipients('replyToRecipients');
$carbonCopyRecipients = $this->getRecipients('carbonCopyRecipients');
$blindCarbonCopyRecipients = $this->getRecipients('blindCarbonCopyRecipients');
$addHtmlPart = $this->parseOption('addHtmlPart') ? true : false;
$attachUploads = $this->parseOption('attachUploads');
$title = (string)$this->parseOption('title') ?: $subject;
if ($subject === '') {
throw new FinisherException('The option "subject" must be set for the EmailFinisher.', 1327060320);
}
if (empty($recipients)) {
throw new FinisherException('The option "recipients" must be set for the EmailFinisher.', 1327060200);
}
if (empty($senderAddress)) {
throw new FinisherException('The option "senderAddress" must be set for the EmailFinisher.', 1327060210);
}
$formRuntime = $this->finisherContext->getFormRuntime();
$translationService = GeneralUtility::makeInstance(TranslationService::class);
if (is_string($this->options['translation']['language'] ?? null) && $this->options['translation']['language'] !== '') {
$languageBackup = $translationService->getLanguage();
$translationService->setLanguage($this->options['translation']['language']);
}
$mail = $this
->initializeFluidEmail($formRuntime)
->from(new Address($senderAddress, $senderName))
->to(...$recipients)
->subject($subject)
->format($addHtmlPart ? FluidEmail::FORMAT_BOTH : FluidEmail::FORMAT_PLAIN)
->assign('title', $title);
if (!empty($replyToRecipients)) {
$mail->replyTo(...$replyToRecipients);
}
if (!empty($carbonCopyRecipients)) {
$mail->cc(...$carbonCopyRecipients);
}
if (!empty($blindCarbonCopyRecipients)) {
$mail->bcc(...$blindCarbonCopyRecipients);
}
if (!empty($languageBackup)) {
$translationService->setLanguage($languageBackup);
}
if ($attachUploads) {
foreach ($formRuntime->getFormDefinition()->getRenderablesRecursively() as $element) {
if (!$element instanceof FileUpload) {
continue;
}
$file = $formRuntime[$element->getIdentifier()];
if ($file) {
if ($file instanceof FileReference) {
$file = $file->getOriginalResource();
}
$mail->attach($file->getContents(), $file->getName(), $file->getMimeType());
}
}
}
// TODO: DI should be used to inject the MailerInterface
GeneralUtility::makeInstance(MailerInterface::class)->send($mail);
}
protected function initializeFluidEmail(FormRuntime $formRuntime): FluidEmail
{
$templateConfiguration = $GLOBALS['TYPO3_CONF_VARS']['MAIL'];
if (is_array($this->options['templateRootPaths'] ?? null)) {
$templateConfiguration['templateRootPaths'] = array_replace_recursive(
$templateConfiguration['templateRootPaths'],
$this->options['templateRootPaths']
);
ksort($templateConfiguration['templateRootPaths']);
}
if (is_array($this->options['partialRootPaths'] ?? null)) {
$templateConfiguration['partialRootPaths'] = array_replace_recursive(
$templateConfiguration['partialRootPaths'],
$this->options['partialRootPaths']
);
ksort($templateConfiguration['partialRootPaths']);
}
if (is_array($this->options['layoutRootPaths'] ?? null)) {
$templateConfiguration['layoutRootPaths'] = array_replace_recursive(
$templateConfiguration['layoutRootPaths'],
$this->options['layoutRootPaths']
);
ksort($templateConfiguration['layoutRootPaths']);
}
$fluidEmail = GeneralUtility::makeInstance(
FluidEmail::class,
GeneralUtility::makeInstance(TemplatePaths::class, $templateConfiguration)
);
if (!isset($this->options['templateName']) || $this->options['templateName'] === '') {
throw new FinisherException('The option "templateName" must be set to use FluidEmail.', 1599834020);
}
// Migrate old template name to default FluidEmail name
if ($this->options['templateName'] === '{@format}.html') {
$this->options['templateName'] = 'Default';
}
// Set the PSR-7 request object if available
if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface) {
$fluidEmail->setRequest($GLOBALS['TYPO3_REQUEST']);
}
$fluidEmail
->setTemplate($this->options['templateName'])
->assignMultiple([
'finisherVariableProvider' => $this->finisherContext->getFinisherVariableProvider(),
'form' => $formRuntime,
]);
if (is_array($this->options['variables'] ?? null)) {
$fluidEmail->assignMultiple($this->options['variables']);
}
$fluidEmail
->getViewHelperVariableContainer()
->addOrUpdate(RenderRenderableViewHelper::class, 'formRuntime', $formRuntime);
return $fluidEmail;
}
/**
* Get mail recipients
*
* @param string $listOption List option name
*/
protected function getRecipients(string $listOption): array
{
$recipients = $this->parseOption($listOption) ?? [];
if (!is_array($recipients) || $recipients === []) {
return [];
}
$addresses = [];
foreach ($recipients as $address => $name) {
// The if is needed to set address and name with TypoScript
if (MathUtility::canBeInterpretedAsInteger($address)) {
if (is_array($name)) {
$address = $name[0] ?? '';
$name = $name[1] ?? '';
} else {
$address = $name;
$name = '';
}
}
if (!GeneralUtility::validEmail($address)) {
// Drop entries without valid address
continue;
}
$addresses[] = new Address($address, $name);
}
return $addresses;
}
}