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
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
Multiple file upload fix
  • Loading branch information
pitssavinmb committed Jan 2, 2024
commit a1e4ac18ff611d19bf4bee78f61c7556b8bf5179
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
@@ -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;
@@ -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;
}
@@ -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 {
4 changes: 2 additions & 2 deletions ext_emconf.php
Original file line number Diff line number Diff line change
@@ -6,13 +6,13 @@
'category' => 'fe',
'author' => 'Georg Ringer',
'author_email' => 'gr@studiomitte.com',
'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' => [],
4 changes: 4 additions & 0 deletions ext_localconf.php
Original file line number Diff line number Diff line change
@@ -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
];