From d4d6b5be0c909346bcab15a8999a9454f833fcc4 Mon Sep 17 00:00:00 2001 From: Ralf Zimmermann Date: Sun, 6 Mar 2016 01:57:00 +0100 Subject: [PATCH] [FEATURE] EXT:form - Allow predefined forms This patchset enables the integration of predefined forms. An integrator can define forms - for example within the site package - using plugin.tx_form.predefinedForms. An editor can add a new mailform content element to a page and choose a form from the list of predefined elements. Example integration: plugin.tx_form.predefinedForms.someUniqueName = FORM plugin.tx_form.predefinedForms.someUniqueName { ... } Resolves: #72309 Releases: master Change-Id: I79def3cc00812bd5e5006b5226216064cc1b7ac7 Reviewed-on: https://review.typo3.org/45357 Reviewed-by: Benni Mack Tested-by: Benni Mack Reviewed-by: Oliver Hader Tested-by: Oliver Hader --- ...form-AllowIntegrationOfPredefinedForms.rst | 108 ++++++++++++++++++ .../form/Classes/Hooks/ContentObjectHook.php | 71 +++++++----- .../TCA/Overrides/tt_content.php | 33 ++++++ .../Resources/Private/Language/Database.xlf | 14 +++ typo3/sysext/form/ext_tables.sql | 6 + 5 files changed, 206 insertions(+), 26 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-72309-EXTform-AllowIntegrationOfPredefinedForms.rst create mode 100644 typo3/sysext/form/Resources/Private/Language/Database.xlf create mode 100644 typo3/sysext/form/ext_tables.sql diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-72309-EXTform-AllowIntegrationOfPredefinedForms.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-72309-EXTform-AllowIntegrationOfPredefinedForms.rst new file mode 100644 index 000000000000..b35b79546461 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-72309-EXTform-AllowIntegrationOfPredefinedForms.rst @@ -0,0 +1,108 @@ +============================================================ +Feature: #72309 - EXT:form - Integration of Predefined Forms +============================================================ + +Description +=========== + +The content element of EXT:form now allows the integration of predefined forms. An integrator can +define forms - for example within a site package - using ``plugin.tx_form.predefinedForms``. An +editor can add a new ``mailform`` content element to a page and choose a form from a list of +predefined elements. + +There are even more advantages: + +- Integrators can build there forms with TypoScript which offers much more possibilites than doing +it within the form wizard. Especially, the integrator is able to use stdWrap functionalities which +are not available when using the form wizard (for security reasons). +- There is no need anymore for editors to use the form wizard. They can choose the predefined forms +which are optimized layout-wise. +- Forms can be re-used throughout the whole installation. +- Forms can be stored outside the DB and versionized. + +In order to be able to select the pre-defined form in the backend, the form has to be registered +using PageTS. + +.. code-block:: typoscript + + TCEFORM.tt_content.tx_form_predefinedform.addItems.contactForm = LLL:EXT:my_theme/Resources/Private/Language/locallang.xlf:contactForm + +Example form: + +.. code-block:: typoscript + + plugin.tx_form.predefinedForms.contactForm = FORM + plugin.tx_form.predefinedForms.contactForm { + enctype = multipart/form-data + method = post + prefix = contact + confirmation = 1 + + postProcessor { + 1 = mail + 1 { + recipientEmail = test@mail.com + senderEmail = test@mail.com + subject { + value = Contact form + lang.de = Kontakt Formular + } + } + } + + 10 = TEXTLINE + 10 { + name = name + type = text + required = required + label { + value = Name + lang.de = Name + } + placeholder { + value = Enter your name + lang.de = Name eingeben + } + } + + 20 = TEXTLINE + 20 { + name = email + type = email + required = required + label { + value = Email + lang.de = E-Mail + } + placeholder { + value = Enter your email address + lang.de = E-Mail Adresse eingeben + } + } + + 30 = TEXTAREA + 30 { + name = message + cols = 40 + rows = 5 + required = required + label { + value = Message + lang.de = Nachricht + } + placeholder { + value = Enter your message + lang.de = Nachricht eingeben + } + } + + 40 = SUBMIT + 40 { + name = 5 + type = submit + value { + value = Send + lang.de = Senden + } + } + } \ No newline at end of file diff --git a/typo3/sysext/form/Classes/Hooks/ContentObjectHook.php b/typo3/sysext/form/Classes/Hooks/ContentObjectHook.php index 81dcd575b28a..734f32f5d71d 100644 --- a/typo3/sysext/form/Classes/Hooks/ContentObjectHook.php +++ b/typo3/sysext/form/Classes/Hooks/ContentObjectHook.php @@ -18,6 +18,7 @@ use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Core\Bootstrap; use TYPO3\CMS\Form\Domain\Model\Configuration; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; @@ -30,10 +31,9 @@ class ContentObjectHook * Renders the application defined cObject FORM * which overrides the TYPO3 default cObject FORM * - * Convert FORM to COA_INT - COA_INT.10 = FORM_INT - * If FORM_INT is also dedected by the ContentObjectRenderer, and now - * the Extbaseplugin "Form" is initalized. At this time the - * controller "Frontend" action "execute" do the rest. + * If FORM is dedected by the ContentObjectRenderer, + * the Extbase plugin "Form" is initialized. At this time, the + * controller "Frontend" action "execute" does the rest. * * @param string $typoScriptObjectName Name of the object * @param array $typoScript TS configuration for this cObject @@ -44,45 +44,64 @@ class ContentObjectHook public function cObjGetSingleExt($typoScriptObjectName, array $typoScript, $typoScriptKey, ContentObjectRenderer $contentObject) { $content = ''; - if ( - $typoScriptObjectName === 'FORM' + // render the FORM CE from TYPO3 < 4.6 + if ($typoScriptObjectName === 'FORM' && !empty($typoScript['useDefaultContentObject']) && ExtensionManagementUtility::isLoaded('compatibility6') ) { $content = $contentObject->getContentObject($typoScriptObjectName)->render($typoScript); } elseif ($typoScriptObjectName === 'FORM') { $mergedTypoScript = null; + // If the FORM configuration comes from the database + // all TypoScript interpretation will be disabled for security. if ($contentObject->data['CType'] === 'mailform') { - $bodytext = $contentObject->data['bodytext']; - /** @var $typoScriptParser TypoScriptParser */ - $typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class); - $typoScriptParser->parse($bodytext); - $mergedTypoScript = (array)$typoScriptParser->setup; - ArrayUtility::mergeRecursiveWithOverrule($mergedTypoScript, $typoScript); - // Disables content elements since TypoScript is handled that could contain insecure settings: - $mergedTypoScript[Configuration::DISABLE_CONTENT_ELEMENT_RENDERING] = true; - } - $newTypoScript = array( - '10' => 'FORM_INT', - '10.' => (is_array($mergedTypoScript) ? $mergedTypoScript : $typoScript), - ); - $content = $contentObject->cObjGetSingle('COA_INT', $newTypoScript); - // Only apply stdWrap to TypoScript that was NOT created by the wizard: - if (isset($typoScript['stdWrap.'])) { - $content = $contentObject->stdWrap($content, $typoScript['stdWrap.']); + // If the FORM configuration comes from the database + // and a predefined form is selected than the TypoScript + // interpretation is allowed. + $renderPredefinedForm = false; + if (isset($contentObject->data['tx_form_predefinedform']) + && !empty($contentObject->data['tx_form_predefinedform']) + ) { + $predefinedFormIdentifier = $contentObject->data['tx_form_predefinedform']; + if (isset($GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_form.']['predefinedForms.'][$predefinedFormIdentifier . '.'])) { + $renderPredefinedForm = true; + } else { + throw new \InvalidArgumentException('No FORM configuration for identifier "' . $predefinedFormIdentifier . '" available.', 1457097250); + } + } + + if ($renderPredefinedForm) { + $mergedTypoScript = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_form.']['predefinedForms.'][$predefinedFormIdentifier . '.']; + ArrayUtility::mergeRecursiveWithOverrule($mergedTypoScript, $typoScript); + } else { + $bodytext = $contentObject->data['bodytext']; + /** @var $typoScriptParser TypoScriptParser */ + $typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class); + $typoScriptParser->parse($bodytext); + $mergedTypoScript = (array)$typoScriptParser->setup; + ArrayUtility::mergeRecursiveWithOverrule($mergedTypoScript, $typoScript); + // Disables TypoScript interpretation since TypoScript is handled that could contain insecure settings: + $mergedTypoScript[Configuration::DISABLE_CONTENT_ELEMENT_RENDERING] = true; + } } - } elseif ($typoScriptObjectName === 'FORM_INT') { - $extbase = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Core\Bootstrap::class); + $newTypoScript = (is_array($mergedTypoScript) ? $mergedTypoScript : $typoScript); + + $extbase = GeneralUtility::makeInstance(Bootstrap::class); $content = $extbase->run('', array( 'pluginName' => 'Form', 'extensionName' => 'Form', 'vendorName' => 'TYPO3\\CMS', 'controller' => 'Frontend', 'action' => 'show', - 'settings' => array('typoscript' => $typoScript), + 'settings' => array('typoscript' => $newTypoScript), 'persistence' => array(), 'view' => array(), )); + + // Only apply stdWrap to TypoScript that was NOT created by the wizard: + if (isset($typoScript['stdWrap.'])) { + $content = $contentObject->stdWrap($content, $typoScript['stdWrap.']); + } } return $content; } diff --git a/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php b/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php index 0f597333ad78..e0c0a34be174 100644 --- a/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php +++ b/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php @@ -34,6 +34,38 @@ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem('tt_content', 'CType', $additionalCTypeItem); } +// predefined forms +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns( + 'tt_content', + array( + 'tx_form_predefinedform' => array( + 'label' => 'LLL:EXT:form/Resources/Private/Language/Database.xlf:tx_form_predefinedform', + 'exclude' => 1, + 'config' => array( + 'type' => 'select', + 'items' => array( + array( + 'LLL:EXT:form/Resources/Private/Language/Database.xlf:tx_form_predefinedform.selectPredefinedForm', + '' + ), + ), + ), + ), + ) +); +$GLOBALS['TCA']['tt_content']['ctrl']['requestUpdate'] .= ',tx_form_predefinedform'; + +// Hide bodytext if a predefined form is selected +$GLOBALS['TCA']['tt_content']['columns']['bodytext']['displayCond']['AND'] = array( + 'OR' => array( + 'FIELD:CType:!=:mailform', + 'AND' => array( + 'FIELD:CType:=:mailform', + 'FIELD:tx_form_predefinedform:REQ:false', + ), + ), +); + $GLOBALS['TCA']['tt_content']['columns']['bodytext']['config']['wizards']['forms'] = array( 'notNewRecords' => 1, 'enableByTypeConfig' => 1, @@ -72,6 +104,7 @@ --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header,rowDescription, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType.I.8, bodytext;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext.ALT.mailform, + tx_form_predefinedform;LLL:EXT:form/Resources/Private/Language/Database.xlf:tx_form_predefinedform, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance, --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, diff --git a/typo3/sysext/form/Resources/Private/Language/Database.xlf b/typo3/sysext/form/Resources/Private/Language/Database.xlf new file mode 100644 index 000000000000..069dedb78431 --- /dev/null +++ b/typo3/sysext/form/Resources/Private/Language/Database.xlf @@ -0,0 +1,14 @@ + + + +
+ + + Predefined form + + + Choose a predefined form + + + + diff --git a/typo3/sysext/form/ext_tables.sql b/typo3/sysext/form/ext_tables.sql new file mode 100644 index 000000000000..21ac6fbd3528 --- /dev/null +++ b/typo3/sysext/form/ext_tables.sql @@ -0,0 +1,6 @@ +# +# Table structure for table 'tt_content' +# +CREATE TABLE tt_content ( + tx_form_predefinedform varchar(255) DEFAULT '' NOT NULL, +);