Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple file upload fix #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions Classes/Xclass/EmailFinisherXclass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
<?php

namespace StudioMitte\FormMultipleUploads\Xclass;

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;
use TYPO3\CMS\Form\Domain\Finishers\EmailFinisher;


class EmailFinisherXclass extends EmailFinisher
{

/**
* @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;
}
$files = $formRuntime[$element->getIdentifier()];
foreach ($files as $file) {
if ($file) {
if ($file instanceof FileReference) {

$file = $file->getOriginalResource();
}
$mail->attach($file->getContents(), $file->getOriginalFile()->getName(),$file->getOriginalFile()->getProperties()['mime_type']);
}
}
}
}

// 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;
}
}
12 changes: 9 additions & 3 deletions Classes/Xclass/UploadedFileReferenceConverterXclass.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace StudioMitte\FormMultipleUploads\Xclass;

use TYPO3\CMS\Core\Http\UploadedFile;
use TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Domain\Model\FileReference as ExtbaseFileReference;
Expand All @@ -26,9 +27,15 @@ class UploadedFileReferenceConverterXclass extends UploadedFileReferenceConverte
*/
public function convertFrom($source, $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null)
{
if ($source instanceof UploadedFile) {
$source = $this->convertUploadedFileToUploadInfoArray($source);
}
if (isset($source[0])) {
$result = [];
foreach ($source as $singleSource) {
if ($singleSource instanceof UploadedFile) {
$singleSource = $this->convertUploadedFileToUploadInfoArray($singleSource);
}
$converted = $this->convertSingleFile($singleSource, $configuration);
$result[] = $converted;
}
Expand All @@ -49,9 +56,8 @@ public function convertFrom($source, $targetType, array $convertedChildPropertie
*/
protected function convertSingleFile($source, ?PropertyMappingConfigurationInterface $configuration)
{
if ($source instanceof FileReference) {
return $source;
}


if (!isset($source['error']) || $source['error'] === \UPLOAD_ERR_NO_FILE) {
if (isset($source['submittedFile']['resourcePointer'])) {
try {
Expand Down
4 changes: 2 additions & 2 deletions ext_emconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
'category' => 'fe',
'author' => 'Georg Ringer',
'author_email' => '[email protected]',
'state' => 'alpha',
'state' => 'stable',
'createDirs' => '',
'clearCacheOnLoad' => 0,
'version' => '1.0.0',
'constraints' => [
'depends' => [
'typo3' => '10.4.0-10.4.99',
'typo3' => '10.4.0-12.4.7',
'form' => '',
],
'conflicts' => [],
Expand Down
4 changes: 4 additions & 0 deletions ext_localconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Form\Domain\Finishers\SaveToDatabaseFinisher::class] = [
'className' => \StudioMitte\FormMultipleUploads\Xclass\SaveToDabaseFinisherXclass::class
];

$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Form\Domain\Finishers\EmailFinisher::class] = [
'className' => \StudioMitte\FormMultipleUploads\Xclass\EmailFinisherXclass::class
];