Skip to content

Commit

Permalink
[FEATURE] EXT:form - Allow predefined forms
Browse files Browse the repository at this point in the history
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 <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
  • Loading branch information
waldhacker1 authored and ohader committed Mar 6, 2016
1 parent 72d6c6e commit d4d6b5b
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 26 deletions.
@@ -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
}
}
}
71 changes: 45 additions & 26 deletions typo3/sysext/form/Classes/Hooks/ContentObjectHook.php
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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;
}
Expand Down
33 changes: 33 additions & 0 deletions typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 14 additions & 0 deletions typo3/sysext/form/Resources/Private/Language/Database.xlf
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
<file t3:id="1450450398" source-language="en" datatype="plaintext" original="messages" date="2015-12-18T15:53:55Z" product-name="form">
<header/>
<body>
<trans-unit id="tx_form_predefinedform">
<source>Predefined form</source>
</trans-unit>
<trans-unit id="tx_form_predefinedform.selectPredefinedForm">
<source>Choose a predefined form</source>
</trans-unit>
</body>
</file>
</xliff>
6 changes: 6 additions & 0 deletions 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,
);

0 comments on commit d4d6b5b

Please sign in to comment.