diff --git a/Classes/Finishers/EmailFinisher.php b/Classes/Finishers/EmailFinisher.php index 5a6bccb..5f2436f 100644 --- a/Classes/Finishers/EmailFinisher.php +++ b/Classes/Finishers/EmailFinisher.php @@ -27,6 +27,10 @@ * * - templatePathAndFilename (mandatory if "templateSource" option is not set): Template path and filename for the mail body * - templateSource (mandatory if "templatePathAndFilename" option is not set): The raw Fluid template + * - htmlTemplatePathAndFilename (mandatory if "htmlTemplateSource" option is not set): Template path and filename for the html mail body + * - htmlTemplateSource (mandatory if "htmlTemplatePathAndFilename" option is not set): The raw Fluid template for html mail body + * - plaintextTemplatePathAndFilename (mandatory if "plaintextTemplateSource" option is not set): Template path and filename for the plaintext mail body + * - plaintextTemplateSource (mandatory if "plaintextTemplatePathAndFilename" option is not set): The raw Fluid template for plaintext mail body * - layoutRootPath: root path for the layouts * - partialRootPath: root path for the partials * - variables: associative array of variables which are available inside the Fluid template @@ -46,7 +50,7 @@ * - carbonCopyAddress: Email address of the copy recipient (use multiple addresses with an array) * - blindCarbonCopyAddress: Email address of the blind copy recipient (use multiple addresses with an array) * - format: format of the email (one of the FORMAT_* constants). By default mails are sent as HTML - * - attachAllPersistentResources: if TRUE all FormElements that are converted to a PersistendResource (e.g. the FileUpload element) are added to the mail as attachments + * - attachAllPersistentResources: if TRUE all FormElements that are converted to a PersistentResource (e.g. the FileUpload element) are added to the mail as attachments * - attachments: array of explicit files to be attached. Every item in the array has to be either "resource" being the path to a file, or "formElement" referring to the identifier of an Form Element that contains the PersistentResource to attach. This can be combined with the "attachAllPersistentResources" option * - testMode: if TRUE the email is not actually sent but outputted for debugging purposes. Defaults to FALSE */ @@ -54,6 +58,9 @@ class EmailFinisher extends AbstractFinisher { const FORMAT_PLAINTEXT = 'plaintext'; const FORMAT_HTML = 'html'; + const FORMAT_MULTIPART = 'multipart'; + const CONTENT_TYPE_PLAINTEXT = 'text/plain'; + const CONTENT_TYPE_HTML = 'text/html'; /** * @var Service @@ -61,6 +68,11 @@ class EmailFinisher extends AbstractFinisher */ protected $i18nService; + protected $formatContentTypes = [ + self::FORMAT_HTML => self::CONTENT_TYPE_HTML, + self::FORMAT_PLAINTEXT => self::CONTENT_TYPE_PLAINTEXT, + ]; + /** * @var array */ @@ -85,13 +97,6 @@ protected function executeInternal() if (!class_exists(SwiftMailerMessage::class)) { throw new FinisherException('The "neos/swiftmailer" doesn\'t seem to be installed, but is required for the EmailFinisher to work!', 1503392532); } - $formRuntime = $this->finisherContext->getFormRuntime(); - $standaloneView = $this->initializeStandaloneView(); - $standaloneView->assign('form', $formRuntime); - $referrer = $formRuntime->getRequest()->getHttpRequest()->getUri(); - $standaloneView->assign('referrer', $referrer); - $message = $standaloneView->render(); - $subject = $this->parseOption('subject'); $recipientAddress = $this->parseOption('recipientAddress'); $recipientName = $this->parseOption('recipientName'); @@ -102,6 +107,7 @@ protected function executeInternal() $blindCarbonCopyAddress = $this->parseOption('blindCarbonCopyAddress'); $format = $this->parseOption('format'); $testMode = $this->parseOption('testMode'); + $messages = $this->getMessages($format); if ($subject === null) { throw new FinisherException('The option "subject" must be set for the EmailFinisher.', 1327060320); @@ -140,11 +146,7 @@ protected function executeInternal() $mail->setBcc($blindCarbonCopyAddress); } - if ($format === self::FORMAT_PLAINTEXT) { - $mail->setBody($message, 'text/plain'); - } else { - $mail->setBody($message, 'text/html'); - } + $this->addMessages($mail, $messages); $this->addAttachments($mail); if ($testMode === true) { @@ -155,7 +157,7 @@ protected function executeInternal() 'replyToAddress' => $replyToAddress, 'carbonCopyAddress' => $carbonCopyAddress, 'blindCarbonCopyAddress' => $blindCarbonCopyAddress, - 'message' => $message, + 'message' => $messages, 'format' => $format, ), 'E-Mail "' . $subject . '"' @@ -165,20 +167,76 @@ protected function executeInternal() } } + protected function addMessages(SwiftMailerMessage $mail, array $messages): void + { + foreach ($messages as $messageFormat => $message) { + if (count($messages) === 1) { + $mail->setBody($message, $this->formatContentTypes[$messageFormat]); + } else { + $mail->addPart($message, $this->formatContentTypes[$messageFormat]); + } + } + } + + protected function getMessages(string $format): array + { + $messages = []; + if ($format === self::FORMAT_MULTIPART) { + $messages[self::FORMAT_HTML] = $this->createMessage(self::FORMAT_HTML); + $messages[self::FORMAT_PLAINTEXT] = $this->createMessage(self::FORMAT_PLAINTEXT); + } elseif ($format === self::FORMAT_PLAINTEXT) { + $messages[self::FORMAT_PLAINTEXT] = $this->createMessage(self::FORMAT_PLAINTEXT); + } else { + $messages[self::FORMAT_HTML] = $this->createMessage(self::FORMAT_HTML); + } + + return $messages; + } + + protected function createMessage(string $format): string + { + $formRuntime = $this->finisherContext->getFormRuntime(); + $standaloneView = $this->initializeStandaloneView($format); + $standaloneView->assign('form', $formRuntime); + $referrer = $formRuntime->getRequest()->getHttpRequest()->getUri(); + $standaloneView->assign('referrer', $referrer); + + return $standaloneView->render(); + } + /** + * @param string $format * @return StandaloneView * @throws FinisherException + * @throws \Neos\FluidAdaptor\Exception */ - protected function initializeStandaloneView() + protected function initializeStandaloneView(string $format = ''): StandaloneView { + $templatePathAndFilenameOption = 'templatePathAndFilename'; + $templateSourceOption = 'templateSource'; + $isSingleTemplate = isset($this->options[$templatePathAndFilenameOption]) || isset($this->options[$templateSourceOption]); + + if (!$isSingleTemplate && in_array($format, [self::FORMAT_PLAINTEXT, self::FORMAT_HTML])) { + $templatePathAndFilenameOption = $format . ucfirst($templatePathAndFilenameOption); + $templateSourceOption = $format . ucfirst($templateSourceOption); + } + $standaloneView = new StandaloneView(); - if (isset($this->options['templatePathAndFilename'])) { - $templatePathAndFilename = $this->i18nService->getLocalizedFilename($this->options['templatePathAndFilename']); + if (isset($this->options[$templatePathAndFilenameOption])) { + $templatePathAndFilename = $this->i18nService->getLocalizedFilename($this->options[$templatePathAndFilenameOption]); $standaloneView->setTemplatePathAndFilename($templatePathAndFilename[0]); - } elseif (isset($this->options['templateSource'])) { - $standaloneView->setTemplateSource($this->options['templateSource']); + } elseif (isset($this->options[$templateSourceOption])) { + $standaloneView->setTemplateSource($this->options[$templateSourceOption]); } else { - throw new FinisherException('The option "templatePathAndFilename" or "templateSource" must be set for the EmailFinisher.', 1327058829); + $options = [ + 'templatePathAndFilename', + 'templateSource', + self::FORMAT_PLAINTEXT . 'TemplatePathAndFilename', + self::FORMAT_PLAINTEXT . 'TemplateSource', + self::FORMAT_HTML . 'TemplatePathAndFilename', + self::FORMAT_HTML . 'TemplateSource' + ]; + throw new FinisherException(sprintf('One of the option "%s" must be set for the EmailFinisher.', implode('", "', $options)), 1551371435); } diff --git a/Classes/FormElements/FileUpload.php b/Classes/FormElements/FileUpload.php index 2fac7f1..1c36142 100644 --- a/Classes/FormElements/FileUpload.php +++ b/Classes/FormElements/FileUpload.php @@ -11,9 +11,13 @@ * source code. */ +use Neos\Flow\Property\PropertyMappingConfiguration; use Neos\Flow\ResourceManagement\PersistentResource; +use Neos\Flow\ResourceManagement\ResourceTypeConverter; +use Neos\Flow\Validation\Exception\InvalidValidationOptionsException; use Neos\Form\Core\Model\AbstractFormElement; use Neos\Form\Core\Runtime\FormRuntime; +use Neos\Form\Exception\FormDefinitionConsistencyException; use Neos\Form\Validation\FileTypeValidator; /** @@ -35,9 +39,15 @@ public function initializeFormElement() * @param FormRuntime $formRuntime * @param mixed $elementValue * @return void + * @throws InvalidValidationOptionsException | FormDefinitionConsistencyException */ public function onSubmit(FormRuntime $formRuntime, &$elementValue) { + if (isset($this->properties['resourceCollection'])) { + /** @var PropertyMappingConfiguration $propertyMappingConfiguration */ + $propertyMappingConfiguration = $this->getRootForm()->getProcessingRule($this->getIdentifier())->getPropertyMappingConfiguration(); + $propertyMappingConfiguration->setTypeConverterOption(ResourceTypeConverter::class, ResourceTypeConverter::CONFIGURATION_COLLECTION_NAME, $this->properties['resourceCollection']); + } $fileTypeValidator = new FileTypeValidator(array('allowedExtensions' => $this->properties['allowedExtensions'])); $this->addValidator($fileTypeValidator); } diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 1b9b582..f76073d 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -137,6 +137,10 @@ Neos: 'Neos.Form:FormElement': true implementationClassName: Neos\Form\FormElements\FileUpload properties: + # target collection of the uploaded PersistentResource + resourceCollection: 'persistent' + # set this to "false" if you don't want to create a link to the uploaded file (required for non-public resource collections) + createLinkToFilePreview: true allowedExtensions: - pdf - doc diff --git a/Resources/Private/Form/FileUpload.html b/Resources/Private/Form/FileUpload.html index a63e8c7..7d5652a 100644 --- a/Resources/Private/Form/FileUpload.html +++ b/Resources/Private/Form/FileUpload.html @@ -12,9 +12,11 @@ </div> <f:if condition="{resource}"> <div id="{element.uniqueIdentifier}-preview"> - <a href="{f:uri.resource(resource: resource)}"> - {resource.filename} - </a> + <f:if condition="{element.properties.createLinkToFilePreview}" else="{resource.filename}"> + <a href="{f:uri.resource(resource: resource)}"> + {resource.filename} + </a> + </f:if> <div class="clearfix"> <a class="btn small" href="#" onclick="return !enableUpload('{element.uniqueIdentifier}')"><f:translate id="forms.labels.replaceFile" package="{element.renderingOptions.translationPackage}">Replace File</f:translate></a> </div>