Commit 0ee65b8f authored by Christian Kuhn's avatar Christian Kuhn Committed by Anja Leichsenring
Browse files

[!!!][FEATURE] FormEngine: The extendables

For details, see the ReST files with examples for new API
and TCA changes.

* Split TCA config "type" to "type" and "renderType":
  TCA config "type" is a technical debt since it both defines the
  database storage as well as the widget that is used to render
  a certain field in FormEngine. While "type" is kept, the
  render widget is now extracted to a "renderType".

* t3editor uses this "renderType" now. type=text with
  renderType=t3editor will call the new T3editorElement provided
  by ext:t3editor, and falls back to TextElement if t3editor is
  not loaded.

* t3editor is now enabled for "setup" and "constants" of
  sys_template records if opening the whole record.

* t3editor now works when configured in a flex form.

* Introduce an API in FormEngine NodeFactory to register new
  renderType, used by t3editor.

* Introduce a resolver API in FormEngine NodeFactory to change
  the class that renders a widget or container.

* Split TextElement into TextElement that only renders a textarea
  and RichTextElement provided by ext:rtehtmlarea that renders RTE.
  ext:rtehtmlarea uses the new resolver API to route rendering to
  its own class in case RTE is enabled and configured for a field.

* In TCA section "types" a new array "columnsOverrides" is
  introduced that allows overwriting some column configurations
  of fields. Currently, this works for some View/FormEngine related
  settings like renderType and defaultExtras.

* TCA Migration is introduced to dynamically rewrite TCA before
  it is put into cache.

* TCA migration is called a second time in ext:compatibility6 in
  case TCA is still registered via ext_tables.php. This has performance
  penalty since it is done on every frontend and backend call.

* TCA migration is also called dynamically for flex form definitions.

* TCA migration moves configured t3editor wizards to type=text with
  renderType=t3editor.

* TCA migration removes the 5th parameter "style pointer" from
  types showitem

* TCA migration moves the 4th showitem parameter "extra configuration"
  to "defaultExtras" of "columnsOverrides" of given TCA type.

Change-Id: Ia2c2bc16463a01021c7a6be765b4efa872a130fd
Resolves: #67229
Releases: master
Reviewed-on: http://review.typo3.org/39662


Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: default avatarFrank Nägler <typo3@naegler.net>
Tested-by: default avatarFrank Nägler <typo3@naegler.net>
Reviewed-by: Markus Klein's avatarMarkus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein's avatarMarkus Klein <markus.klein@typo3.org>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
parent 7231ac0f
......@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Utility;
use TYPO3\CMS\Core\Category\CategoryRegistry;
use TYPO3\CMS\Core\Package\PackageManager;
use TYPO3\CMS\Core\Migrations\TcaMigration;
/**
* Extension Management functions
......@@ -302,7 +303,7 @@ class ExtensionManagementUtility {
$paletteCount = preg_match_all('/(?:^|,) # Line start or a comma
(?:
\\s*\\-\\-palette\\-\\-;[^;]*;([^,$]*)| # --palette--;label;paletteName
\\s*\\b[^;,]+\\b(?:;[^;]*;([^;,]+);?[^;,]*;?)?[^,]* # field;label;paletteName[;options[;colors]]
\\s*\\b[^;,]+\\b(?:;[^;]*;([^;,]+);?[^;,]*;?)?[^,]* # @deprecated since TYPO3 CMS 7: field;label;paletteName[;options[;colors]]
)/x', $typeDetails['showitem'], $paletteMatches);
if ($paletteCount > 0) {
$paletteNames = array_filter(array_merge($paletteMatches[1], $paletteMatches[2]));
......@@ -1652,6 +1653,19 @@ tt_content.' . $key . $suffix . ' {
}
}
// TCA migration
// @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. This can be removed *if* no additional TCA migration is added with CMS 8, see class TcaMigration
$tcaMigration = GeneralUtility::makeInstance(TcaMigration::class);
$GLOBALS['TCA'] = $tcaMigration->migrate($GLOBALS['TCA']);
$messages = $tcaMigration->getMessages();
if (!empty($messages)) {
$context = 'Automatic TCA migration done during boostrap. Please adapt TCA accordingly, these migrations'
. ' will be removed with TYPO3 CMS 8. The backend module "Configuration -> TCA" shows the modified values.'
. ' Please adapt these areas:';
array_unshift($messages, $context);
GeneralUtility::deprecationLog(implode(LF, $messages));
}
static::emitTcaIsBeingBuiltSignal($GLOBALS['TCA']);
}
......
......@@ -277,6 +277,10 @@ return array(
),
'isInitialInstallationInProgress' => FALSE, // Boolean: If TRUE, the installation is 'in progress'. This value is handled within the install tool step installer internally.
'clearCacheSystem' => FALSE, // Boolean: If set, the toolbar menu entry for clearing system caches (core cache, class cache, etc.) is visible for admin users.
'formEngine' => array(
'nodeRegistry' => array(), // Array: Registry to add or overwrite FormEngine nodes. Main key is a timestamp of the date when an entry is added, sub keys type, priority and class are required. Class must implement TYPO3\CMS\Backend\Form\NodeInterface.
'nodeResolver' => array(), // Array: Additional node resolver. Main key is a timestamp of the date when an entry is added, sub keys type, priority and class are required. Class must implement TYPO3\CMS\Backend\Form\NodeResolverInterface.
),
),
'EXT' => array( // Options related to the Extension Management
'allowGlobalInstall' => FALSE, // Boolean: If set, global extensions in typo3/ext/ are allowed to be installed, updated and deleted etc.
......
......@@ -78,12 +78,13 @@ return array(
)
)
)
)
),
'defaultExtras' => 'richtext:rte_transform[flag=rte_enabled|mode=ts_css]',
)
),
'types' => array(
'1' => array('showitem' => '
hidden, title, content;;9;richtext:rte_transform[flag=rte_enabled|mode=ts_css],
--div--;LLL:EXT:lang/locallang_tca.xlf:sys_news.tabs.access, starttime, endtime')
)
'1' => array(
'showitem' => 'hidden, title, content, --div--;LLL:EXT:lang/locallang_tca.xlf:sys_news.tabs.access, starttime, endtime',
),
),
);
==============================================
Breaking: #67229 - FormEngine related classses
==============================================
Description
===========
With the further development of FormEngine, some minor changes on ``PHP`` level were applied:
* Class ``TYPO3\CMS\T3editor\FormWizard`` is removed
* Class ``TYPO3\CMS\Rtehtmlarea\Controller\FrontendRteController`` is removed
* Method signature of class ``TYPO3\CMS\Utility\BackendUtility`` method ``getSpecConfParts`` changed
Impact
======
Using code will fatal or not be called any longer.
Affected Installations
======================
If extensions use above classes or methods. Since these classes are mostly core internal
it is quite unlikely any project in the wild is affected.
Migration
=========
Use the newly introduced API.
=================================
Deprecation: #65290 - TCA changes
=================================
Description
===========
Some details in the main ``Table Configuration Array, TCA``, known on PHP side as ``$GLOBALS['TCA']`` changed.
Simplified ``types`` ``showitem`` configuration using ``columnsOverrides``
--------------------------------------------------------------------------
If a field is configured as ``type`` in ``TCA`` ``ctrl`` section, the value of this database field determines
which fields are shown if opening a record in the backend. The shown fields are configured in ``TCA`` section
``types`` ``showitem`` and is a comma separated list of field names. Each field name can have 4 additional
semicolon separated options, from which the last two are dropped and moved:
Before:
.. code-block:: php
'types' => array(
'aType' => array(
'showitem' => 'aField,anotherField;otherLabel;aPalette;special:configuration;a-style-indicator,thirdField',
),
),
If a record is opened that has the type field set to ``aType``, it would show the three fields ``aField``, ``anotherField``
and ``thirdField``. The second field ``anotherField`` has further configuration and shows a different label, adds an additional
palette below the field referenced as ``aPalette``, adds ``special:configuration`` as special configuration and changes
the style with its last field. The last two parameters were changed: The style configuration is obsolete since 7.1 and has been removed therefore.
The special configuration is identical to ``defaultExtras`` field of a ``columns`` field section and can be added with this
name in a new introduced array ``columnsOverrides`` that is parallel to ``showitem`` of this type:
.. code-block:: php
'types' => array(
'aType' => array(
'showitem' => 'aField,anotherField;otherLabel;aPalette,thirdField',
'columnsOverrides` => array(
'anotherField' => array(
'defaultExtras' => 'special:configuration',
),
),
),
),
So, the 4th parameter is transferred to ``columnsOverrides`` while the 5th parameter is removed.
This change enables more flexible overrides of column configuration based on given type. This is currently used in
``FormEngine`` only, so only view related parameters must be overwritten here. It is not supported to change data handling
related parameters like ``type=text`` to ``type=select`` or similar, but it is possible to change for example the number
of rows shown in a ``type=text`` column field:
.. code-block:: php
'types' => array(
'aType' => array(
'showitem' => 'aField,anotherField;otherLabel;aPalette,thirdField',
'columnsOverrides` => array(
'anotherField' => array(
'config' => array(
'rows' => 42,
),
),
),
),
),
It is also possible to remove a given configuration from the default configuration using the ``__UNSET`` keyword. Again,
this is only supported for view related configuration options. Changing for instance an ``eval`` option may cripple the
PHP side validation done by the DataHandler that checks and stores values.
.. code-block:: php
'types' => array(
'aType' => array(
'columnsOverrides` => array(
'bodytext' => array(
'config' => array(
'rows' => '__UNSET',
),
),
),
),
),
The above example would remove the ``rows`` parameter of the ``bodytext`` field columns configuration, so a default
value would be used instead.
Simplified t3editor configuration
---------------------------------
t3editor is no longer configured and enabled as wizard.
Configuration for a column field looked like this before:
.. code-block:: php
'bodytext' => array(
'config' => array(
'type' => 'text',
'rows' => 42,
'wizards' => array(
't3editor' => array(
'type' => 'userFunc',
'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
'title' => 't3editor',
'icon' => 'wizard_table.gif',
'module' => array(
'name' => 'wizard_table'
),
'params' => array(
'format' => 'html',
'style' => 'width:98%; height: 60%;'
),
),
),
),
),
The new configuration is simplified to:
.. code-block:: php
'bodytext' => array(
'exclude' => 1,
'label' => 'aLabel',
'config' => array(
'type' => 'text',
'renderType' => 't3editor',
'format' => 'html',
'rows' => 42,
),
),
In case t3editor was only enabled for a specific type, this was previously done with
``enableByTypeConfig`` within the wizard configuration and ``wizards[theWizardName]`` as
the 4th semicolon separated parameter of the accorting field in section ``showitem`` of the
``type`` where t3editor should be enabled. Old configuration was:
.. code-block:: php
'columns' => array(
'bodytext' => array(
'exclude' => 1,
'label' => 'aLabel',
'config' => array(
'type' => 'text',
'rows' => 42,
'wizards' => array(
't3editorHtml' => array(
'type' => 'userFunc',
'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
'enableByTypeConfig' => 1,
'title' => 't3editor',
'icon' => 'wizard_table.gif',
'module' => array(
'name' => 'wizard_table'
),
'params' => array(
'format' => 'html',
'style' => 'width:98%; height: 60%;'
),
),
),
),
),
),
'types' => array(
'firstType' => array(
'showitem' => 'bodytext;;;wizards[t3editorHtml]',
),
),
This now uses the new ``columnsOverrides`` feature parallel to ``showitem``:
.. code-block:: php
'columns' => array(
'bodytext' => array(
'config' => array(
'type' => 'text',
'rows' => 42,
),
),
),
'types' => array(
'firstType' => array(
'showitem' => 'bodytext',
'columnsOverrides' => array(
'bodytext' => array(
'config' => array(
'format' => 'typoscript',
'renderType' => 't3editor',
),
),
),
),
Impact
======
TCA is automatically migrated during bootstrap of the TYPO3 core and the result is cached.
In case TCA is still registered or changed in extensions with entries in ``ext_tables.php``, and automatic
migration of this part of ``TCA`` is only triggered if extension ``compatibility6`` is loaded. This has a
performance penalty since the migration in ``compatibility6`` is then done on every frontend and backend
script call and is not cached.
It is strongly advised to move remaining ``TCA`` changes from ``ext_tables`` to ``Configuration/TCA`` or
``Configuration/TCA/Overrides`` of the according extension and to unload ``compatibility6``.
Migration
=========
An automatic migration is in place. It throws deprecation log entries in case ``TCA`` was changed on the fly.
The migration logs give hints on what exactly is changed and the final ``TCA`` can be inspected in the backend
configuration module. If outdated flex form is used, the migration is done within the FormEngine class
construct on the fly and will throw deprecation warnings as soon as a record with outdated ``TCA`` flex form
is opened in the backend.
Typical migration of the 4th ``showitem`` parameter involves moving a RTE configuration like
``richtext:rte_transform[flag=rte_enabled|mode=ts_css]`` or the ``type=text`` flags ``nowrap``, ``fixed-font``
and ``enabled-tab`` to ``columnsOverrides``.
============================================
Feature: #67229 - FormEngine NodeFactory API
============================================
Description
===========
The FormEngine class construct was moved to a tree approach with container classes as inner nodes and
element classes (the rendering widgets) as leaves. Finding, instantiation and preparation of those
classes is done via ``TYPO3\CMS\Backend\Form\NodeFactory``.
This class was extended with an API to allow flexible overriding and adding of containers and elements:
Registration of new nodes and overwriting existing nodes
--------------------------------------------------------
.. code-black:: php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1433196792] = array(
'nodeName' => 'input',
'priority' => 40,
'class' => \MyVendor\MyExtension\Form\Element\T3editorElement::class,
);
This registers the class ``MyVendor\MyExtension\Form\Element\T3editorElement`` as render class for
the type ``input``. It will be called to render elements of this type and must implement the interface
``TYPO3\CMS\Backend\Form\NodeInterface``. The array key is the unix timestamp of the date when an registry
element is added and is just used to have a unique key that is very unlikely to collide with others - this
is the same logic that is used for exception codes. If more than one registry element for the same type
is registered, the element with highest priority wins. Priority must be set between 0 and 100. Two elements
with same priority for the same type will throw an exception.
The core extension t3editor uses this API to substitute a ``type=text`` field with ``renderType=t3editor``
from the default ``TextElement`` to its own ``T3editorElement``.
This registry both allows completely overriding existing implementations of any existing given type, as well as
registration of a new ``renderType`` for own fancy elements. A TCA configuration for a new renderType
and its nodeRegistry could look like:
.. code-block:: php
'columns' => array(
'bodytext' => array(
'config' => array(
'type' => 'text',
'renderType' => '3dCloud',
),
),
),
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1433197759] = array(
'nodeName' => '3dCloud',
'priority' => 40,
'class' => \MyVendor\MyExtension\Form\Element\ShowTextAs3dCloudElement::class,
);
Resolve class resolution to different render classes
----------------------------------------------------
In case the above API is not flexible enough, another class can be registered to resolve the final
class that renders a certain element or container differently:
.. code-block:: php
// Register FormEngine node type resolver hook to render RTE in FormEngine if enabled
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'][1433198160] = array(
'nodeName' => 'text',
'priority' => 50,
'class' => \MyVendor\MyExtension\Form\Resolver\MyTextNodeResolver::class,
);
This registers a resolver class at priority 50 if the type ``text`` should be rendered. This class must
implement ``TYPO3\CMS\Backend\Form\NodeResolverInterface`` and can return a different class name that is
called as render class. The render class in turn must implement ``TYPO3\CMS\Backend\Form\NodeInterface``.
The array key is again a unix timestamp of the date when this resolver code is registered. Multiple resolvers
are a chain, the resolver with highest priority is asked first, and the chain is called until one resolver
returns a new class name. If no resolver returns anything, the default class name will be instantiated and rendered.
Priority is again between 0 and 100 and two resolver for the same type and same priority will throw an exception.
The resolver will receive the full ``globalOptions`` array with all settings to take a resolve decision
on all incoming values.
This API is used by core extension rtehtmlarea to route the rendering of ``type=text`` to its own
``RichTextElement`` class in case the editor is enabled for this field and for the user.
This API allows fine grained resolution of render-nodes based on any need, for instance it would be
easily possible to call another different richtext implementation (eg. TinyMCE) for specific fields
of own extensions based on moon phases, by adding a resolver class with a higher priority.
Warning
-------
The internal data given to the resolver class still may change. Both the ``globalOptions`` and the current
``renderType`` values are subject to change without further notice until TYPO3 CMS 7 LTS.
<?php
namespace TYPO3\CMS\Core\Tests\Unit\Migrations;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Core\Tests\UnitTestCase;
use TYPO3\CMS\Core\Migrations\TcaMigration;
/**
* Test case
*/
class TcaMigrationTest extends UnitTestCase {
/**
* @test
*/
public function migrateReturnsGivenArrayUnchangedIfNoMigrationNeeded() {
$input = $expected = array(
'aTable' => array(
'ctrl' => array(
'aKey' => 'aValue',
),
'columns' => array(
'aField' => array(
'label' => 'foo',
'config' => array(
'type' => 'aType',
'lolli' => 'did this',
)
),
),
'types' => array(
0 => array(
'showitem' => 'this,should;stay;this,too',
),
),
),
);
$subject = new TcaMigration();
$this->assertEquals($expected, $subject->migrate($input));
}
/**
* @test
*/
public function migrateChangesT3editorWizardToT3editorRenderTypeIfNotEnabledByTypeConfig() {
$input = array(
'aTable' => array(
'columns' => array(
'bodytext' => array(
'exclude' => 1,
'label' => 'aLabel',
'config' => array(
'type' => 'text',
'rows' => 42,
'wizards' => array(
't3editor' => array(
'type' => 'userFunc',
'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
'title' => 't3editor',
'icon' => 'wizard_table.gif',
'module' => array(
'name' => 'wizard_table'
),
'params' => array(
'format' => 'html',
'style' => 'width:98%; height: 60%;'
),
),
),
),
),
),
),
);
$expected = array(
'aTable' => array(
'columns' => array(
'bodytext' => array(
'exclude' => 1,
'label' => 'aLabel',
'config' => array(
'type' => 'text',
'renderType' => 't3editor',
'format' => 'html',
'rows' => 42,
),
),
),
),
);
$subject = new TcaMigration();
$this->assertEquals($expected, $subject->migrate($input));
}
/**
* @test
*/
public function migrateDropsStylePointerFromShowItem() {
$input = array(
'aTable' => array(
'types' => array(
0 => array(
'showitem' => 'aField,anotherField;with;palette;;and-style-pointer,thirdField',
),
1 => array(
'showitem' => 'aField,;;;;only-a-style-pointer,anotherField',
),
),
),
);
$expected = array(
'aTable' => array(
'types' => array(
0 => array(
'showitem' => 'aField,anotherField;with;palette,thirdField',
),
1 => array(
'showitem' => 'aField,anotherField',
),
),
),
);
$subject = new TcaMigration();
$this->assertEquals($expected, $subject->migrate($input));
}
/**
* @test
*/
public function migrateMovesSpecialConfigurationToColumnsOverridesDefaultExtras() {
$input = array(
'aTable' => array(
'types' => array(
0 => array(
'showitem' => 'aField,anotherField;with;palette;special:configuration,thirdField',
),
),