[FEATURE] Move CE table options from flexform to tt_content 55/40955/9
authorPatrick Broens <patrick@patrickbroens.nl>
Thu, 28 May 2015 10:33:13 +0000 (12:33 +0200)
committerBenjamin Mack <benni@typo3.org>
Wed, 15 Jul 2015 17:18:10 +0000 (19:18 +0200)
When EXT:css_styled_content isn't installed a Migration wizard is
shown in the install tool to move the flexform values to regular
database fields in the tt_content table.

Resolves: #67950
Releases: master
Change-Id: I45dfd8882b98ed569f738bb2de10da52063a4400
Reviewed-on: http://review.typo3.org/40955
Reviewed-by: Susanne Moog <typo3@susannemoog.de>
Tested-by: Susanne Moog <typo3@susannemoog.de>
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
typo3/sysext/core/Documentation/Changelog/master/Feature-67950-MoveCETableOptionsFromFlexformToTt_content.rst [new file with mode: 0644]
typo3/sysext/frontend/Configuration/TCA/tt_content.php
typo3/sysext/frontend/Resources/Private/Language/Database.xlf [new file with mode: 0644]
typo3/sysext/frontend/ext_tables.sql
typo3/sysext/install/Classes/Updates/TableFlexFormToTtContentFieldsUpdate.php [new file with mode: 0644]
typo3/sysext/install/Tests/Unit/Updates/TableFlexFormToTtContentFieldsUpdateTest.php [new file with mode: 0644]
typo3/sysext/install/ext_localconf.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-67950-MoveCETableOptionsFromFlexformToTt_content.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-67950-MoveCETableOptionsFromFlexformToTt_content.rst
new file mode 100644 (file)
index 0000000..690ec8c
--- /dev/null
@@ -0,0 +1,14 @@
+===================================================================
+Feature: #67950 - Move CE table options from flexform to tt_content
+===================================================================
+
+Description
+===========
+
+The CE table (processing) configuration ``Table caption``, ``Field delimiter``, ``Text enclosure``, ``Table header position`` and ``Use table footer`` are in EXT:css_styled_content configured/saved in a flexform. This has now been moved to regular database fields.
+
+
+Impact
+======
+
+When EXT:css_styled_content isn't installed a Migration wizard is shown in the install tool to move the flexform values to regular database fields in the tt_content table.
\ No newline at end of file
index f959ab8..21fc135 100644 (file)
@@ -1018,7 +1018,66 @@ return array(
                                'suppress_icons' => 1,
                                'itemsProcFunc' => \TYPO3\CMS\Core\Category\CategoryRegistry::class . '->getCategoryFieldsForTable',
                        )
-               )
+               ),
+               'table_caption' => array(
+                       'exclude' => TRUE,
+                       'label' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_caption',
+                       'config' => array(
+                               'type' => 'input'
+                       )
+               ),
+               'table_delimiter' => array(
+                       'exclude' => TRUE,
+                       'label' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_delimiter',
+                       'config' => array(
+                               'type' => 'select',
+                               'items' => array(
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_delimiter.124', 124),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_delimiter.59', 59),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_delimiter.44', 44),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_delimiter.58', 58),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_delimiter.9', 9)
+                               ),
+                               'default' => 124
+                       )
+               ),
+               'table_enclosure' => array(
+                       'exclude' => TRUE,
+                       'label' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_enclosure',
+                       'config' => array(
+                               'type' => 'select',
+                               'items' => array(
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_enclosure.0', 0),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_enclosure.39', 39),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_enclosure.34', 34)
+                               ),
+                               'default' => 0
+                       )
+               ),
+               'table_header_position' => array(
+                       'exclude' => TRUE,
+                       'label' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_header_position',
+                       'config' => array(
+                               'type' => 'select',
+                               'items' => array(
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_header_position.0', 0),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_header_position.1', 1),
+                                       array('LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_header_position.2', 2)
+                               ),
+                               'default' => 0
+                       )
+               ),
+               'table_tfoot' => array(
+                       'exclude' => TRUE,
+                       'label' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.table_tfoot',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => 0,
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_core.xml:labels.enabled', 1)
+                               )
+                       )
+               ),
        ),
        'types' => array(
                '1' => array(
@@ -1052,7 +1111,24 @@ return array(
                                '20' => 'layout',
                                '21' => 'layout'
                        )
-               )
+               ),
+               'table' => array(
+                       'showitem' => '
+                                       --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
+                                       --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header,
+                                       bodytext;LLL:EXT:frontend/Resources/Private/Language/TCA.xlf:field.table.bodytext;tableconfiguration;nowrap:wizards[table],
+                                       table_caption,
+                               --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
+                                       layout;LLL:EXT:cms/locallang_ttc.xlf:layout_formlabel,
+                                       behaviour,
+                                       --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.table_layout;tablelayout,
+                                       --palette--;LLL:EXT:frontend/Resources/Private/Language/TCA.xlf:palette.appearanceLinks;appearanceLinks,
+                               --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access,
+                                       hidden;LLL:EXT:frontend/Resources/Private/Language/TCA.xlf:field.default.hidden,
+                                       --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
+                               --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended
+                       '
+               ),
        ),
        'palettes' => array(
                'general' => array(
@@ -1126,6 +1202,12 @@ return array(
                ),
                'uploadslayout' => array(
                        'showitem' => 'filelink_size;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:filelink_size_formlabel',
+               ),
+               'tableconfiguration' => array(
+                       'showitem' => 'table_delimiter,table_enclosure'
+               ),
+               'tablelayout' => array(
+                       'showitem' => 'cols,table_header_position,table_tfoot'
                )
        )
 );
diff --git a/typo3/sysext/frontend/Resources/Private/Language/Database.xlf b/typo3/sysext/frontend/Resources/Private/Language/Database.xlf
new file mode 100644 (file)
index 0000000..d5d2bef
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
+       <file t3:id="1427832976" source-language="en" datatype="plaintext" original="messages" date="2014-02-07T20:22:32Z" product-name="frontend">
+               <header/>
+               <body>
+                       <trans-unit id="tt_content.table_caption">
+                               <source>Table caption</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_delimiter">
+                               <source>Field Delimiter</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_delimiter.124">
+                               <source>| (Pipe)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_delimiter.59">
+                               <source>; (Semicolon)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_delimiter.58">
+                               <source>: (Colon)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_delimiter.44">
+                               <source>, (Comma)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_delimiter.9">
+                               <source>⇥ (Tab)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_enclosure">
+                               <source>Text enclosure</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_enclosure.0">
+                               <source>None</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_enclosure.39">
+                               <source>' (Single quotes)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_enclosure.34">
+                               <source>" (Double quotes)</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_header_position">
+                               <source>Table header position</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_header_position.0">
+                               <source>No header</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_header_position.1">
+                               <source>Top</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_header_position.2">
+                               <source>Left</source>
+                       </trans-unit>
+                       <trans-unit id="tt_content.table_tfoot">
+                               <source>Use table footer (wrap last row with &lt;tfoot&gt; tags)</source>
+                       </trans-unit>
+               </body>
+       </file>
+</xliff>
\ No newline at end of file
index bf581a3..fe7f479 100644 (file)
@@ -296,6 +296,11 @@ CREATE TABLE tt_content (
        l18n_diffsource mediumblob,
        selected_categories text,
        category_field varchar(64) DEFAULT '' NOT NULL,
+       table_caption varchar(255) DEFAULT NULL,
+       table_delimiter smallint(6) unsigned DEFAULT '0' NOT NULL,
+       table_enclosure smallint(6) unsigned DEFAULT '0' NOT NULL,
+       table_header_position tinyint(3) unsigned DEFAULT '0' NOT NULL,
+       table_tfoot tinyint(1) unsigned DEFAULT '0' NOT NULL,
 
        PRIMARY KEY (uid),
        KEY t3ver_oid (t3ver_oid,t3ver_wsid),
diff --git a/typo3/sysext/install/Classes/Updates/TableFlexFormToTtContentFieldsUpdate.php b/typo3/sysext/install/Classes/Updates/TableFlexFormToTtContentFieldsUpdate.php
new file mode 100644 (file)
index 0000000..835390e
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+namespace TYPO3\CMS\Install\Updates;
+
+/*
+ * 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\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Migrate the Flexform for CType 'table' to regular fields in tt_content
+ */
+class TableFlexFormToTtContentFieldsUpdate extends AbstractUpdate {
+
+       /**
+        * @var string
+        */
+       protected $title = 'Migrate the Flexform for CType "table" to regular fields in tt_content';
+
+       /**
+        * Checks if an update is needed
+        *
+        * @param string &$description The description for the update
+        * @return bool Whether an update is needed (TRUE) or not (FALSE)
+        */
+       public function checkForUpdate(&$description) {
+               $flexFormCount = $this->getDatabaseConnection()->exec_SELECTcountRows(
+                       'uid',
+                       'tt_content',
+                       'CType=\'table\' AND pi_flexform IS NOT NULL AND deleted = 0'
+               );
+
+               if (
+                       $this->isWizardDone() || $flexFormCount === 0
+                       || ExtensionManagementUtility::isLoaded('css_styled_content')
+               ) {
+                       return FALSE;
+               }
+
+               $description = 'The extension "frontend" uses regular database fields in the tt_content table ' .
+                       'for the CType "table". Before this was a FlexForm.<br /><br />'.
+                       'This update wizard migrates these FlexForms to regular database fields.';
+
+               return TRUE;
+       }
+
+       /**
+        * Performs the database update if CType 'table' still has content in pi_flexform
+        *
+        * @param array &$databaseQueries Queries done in this update
+        * @param mixed &$customMessages Custom messages
+        * @return bool
+        */
+       public function performUpdate(array &$databaseQueries, &$customMessages) {
+               $databaseConnection = $this->getDatabaseConnection();
+
+               $databaseResult = $databaseConnection->exec_SELECTquery(
+                       'uid, pi_flexform',
+                       'tt_content',
+                       'CType=\'table\' AND pi_flexform IS NOT NULL AND deleted = 0'
+               );
+
+               while ($tableRecord = $databaseConnection->sql_fetch_assoc($databaseResult)) {
+                       $flexForm = $this->initializeFlexForm($tableRecord['pi_flexform']);
+
+                       if (is_array($flexForm)) {
+                               $fields = $this->mapFieldsFromFlexForm($flexForm);
+
+                               // Set pi_flexform to NULL
+                               $fields['pi_flexform'] = NULL;
+
+                               $databaseConnection->exec_UPDATEquery(
+                                       'tt_content',
+                                       'uid=' . (int)$tableRecord['uid'],
+                                       $fields
+                               );
+
+                               $databaseQueries[] = $databaseConnection->debug_lastBuiltQuery;
+                       }
+               }
+
+               $databaseConnection->sql_free_result($databaseResult);
+
+               $this->markWizardAsDone();
+
+               return TRUE;
+       }
+
+       /**
+        * Map the old FlexForm values to the new database fields
+        * and fill them with the proper data
+        *
+        * @param array $flexForm The content of the FlexForm
+        * @return array The fields which need to be updated in the tt_content table
+        */
+       protected function mapFieldsFromFlexForm($flexForm) {
+               $fields = array();
+
+               $mapping = array(
+                       'table_caption' => array(
+                               'sheet' => 'sDEF',
+                               'fieldName' => 'acctables_caption',
+                               'default' => '',
+                               'values' => 'passthrough'
+                       ),
+                       'table_delimiter' => array(
+                               'sheet' => 's_parsing',
+                               'fieldName' => 'tableparsing_delimiter',
+                               'default' => 124,
+                               'values' => 'passthrough'
+                       ),
+                       'table_enclosure' => array(
+                               'sheet' => 's_parsing',
+                               'fieldName' => 'tableparsing_quote',
+                               'default' => 0,
+                               'values' => 'passthrough'
+                       ),
+                       'table_header_position' => array(
+                               'sheet' => 'sDEF',
+                               'fieldName' => 'acctables_headerpos',
+                               'default' => 0,
+                               'values' => array(
+                                       'top' => 1,
+                                       'left' => 2
+                               )
+                       ),
+                       'table_tfoot' => array(
+                               'sheet' => 'sDEF',
+                               'fieldName' => 'acctables_tfoot',
+                               'default' => 0,
+                               'values' => 'passthrough'
+                       )
+               );
+
+               foreach ($mapping as $fieldName => $configuration) {
+                       $flexFormValue = $this->getFlexFormValue($flexForm, $configuration['fieldName'], $configuration['sheet']);
+
+                       if ($flexFormValue !== '') {
+                               if ($configuration['values'] === 'passthrough') {
+                                       $fields[$fieldName] = $flexFormValue;
+                               } elseif (is_array($configuration['values'])) {
+                                       $fields[$fieldName] = $configuration['values'][$flexFormValue];
+                               }
+                       } else {
+                               $fields[$fieldName] = $configuration['default'];
+                       }
+               }
+
+               return $fields;
+
+       }
+
+       /**
+        * Convert the XML of the FlexForm to an array
+        *
+        * @param string|NULL $flexFormXml The XML of the FlexForm
+        * @return array|NULL Converted XML to array
+        */
+       protected function initializeFlexForm($flexFormXml) {
+               $flexForm = NULL;
+
+               if ($flexFormXml) {
+                       $flexForm = GeneralUtility::xml2array($flexFormXml);
+                       if (!is_array($flexForm)) {
+                               $flexForm = NULL;
+                       }
+               }
+
+               return $flexForm;
+       }
+
+       /**
+        * @param array $flexForm The content of the FlexForm
+        * @param string $fieldName The field name to get the value for
+        * @param string $sheet The sheet on which this value is located
+        * @return string The value
+        */
+       protected function getFlexFormValue(array $flexForm, $fieldName, $sheet = 'sDEF') {
+               return $flexForm['data'][$sheet]['lDEF'][$fieldName]['vDEF'];
+       }
+}
diff --git a/typo3/sysext/install/Tests/Unit/Updates/TableFlexFormToTtContentFieldsUpdateTest.php b/typo3/sysext/install/Tests/Unit/Updates/TableFlexFormToTtContentFieldsUpdateTest.php
new file mode 100644 (file)
index 0000000..fe55aa9
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+namespace TYPO3\CMS\Install\Tests\Unit\Updates;
+
+/*
+ * 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 Prophecy\Argument;
+use Prophecy\Prophecy\ObjectProphecy;
+use Prophecy\Prophet;
+use TYPO3\CMS\Core\Package\PackageManager;
+use TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Install\Updates\TableFlexFormToTtContentFieldsUpdate as UpdateWizard;
+
+/**
+ * Test Class for TableFlexFormToTtContentFieldsUpdateTest
+ */
+class TableFlexFormToTtContentFieldsUpdateTest extends BaseTestCase {
+
+       /**
+        * @var ObjectProphecy
+        */
+       protected $packageManagerProphecy;
+
+       /**
+        * @var ObjectProphecy
+        */
+       protected $dbProphecy;
+
+       /**
+        * @var ObjectProphecy
+        */
+       protected $updateWizard;
+
+       public function setUp() {
+               unset($GLOBALS['TYPO3_CONF_VARS']['INSTALL']['wizardDone']);
+               $prophet = new Prophet();
+               $this->packageManagerProphecy = $prophet->prophesize(\TYPO3\CMS\Core\Package\PackageManager::class);
+               $this->dbProphecy = $prophet->prophesize(\TYPO3\CMS\Core\Database\DatabaseConnection::class);
+               $GLOBALS['TYPO3_DB'] = $this->dbProphecy->reveal();
+               $this->updateWizard = new UpdateWizard();
+               ExtensionManagementUtility::setPackageManager($this->packageManagerProphecy->reveal());
+       }
+
+       public function tearDown() {
+               ExtensionManagementUtility::setPackageManager(new PackageManager());
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function updateWizardDoesNotRunIfCssStyledContentIsInstalled_withoutExistingFlexFormContent() {
+
+               $this->packageManagerProphecy->isPackageActive('css_styled_content')->willReturn(TRUE);
+               $this->dbProphecy->exec_SELECTcountRows(Argument::cetera())->willReturn(0);
+
+               $description = '';
+               $this->assertFalse($this->updateWizard->checkForUpdate($description));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function updateWizardDoesNotRunIfCssStyledContentIsInstalled_withExistingFlexFormContent() {
+               $this->packageManagerProphecy->isPackageActive('css_styled_content')->willReturn(TRUE);
+               $this->dbProphecy->exec_SELECTcountRows(Argument::cetera())->willReturn(1);
+
+               $description = '';
+               $this->assertFalse($this->updateWizard->checkForUpdate($description));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function updateWizardDoesRunIfCssStyledContentIsNotInstalledAndExistingFlexFormContent() {
+               $this->packageManagerProphecy->isPackageActive('css_styled_content')->willReturn(FALSE);
+               $this->dbProphecy->exec_SELECTcountRows(Argument::cetera())->willReturn(1);
+
+               $description = '';
+               $this->assertTrue($this->updateWizard->checkForUpdate($description));
+       }
+}
index bacd6c2..c48b086 100644 (file)
@@ -8,6 +8,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['PageShortcut
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['backendShortcuts'] = \TYPO3\CMS\Install\Updates\MigrateShortcutUrlsUpdate::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['processedFilesChecksum'] = \TYPO3\CMS\Install\Updates\ProcessedFileChecksumUpdate::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['filesReplacePermission'] = \TYPO3\CMS\Install\Updates\FilesReplacePermissionUpdate::class;
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tableCType'] = \TYPO3\CMS\Install\Updates\TableFlexFormToTtContentFieldsUpdate::class;
 
 $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
 $signalSlotDispatcher->connect(