cd6958eb21d9215d440d6c193940bd52005c0670
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Domain / Finishers / EmailFinisher.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Form\Domain\Finishers;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\Mail\MailMessage;
19 use TYPO3\CMS\Extbase\Domain\Model\FileReference;
20 use TYPO3\CMS\Fluid\View\StandaloneView;
21 use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
22 use TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload;
23 use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
24 use TYPO3\CMS\Form\Service\TranslationService;
25 use TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper;
26
27 /**
28 * This finisher sends an email to one recipient
29 *
30 * Options:
31 *
32 * - templatePathAndFilename (mandatory): Template path and filename for the mail body
33 * - layoutRootPath: root path for the layouts
34 * - partialRootPath: root path for the partials
35 * - variables: associative array of variables which are available inside the Fluid template
36 *
37 * The following options control the mail sending. In all of them, placeholders in the form
38 * of {...} are replaced with the corresponding form value; i.e. {email} as recipientAddress
39 * makes the recipient address configurable.
40 *
41 * - subject (mandatory): Subject of the email
42 * - recipientAddress (mandatory): Email address of the recipient
43 * - recipientName: Human-readable name of the recipient
44 * - senderAddress (mandatory): Email address of the sender
45 * - senderName: Human-readable name of the sender
46 * - replyToAddress: Email address of to be used as reply-to email (use multiple addresses with an array)
47 * - carbonCopyAddress: Email address of the copy recipient (use multiple addresses with an array)
48 * - blindCarbonCopyAddress: Email address of the blind copy recipient (use multiple addresses with an array)
49 * - format: format of the email (one of the FORMAT_* constants). By default mails are sent as HTML
50 *
51 * Scope: frontend
52 */
53 class EmailFinisher extends AbstractFinisher
54 {
55 const FORMAT_PLAINTEXT = 'plaintext';
56 const FORMAT_HTML = 'html';
57
58 /**
59 * @var array
60 */
61 protected $defaultOptions = [
62 'recipientName' => '',
63 'senderName' => '',
64 'format' => self::FORMAT_HTML,
65 'attachUploads' => true
66 ];
67
68 /**
69 * Executes this finisher
70 * @see AbstractFinisher::execute()
71 *
72 * @throws FinisherException
73 */
74 protected function executeInternal()
75 {
76 $formRuntime = $this->finisherContext->getFormRuntime();
77 $standaloneView = $this->initializeStandaloneView($formRuntime);
78
79 $translationService = TranslationService::getInstance();
80 if (isset($this->options['translation']['language']) && !empty($this->options['translation']['language'])) {
81 $languageBackup = $translationService->getLanguage();
82 $translationService->setLanguage($this->options['translation']['language']);
83 }
84 $message = $standaloneView->render();
85 if (!empty($languageBackup)) {
86 $translationService->setLanguage($languageBackup);
87 }
88
89 $subject = $this->parseOption('subject');
90 $recipientAddress = $this->parseOption('recipientAddress');
91 $recipientName = $this->parseOption('recipientName');
92 $senderAddress = $this->parseOption('senderAddress');
93 $senderName = $this->parseOption('senderName');
94 $replyToAddress = $this->parseOption('replyToAddress');
95 $carbonCopyAddress = $this->parseOption('carbonCopyAddress');
96 $blindCarbonCopyAddress = $this->parseOption('blindCarbonCopyAddress');
97 $format = $this->parseOption('format');
98 $attachUploads = $this->parseOption('attachUploads');
99
100 if (empty($subject)) {
101 throw new FinisherException('The option "subject" must be set for the EmailFinisher.', 1327060320);
102 }
103 if (empty($recipientAddress)) {
104 throw new FinisherException('The option "recipientAddress" must be set for the EmailFinisher.', 1327060200);
105 }
106 if (empty($senderAddress)) {
107 throw new FinisherException('The option "senderAddress" must be set for the EmailFinisher.', 1327060210);
108 }
109
110 $mail = $this->objectManager->get(MailMessage::class);
111
112 $mail->setFrom([$senderAddress => $senderName])
113 ->setTo([$recipientAddress => $recipientName])
114 ->setSubject($subject);
115
116 if (!empty($replyToAddress)) {
117 $mail->setReplyTo($replyToAddress);
118 }
119
120 if (!empty($carbonCopyAddress)) {
121 $mail->setCc($carbonCopyAddress);
122 }
123
124 if (!empty($blindCarbonCopyAddress)) {
125 $mail->setBcc($blindCarbonCopyAddress);
126 }
127
128 if ($format === self::FORMAT_PLAINTEXT) {
129 $mail->setBody($message, 'text/plain');
130 } else {
131 $mail->setBody($message, 'text/html');
132 }
133
134 $elements = $formRuntime->getFormDefinition()->getRenderablesRecursively();
135
136 if ($attachUploads) {
137 foreach ($elements as $element) {
138 if (!$element instanceof FileUpload) {
139 continue;
140 }
141 $file = $formRuntime[$element->getIdentifier()];
142 if ($file) {
143 if ($file instanceof FileReference) {
144 $file = $file->getOriginalResource();
145 }
146
147 $mail->attach(\Swift_Attachment::newInstance($file->getContents(), $file->getName(), $file->getMimeType()));
148 }
149 }
150 }
151
152 $mail->send();
153 }
154
155 /**
156 * @param FormRuntime $formRuntime
157 * @return StandaloneView
158 * @throws FinisherException
159 */
160 protected function initializeStandaloneView(FormRuntime $formRuntime): StandaloneView
161 {
162 if (!isset($this->options['templatePathAndFilename'])) {
163 throw new FinisherException('The option "templatePathAndFilename" must be set for the EmailFinisher.', 1327058829);
164 }
165
166 $format = ucfirst($this->parseOption('format'));
167
168 $this->options['templatePathAndFilename'] = strtr($this->options['templatePathAndFilename'], [
169 '{@format}' => $format
170 ]);
171
172 $standaloneView = $this->objectManager->get(StandaloneView::class);
173 $standaloneView->setTemplatePathAndFilename($this->options['templatePathAndFilename']);
174 $standaloneView->assign('finisherVariableProvider', $this->finisherContext->getFinisherVariableProvider());
175
176 if (isset($this->options['partialRootPaths']) && is_array($this->options['partialRootPaths'])) {
177 $standaloneView->setPartialRootPaths($this->options['partialRootPaths']);
178 }
179
180 if (isset($this->options['layoutRootPaths']) && is_array($this->options['layoutRootPaths'])) {
181 $standaloneView->setLayoutRootPaths($this->options['layoutRootPaths']);
182 }
183
184 if (isset($this->options['variables'])) {
185 $standaloneView->assignMultiple($this->options['variables']);
186 }
187
188 $standaloneView->assign('form', $formRuntime);
189 $standaloneView->getRenderingContext()
190 ->getViewHelperVariableContainer()
191 ->addOrUpdate(RenderRenderableViewHelper::class, 'formRuntime', $formRuntime);
192
193 return $standaloneView;
194 }
195 }