Skip to content
Snippets Groups Projects
Commit 5333ed7b authored by Torsten Oppermann's avatar Torsten Oppermann
Browse files

Merge branch 'master' of gitlab.sgalinski.de:typo3/sg_mail

parents 26dba361 39070ace
No related branches found
No related tags found
No related merge requests found
......@@ -33,12 +33,14 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher;
/**
* This finisher sends an email to one recipient
* This finisher sends an email via sg_mail after form submission and enables customization of mail markers
*/
class FormsFinisher extends AbstractFinisher {
/**
* Executes this finisher
*
* Send email with the sgmail api to one or more recipients
* overwrites the mail markers with custom identifiers if provided
*
* @see AbstractFinisher::execute()
*
......@@ -49,15 +51,49 @@ class FormsFinisher extends AbstractFinisher {
*/
protected function executeInternal() {
$formValues = $this->finisherContext->getFormValues();
$formRuntime = $this->finisherContext->getFormRuntime();
// check if all the necessary objects exist
if ($formRuntime !== NULL) {
$formDefinition = $formRuntime->getFormDefinition();
} else {
return;
}
if ($formRuntime === NULL) {
return;
}
$markers = [];
foreach ($formValues as $identifier => $value) {
$formElement = $formDefinition->getElementByIdentifier($identifier);
if (!$formElement) {
$markers[$identifier] = $value;
continue;
}
$formElemenProperties = $formElement->getProperties();
if (isset($formElemenProperties['markerName']) && \trim($formElemenProperties['markerName']) !== '') {
$markers[\trim($formElemenProperties['markerName'])] = $value;
} else {
$markers[$identifier] = $value;
}
}
$templateName = $this->parseOption('template');
if ($this->parseOption('template') === '') {
$templateName = $formDefinition->getIdentifier();
}
$ignoreMailQueue = (boolean) $this->parseOption('ignoreMailQueue');
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
/** @var \SGalinski\SgMail\Service\MailTemplateService $mailTemplateService */
$mailTemplateService = $objectManager->get(
MailTemplateService::class, $this->parseOption('template'), $this->parseOption('extension'), $formValues
MailTemplateService::class, $templateName, $this->parseOption('extension'), $markers
);
$mailTemplateService->setIgnoreMailQueue(FALSE);
$mailTemplateService->setIgnoreMailQueue($ignoreMailQueue);
$mailTemplateService->setLanguage($GLOBALS['TSFE']->config['config']['language']);
$mailTemplateService->setSubject($this->parseOption('subject'));
$mailTemplateService->setToAddresses($this->parseOption('mailTo'));
$mailTemplateService->setFromAddress($this->parseOption('mailFrom'));
$mailTemplateService->setFromName($this->parseOption('userName'));
......
......@@ -46,6 +46,7 @@ use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Page\PageRepository;
/**
* MailTemplateService
......@@ -59,6 +60,8 @@ class MailTemplateService {
const DEFAULT_TEMPLATE_PATH = 'Resources/Private/Templates/SgMail/';
const CACHE_NAME = 'sg_mail_registerArrayCache';
const CACHE_LIFETIME_IN_SECONDS = 86400;
const REGISTER_FILE = 'Register.php';
const CONFIG_PATH = 'Configuration/MailTemplates';
/**
* @var array $toAddresses
......@@ -258,13 +261,22 @@ class MailTemplateService {
if (TYPO3_MODE === 'FE') {
/** @var TypoScriptFrontendController $tsfe */
$tsfe = $GLOBALS['TSFE'];
$pageUid = $tsfe->id;
$pageUid = (int) $tsfe->id;
} else {
$pageUid = (int) GeneralUtility::_GP('id');
}
if ($this->pid) {
$pageUid = $this->pid;
$pageUid = (int) $this->pid;
}
if ($pageUid === 0) {
$pageRepository = $this->objectManager->get(PageRepository::class);
$rootPageRows = $pageRepository->getRecordsByField(
'pages', 'is_siteroot', 1, 'hidden = 0', '', 'sorting', 1
);
if ($rootPageRows && \count($rootPageRows)) {
$pageUid = (int) $rootPageRows[0]['uid'];
}
}
$siteRootId = BackendService::getSiteRoot($pageUid);
......@@ -295,7 +307,13 @@ class MailTemplateService {
if (file_exists($defaultTemplateFile)) {
$defaultTemplateContent = file_get_contents($defaultTemplateFile);
} else {
return FALSE;
// use configured default html template
$defaultTemplateFile = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultHtmlTemplate'];
if (file_exists($defaultTemplateFile)) {
$defaultTemplateContent = file_get_contents($defaultTemplateFile);
} else {
return FALSE;
}
}
} elseif (filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) {
$this->setToAddresses(trim($template->getToAddress()));
......@@ -330,6 +348,8 @@ class MailTemplateService {
/** @var StandaloneView $emailView */
$emailView = $this->objectManager->get(StandaloneView::class);
$emailView->assignMultiple($this->markers);
$emailView->assign('all_fields', $this->getAllMarker($this->markers));
if (NULL === $defaultTemplateContent) {
$emailView->setTemplateSource(\trim($template->getSubject()));
$subject = $emailView->render();
......@@ -788,7 +808,7 @@ class MailTemplateService {
foreach ($extensionList as $extensionName) {
$extensionConfigDirectory = ExtensionManagementUtility::extPath($extensionName);
$extensionConfigDirectory .= '/Configuration/MailTemplates';
$extensionConfigDirectory .= self::CONFIG_PATH;
$configFiles = GeneralUtility::getFilesInDir($extensionConfigDirectory);
foreach ($configFiles as $configFile) {
......@@ -796,36 +816,73 @@ class MailTemplateService {
$extensionKey = $configArray['extension_key'];
$templateKey = $configArray['template_key'];
// transform template directory name: your_templates => YourTemplates/
$templateDirectoryParts = GeneralUtility::trimExplode('_', $configArray['template_key']);
$templateDirectory = '';
foreach ($templateDirectoryParts as $part) {
$templateDirectory .= ucfirst($part);
if ($extensionKey === NULL || $templateKey === NULL) {
continue;
}
$templateDirectory .= '/';
$templatePath = ExtensionManagementUtility::extPath(
$extensionName
) . self::DEFAULT_TEMPLATE_PATH . $templateDirectory;
if ($configArray['template_path']) {
$templatePath = $configArray['template_key'];
}
$registerArray = self::writeRegisterArrayEntry(
$registerArray, $extensionKey, $templateKey, $configArray
);
}
}
return $registerArray;
}
/**
* writes a single entry into the register array
*
* @param array $registerArray
* @param string $extensionKey
* @param string $templateKey
* @param array $configArray
* @param bool $transformTemplateFolder
* @param string $storeTemplateExtension
* @return array
*/
private static function writeRegisterArrayEntry(
array $registerArray, $extensionKey, $templateKey, array $configArray,
$transformTemplateFolder = TRUE, $storeTemplateExtension = ''
) {
// If it is not explicitly set in which extension the html should be located, use the extension set in the template settings
if ($storeTemplateExtension === '') {
$storeTemplateExtension = $extensionKey;
}
$description = $configArray['description'];
$subject = $configArray['subject'];
$marker = $configArray['markers'];
$registerArray[$extensionKey][$templateKey] = [
'templatePath' => $templatePath,
'description' => $description,
'marker' => $marker,
'extension' => $extensionKey,
'templateName' => $templateKey,
'subject' => $subject
];
// give the option to use the template key as folder name. this is used mainly with auto registering
$templateDirectory = $templateKey;
// by default folders with underscore will be transformed to upper camelcase
if ($transformTemplateFolder) {
// transform template directory name: your_templates => YourTemplates/
$templateDirectoryParts = GeneralUtility::trimExplode('_', $templateKey);
$templateDirectory = '';
foreach ($templateDirectoryParts as $part) {
$templateDirectory .= ucfirst($part);
}
}
$templateDirectory .= '/';
$templatePath = ExtensionManagementUtility::extPath($storeTemplateExtension) . self::DEFAULT_TEMPLATE_PATH
. $templateDirectory;
if ($configArray['template_path']) {
$templatePath = $configArray[$templateKey];
}
$description = $configArray['description'];
$subject = $configArray['subject'];
$marker = $configArray['markers'];
$registerArray[$extensionKey][$templateKey] = [
'templatePath' => $templatePath,
'description' => $description,
'marker' => $marker,
'extension' => $extensionKey,
'templateName' => $templateKey,
'subject' => $subject
];
return $registerArray;
}
......@@ -863,4 +920,33 @@ class MailTemplateService {
public function setSubject(string $subject) {
$this->subject = $subject;
}
/**
* Get a single variable containing a list of all markers
*
* @param array $markers
* @return string
*/
private function getAllMarker(array $markers): string {
$allMarker = '';
foreach ($markers as $key => $value) {
if (\is_string($value)) {
$allMarker .= $key . ': ' . $value . PHP_EOL;
} elseif (\is_array($value)) {
foreach ($value as $innerKey => $innerValue) {
$allMarker .= $key . '.' . $innerKey . ': ' . $innerValue . PHP_EOL;
}
} elseif (\is_bool($value)) {
$valueAsString = $value ? 'true' : 'false';
$allMarker .= $key . ': ' . $valueAsString . PHP_EOL;
} elseif (\is_object($value)) {
if (method_exists($value, '__toString')) {
$allMarker .= $key . ': ' . $value->__toString() . PHP_EOL;
}
}
}
return $allMarker;
}
}
<?php
namespace SGalinski\SgMail\XClass\Form;
/***************************************************************
* Copyright notice
*
* (c) sgalinski Internet Services (https://www.sgalinski.de)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use SGalinski\SgMail\Service\MailTemplateService;
use SGalinski\SgMail\Service\TypoScriptSettingsService;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Form\Type\FormDefinitionArray;
/** @noinspection LongInheritanceChainInspection */
/**
* Displays the form editor. Enables hooking into the save process of the form to handle automatic sg mail registration
*/
class FormEditorController extends \TYPO3\CMS\Form\Controller\FormEditorController {
/**
* This contains type names of fields we dont care about in sgmail
*
* @var array
*/
const IGNORE_FIELDS = [
'StaticText', 'Hidden', 'GridRow'
];
/**
* This contains the names of sgmail finishers, so we can identify if we need to generate a template registration
*
* @var array
*/
const MAIL_FINISHER = [
'MailToSenderFinisher', 'MailToReceiverFinisher'
];
/**
* Add automatic SgMail Configuration
*
* @param string $formPersistenceIdentifier
* @param FormDefinitionArray $formDefinition
* @internal
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
public function saveFormAction(string $formPersistenceIdentifier, FormDefinitionArray $formDefinition) {
/** @noinspection PhpInternalEntityUsedInspection */
parent::saveFormAction($formPersistenceIdentifier, $formDefinition);
// immediately exit when no finisher is defined (that means no sgmail integration anyway)
if (!$formDefinition['finishers']) {
return;
}
/** @var array $finishers */
$finishers = $formDefinition['finishers'];
$extensionKey = '';
$templateKey = '';
foreach ($finishers as $finisher) {
// if one finisher prevents automatic registration, exit this function
if (!$finisher['options']['automaticRegistration']) {
return;
}
if (!\in_array($finisher['identifier'], self::MAIL_FINISHER, TRUE)) {
continue;
}
// retrieve the extension and template key and jump out of loop
$extensionKey = $finisher['options']['extension'];
$templateKey = $finisher['options']['template'];
break;
}
// if no template key was explicitly set, use the form identifier as template key
if ($templateKey === '') {
$templateKey = $formDefinition['identifier'];
}
// if there was no sg mail finisher or an missing key then simply exit the function
if ($extensionKey === '' || $templateKey === '') {
return;
}
// parse yaml for form fields
$absoluteFilePath = GeneralUtility::getFileAbsFileName($formPersistenceIdentifier);
$parsedYaml = \yaml_parse_file($absoluteFilePath);
$renderables = [];
foreach ($parsedYaml['renderables'] as $formPage) {
if (\is_array($formPage['renderables'])) {
foreach ($formPage['renderables'] as $row) {
if (!\is_array($row) || !$row['type']) {
continue;
}
if ($row['type'] === 'GridRow') {
foreach ($row['renderables'] as $renderableInsideGridrow) {
$renderables[] = $renderableInsideGridrow;
}
} elseif (!\in_array($row['type'], self::IGNORE_FIELDS, TRUE)) {
$renderables[] = $row;
}
}
} else {
return;
}
}
// write the new Register.php file
$this->writeRegisterFile($renderables, $extensionKey, $templateKey);
// call register function in mail template service class
MailTemplateService::registerExtensions();
// clear caches
$this->clearCaches();
}
/**
* Builds the register array and saves it to the configured location
*
* @param array $renderables
* @param string $extensionKey
* @param string $templateKey
*/
private function writeRegisterFile(array $renderables, $extensionKey, $templateKey) {
// get the location where automatic registrations should be stored
$configurationLocation = $this->getRegistrationPath();
$registerFolder = GeneralUtility::getFileAbsFileName(
$configurationLocation
);
// create folder
GeneralUtility::mkdir($registerFolder);
$registerFile = GeneralUtility::getFileAbsFileName(
$registerFolder . '/' . $templateKey . '.php'
);
// build the register array
$newRegisterArray = [
'extension_key' => $extensionKey,
'template_key' => $templateKey,
'description' => $templateKey,
'subject' => $templateKey,
'markers' => []
];
// add the markers for this template
foreach ($renderables as $element) {
$markerName = $element['identifier'];
// if markerName is explicitly set, override the registered identifier
if (isset($element['properties']['markerName']) && $element['properties']['markerName'] !== '') {
$markerName = $element['properties']['markerName'];
}
$newRegisterArray['markers'][] = [
'marker' => $markerName,
'type' => MailTemplateService::MARKER_TYPE_STRING,
'value' => $element['label'],
'description' => $element['label']
];
}
file_put_contents($registerFile, '<?php return ' . var_export($newRegisterArray, TRUE) . ';');
}
/**
* Clear the sgmail register cache
*
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
private function clearCaches() {
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$cacheManager = $objectManager->get(CacheManager::class);
/** @var FrontendInterface $cache */
$cache = $cacheManager->getCache(MailTemplateService::CACHE_NAME);
/** @var FrontendInterface $cache */
$cache->flush();
}
/**
* Returns the path to the configured location where automatic mail template registrations should be
*
* @return string
*/
private function getRegistrationPath(): string {
// get typoscript settings from sg mail
/** @var TypoScriptSettingsService $typoScriptSettingsService */
$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
// get the location where automatic registrations should be stored
return 'EXT:' . $tsSettings['mail']['configurationLocation'] . '/' . MailTemplateService::CONFIG_PATH;
}
}
{all_fields}
......@@ -15,6 +15,12 @@ module.tx_sgmail {
# comma-separated list of additional cc addresses
default.cc =
# extension where automatic generated registrations are put. Will be appended with /Configuration/MailTemplates/. Make sure these folders exist!
configurationLocation = project_theme
# default html template file, which serves as a fallback for all mail templates
defaultHtmlTemplate = EXT:sg_mail/Configuration/MailTemplates/Default.html
}
# default template language
......
......@@ -12,9 +12,10 @@ TYPO3:
predefinedDefaults:
options:
extension: 'sg_mail'
template: 'contact_user'
template: ''
automaticRegistration: ''
ignoreMailQueue: true
mailTo: ''
subject: ''
userName: ''
replyTo: ''
cc: ''
......@@ -27,10 +28,11 @@ TYPO3:
predefinedDefaults:
options:
extension: 'sg_mail'
template: 'contact_admin'
template: ''
automaticRegistration: ''
ignoreMailQueue: true
mailTo: ''
mailFrom: ''
subject: ''
userName: ''
replyTo: ''
cc: ''
......@@ -68,7 +70,16 @@ TYPO3:
templateName: 'Inspector-TextEditor'
label: 'Unique Template name'
propertyPath: 'options.template'
enableFormelementSelectionButton: true
125:
identifier: 'automaticRegistration'
templateName: 'Inspector-CheckboxEditor'
label: 'Automatic Registration (If selected, you can find your template in the "Mail Template" module after saving. Look for the extension and template key in the dropdown in the upper left corner of the template editor.'
propertyPath: 'options.automaticRegistration'
127:
identifier: 'ignoreMailQueue'
templateName: 'Inspector-CheckboxEditor'
label: 'If selected, the mails are send immediately, otherwise the mails are added to the Mail Queue. See the Readme of the sg_mail extension for more Information.'
propertyPath: 'options.ignoreMailQueue'
130:
identifier: 'mailTo'
templateName: 'Inspector-TextEditor'
......@@ -83,17 +94,11 @@ TYPO3:
templateName: 'Inspector-TextEditor'
label: 'The email address of the website'
propertyPath: 'options.mailFrom'
150:
identifier: 'subject'
templateName: 'Inspector-TextEditor'
label: 'The subject of the E-Mail'
propertyPath: 'options.subject'
160:
identifier: 'userName'
templateName: 'Inspector-TextEditor'
label: 'The name of the website user'
propertyPath: 'options.userName'
enableFormelementSelectionButton: true
propertyValidators:
10: 'NotEmpty'
20: 'FormElementIdentifierWithinCurlyBracesInclusive'
......@@ -129,7 +134,16 @@ TYPO3:
templateName: 'Inspector-TextEditor'
label: 'Template key'
propertyPath: 'options.template'
enableFormelementSelectionButton: true
125:
identifier: 'automaticRegistration'
templateName: 'Inspector-CheckboxEditor'
label: 'Automatic Registration (If selected, you can find your template in the "Mail Template" module after saving. Look for the extension and template key in the dropdown in the upper left corner of the template editor.'
propertyPath: 'options.automaticRegistration'
127:
identifier: 'ignoreMailQueue'
templateName: 'Inspector-CheckboxEditor'
label: 'If selected, the mails are send immediately, otherwise the mails are added to the Mail Queue. See the Readme of the sg_mail extension for more Information.'
propertyPath: 'options.ignoreMailQueue'
130:
identifier: 'mailTo'
templateName: 'Inspector-TextEditor'
......@@ -140,11 +154,6 @@ TYPO3:
templateName: 'Inspector-TextEditor'
label: 'The email address of the website'
propertyPath: 'options.mailFrom'
150:
identifier: 'subject'
templateName: 'Inspector-TextEditor'
label: 'The subject of the E-Mail'
propertyPath: 'options.subject'
160:
identifier: 'replyTo'
templateName: 'Inspector-TextEditor'
......@@ -163,4 +172,4 @@ TYPO3:
renderingOptions:
translation:
translationFile:
90: 'EXT:project_theme/Resources/Private/Language/forms.xlf'
\ No newline at end of file
90: 'EXT:project_theme/Resources/Private/Language/forms.xlf'
......@@ -15,7 +15,7 @@ TYPO3 version: >7.6
This extension provides an email templating service and mail queue functionality for all your TYPO3 extensions.
It also supports Templates in various languages, which can be managed in the backend.
Additionally sg_mail provides a finisher class for the [Formhandler](https://typo3.org/extensions/repository/view/formhandler) extension, making it possible to manage its templates in the backend.
Additionally sg_mail comes with multiple features that help to integrate with [ext:form](https://docs.typo3.org/typo3cms/extensions/form/).
sg_mail ist multi-site and multi-language ready.
......@@ -297,10 +297,31 @@ You can also tell the **MailTemplateService** to not ignore this mail when addin
---
#### FormhandlerFinisherService
### Ext:form Integration
#### Template marker
This extension provides you the possibility to customize the identifier of the form input fields. These identifiers are used in the mail templates as marker names.
To change a fields identifier, select it in the form editor and enter your desired identifier in the field labeled "Email template marker name". After saving the form, the change identifier name will be overwritten.
#### New mail finisher
sg_mail comes with two new finisher for your forms with the following settings regarding sg_mail integration:
- **Template key**: If this field is empty, the form identifier will be used instead
- **Automatic Registration**: A sg_mail registration will automatically be created. See the **Automatic Registration** section for more information
- **Ignore Mail Queue**: Mails will get send immediately and not added to the mail queue
#### Automatic Registration
If you select to automatically register your forms with sg_mail, the default html template for the emails will be used.
You can customize the TypoScript settings in the **setup.ts** in order to have control over automatically generated registration files:
# extension where automatic generated registrations are put. Will be appended with /Configuration/MailTemplates/. Make sure these folders exist!
configurationLocation = your_extension_key
# default html template file, which serves as a fallback for all mail templates
defaultHtmlTemplate = EXT:project_theme/Configuration/MailTemplates/Default.html
This class is an implementation of the **Typoheads\Formhandler\Finisher\AbstractFinisher** Class
that is used by the extension [formhandler extension](https://typo3.org/extensions/repository/view/formhandler).
---
......
......@@ -47,6 +47,11 @@ if (TYPO3_MODE === 'BE') {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScriptSetup(file_get_contents($tsPath . 'setup.ts'));
}
// register xclasses
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Form\Controller\FormEditorController::class] = [
'className' => \SGalinski\SgMail\XClass\Form\FormEditorController::class,
];
// Cache registration
$cacheName = \SGalinski\SgMail\Service\MailTemplateService::CACHE_NAME;
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheName])) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment