[TASK] Add functional tests from irre_tutorial to the core 74/26674/9
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Wed, 8 Jan 2014 12:38:07 +0000 (13:38 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Thu, 9 Jan 2014 10:30:11 +0000 (11:30 +0100)
Add irre_tutorial extension as mock extension for functional tests.
Port functional tests from IRRE tutorial to the functional testing
framework and include them in the core and workspaces extensions.
Some tests are skipped for now, because the core is buggy.

Releases: 6.2
Resolves: #54812
Change-Id: I691dd97e7649c8239b6e96ce6f9a9d59e9b124c4
Reviewed-on: https://review.typo3.org/26674
Tested-by: Markus Klein
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
41 files changed:
typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractLocalizationTestCase.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/MToNMMAsymmetric.xml [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMAsymmetricLocalizationKeepTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMAsymmetricLocalizationSelectTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ChangeLog [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.1ncsv.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.1nff.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.general.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnasym.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnattr.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnmmasym.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnsym.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/FlexForms/tt_content_flexform.xml [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.1ncsv.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.1nff.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnasym.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnattr.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnmmasym.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnsym.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/README.txt [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Private/Language/locallang_db.xml [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_offer_rel.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_rel.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer_price_rel.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_price.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_emconf.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_icon.gif [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.sql [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Fixtures/pages.xml
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractOneToNTestCase.php [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/OneToNCSV.xml [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/OneToNForeignField.xml [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMTest.php [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/OneToNCSVTest.php [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/OneToNForeignFieldTest.php [new file with mode: 0644]
typo3/sysext/workspaces/Tests/Functional/Fixtures/sys_workspace.xml

diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractLocalizationTestCase.php b/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractLocalizationTestCase.php
new file mode 100644 (file)
index 0000000..e46490f
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Oliver Hader <oliver@typo3.org>
+*  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!
+***************************************************************/
+
+require_once(dirname(__FILE__). '/AbstractTestCase.php');
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Generic test helpers for localization tests
+ *
+ */
+abstract class AbstractLocalizationTestCase extends AbstractTestCase {
+       const COMMAND_LocalizeSynchronize = 'inlineLocalizeSynchronize';
+       const COMMAND_LocalizeSynchronize_Localize = 'localize';
+       const COMMAND_LocalizeSynchronize_Synchronize = 'synchronize';
+
+       const VALUE_LocalizationMode_Keep = 'keep';
+       const VALUE_LocalizationMode_Select = 'select';
+
+       const TABLE_Hotel = 'tx_irretutorial_mnmmasym_hotel';
+       const TABLE_Offer = 'tx_irretutorial_mnmmasym_offer';
+       const TABLE_Price = 'tx_irretutorial_mnmmasym_price';
+       const TABLE_Relation_Hotel_Offer = 'tx_irretutorial_mnmmasym_hotel_offer_rel';
+       const TABLE_Relation_Offer_Price = 'tx_irretutorial_mnmmasym_offer_price_rel';
+
+       const FIELD_Hotel_Offers = 'offers';
+       const FIELD_Offer_Hotels = 'hotels';
+       const FIELD_Offer_Prices = 'prices';
+       const FIELD_Price_Offers = 'offers';
+
+       /**
+        * @var array
+        */
+       protected $structure = array(
+               self::TABLE_Hotel => array(self::FIELD_Hotel_Offers),
+               self::TABLE_Offer => array(self::FIELD_Offer_Hotels, self::FIELD_Offer_Prices),
+               self::TABLE_Price => array(self::FIELD_Price_Offers),
+       );
+
+       /**
+        * Asserts that accordant localizations exist.
+        *
+        * @param array $tables Table names with list of ids to be edited
+        * @param integer $languageId The sys_language_id
+        * @param boolean $expected Expected result of assertion
+        * @return void
+        */
+       protected function assertLocalizations(array $tables, $languageId = self::VALUE_LanguageId, $expected = TRUE) {
+               foreach ($tables as $tableName => $idList) {
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $localization = BackendUtility::getRecordLocalization($tableName, $id, $languageId);
+                               $isLocalization = is_array($localization) && count($localization);
+                               $this->assertTrue(
+                                       !($expected XOR $isLocalization),
+                                       'Localization for ' . $tableName . ':' . $id . ($expected ? ' not' : '') . ' available'
+                               );
+                       }
+               }
+       }
+
+       /**
+        * Gets the id of the localized record of a language parent.
+        *
+        * @param string $tableName
+        * @param integer $id
+        * @param integer $languageId
+        * @return boolean
+        */
+       protected function getLocalizationId($tableName, $id, $languageId = self::VALUE_LanguageId) {
+               $localization = BackendUtility::getRecordLocalization($tableName, $id, $languageId);
+               if (is_array($localization) && count($localization)) {
+                       return $localization[0]['uid'];
+               }
+
+               return FALSE;
+       }
+}
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php b/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php
new file mode 100644 (file)
index 0000000..ed0050d
--- /dev/null
@@ -0,0 +1,442 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Oliver Hader <oliver@typo3.org>
+*  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 TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Generic test helpers.
+ *
+ */
+abstract class AbstractTestCase extends \TYPO3\CMS\Core\Tests\FunctionalTestCase {
+       const VALUE_LanguageId = 2;
+
+       const TABLE_Pages = 'pages';
+
+       const COMMAND_Copy = 'copy';
+       const COMMAND_Localize = 'localize';
+       const COMMAND_Delete = 'delete';
+
+       const PROPERTY_LocalizeReferencesAtParentLocalization = 'localizeReferencesAtParentLocalization';
+       const BEHAVIOUR_LocalizeChildrenAtParentLocalization = 'localizeChildrenAtParentLocalization';
+       const BEHAVIOUR_LocalizationMode = 'localizationMode';
+
+       protected $testExtensionsToLoad = array('typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial');
+
+       /**
+        * @var integer
+        */
+       private $expectedLogEntries = 0;
+
+       /**
+        * Sets up this test case.
+        *
+        * @return void
+        */
+       public function setUp() {
+               parent::setUp();
+
+               $this->setUpBackendUserFromFixture(1);
+               \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->initializeLanguageObject();
+
+               $this->expectedLogEntries = 0;
+
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['sqlDebug'] = 1;
+
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/pages.xml');
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/sys_language.xml');
+       }
+
+       /**
+        * Tears down this test case.
+        *
+        * @return void
+        */
+       public function tearDown() {
+               $this->assertNoLogEntries();
+
+               $this->expectedLogEntries = 0;
+
+               parent::tearDown();
+       }
+
+       /**
+        * Sets the number of expected log entries.
+        *
+        * @param integer $count
+        * @return void
+        */
+       protected function setExpectedLogEntries($count) {
+               $count = intval($count);
+
+               if ($count > 0) {
+                       $this->expectedLogEntries = $count;
+               }
+       }
+
+       /**
+        * @param string $command
+        * @param mixed $value
+        * @param array $tables Table names with list of ids to be edited
+        * @return array
+        */
+       protected function getElementStructureForCommands($command, $value, array $tables) {
+               $commandStructure = array();
+
+               foreach ($tables as $tableName => $idList) {
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $commandStructure[$tableName][$id] = array(
+                                       $command => $value
+                               );
+                       }
+               }
+
+               return $commandStructure;
+       }
+
+       /**
+        * Simulates executing commands by using t3lib_TCEmain.
+        *
+        * @param  array $elements The cmdmap to be delivered to DataHandler
+        * @return \TYPO3\CMS\Core\DataHandling\DataHandler
+        */
+       protected function simulateCommandByStructure(array $elements) {
+               $tceMain = $this->getTceMain();
+               $tceMain->start(array(), $elements);
+               $tceMain->process_cmdmap();
+
+               return $tceMain;
+       }
+
+       /**
+        * @param string $command
+        * @param mixed $value
+        * @param array $tables Table names with list of ids to be edited
+        * @return \TYPO3\CMS\Core\DataHandling\DataHandler
+        */
+       protected function simulateCommand($command, $value, array $tables) {
+               return $this->simulateCommandByStructure(
+                       $this->getElementStructureForCommands($command, $value, $tables)
+               );
+       }
+
+       /**
+        * Gets the last log entry.
+        *
+        * @return array
+        */
+       protected function getLastLogEntryMessage() {
+               $message = '';
+
+               $logEntries = $this->getDatabase()->exec_SELECTgetRows('*', 'sys_log', 'error IN (1,2)', '', '', 1);
+
+               if (is_array($logEntries) && count($logEntries)) {
+                       $message = $logEntries[0]['details'];
+               }
+
+               return $message;
+       }
+
+       /**
+        * @param  array $itemArray
+        * @return array
+        */
+       protected function getElementsByItemArray(array $itemArray) {
+               $elements = array();
+
+               foreach ($itemArray as $item) {
+                       $elements[$item['table']][$item['id']] = BackendUtility::getRecord($item['table'], $item['id']);
+               }
+
+               return $elements;
+       }
+
+       /**
+        * Gets all records of a table.
+        *
+        * @param string $table Name of the table
+        * @param string $indexField
+        * @return array
+        */
+       protected function getAllRecords($table, $indexField = 'uid') {
+               return $this->getDatabase()->exec_SELECTgetRows('*', $table, '1=1', '', '', '', $indexField);
+       }
+
+       /**
+        * Gets the TCE configuration of a field.
+        *
+        * @param  $tableName
+        * @param  $fieldName
+        * @return array
+        */
+       protected function getTcaFieldConfiguration($tableName, $fieldName) {
+               if (!isset($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'])) {
+                       $this->fail('TCA definition for field ' . $tableName . '.' . $fieldName . ' not available');
+               }
+
+               return $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'];
+       }
+
+       /**
+        * @param string $tableName
+        * @param string $fieldName
+        * @param string $propertyName
+        * @param mixed $value
+        * @return void
+        */
+       protected function setTcaFieldConfiguration($tableName, $fieldName, $propertyName, $value) {
+               if (isset($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'])) {
+                       $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'][$propertyName] = $value;
+               }
+       }
+
+       /**
+        * @param string $tableName
+        * @param string $fieldName
+        * @param string $behaviourName
+        * @param mixed $value
+        * @return void
+        */
+       protected function setTcaFieldConfigurationBehaviour($tableName, $fieldName, $behaviourName, $value) {
+               if (isset($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'])) {
+                       if (!isset($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config']['behaviour'])) {
+                               $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config']['behaviour'] = array();
+                       }
+
+                       $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config']['behaviour'][$behaviourName] = $value;
+               }
+       }
+
+       /**
+        * Gets the field value of a record.
+        *
+        * @param  $tableName
+        * @param  $id
+        * @param  $fieldName
+        * @return string
+        */
+       protected function getFieldValue($tableName, $id, $fieldName) {
+               $record = BackendUtility::getRecord($tableName, $id, $fieldName);
+
+               if (!is_array($record)) {
+                       $this->fail('Record ' . $tableName . ':' . $id . ' not available');
+               }
+
+               return $record[$fieldName];
+       }
+
+       /**
+        * Gets instance of \TYPO3\CMS\Core\Database\RelationHandler.
+        *
+        * @return \TYPO3\CMS\Core\Database\RelationHandler
+        */
+       protected function getLoadDbGroup() {
+               $loadDbGroup = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
+
+               return $loadDbGroup;
+       }
+
+       /**
+        * Gets an instance of \TYPO3\CMS\Core\DataHandling\DataHandler.
+        *
+        * @return \TYPO3\CMS\Core\DataHandling\DataHandler
+        */
+       protected function getTceMain() {
+               $tceMain = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
+               return $tceMain;
+       }
+
+       /**
+        * Assert that no sys_log entries had been written.
+        *
+        * @return void
+        */
+       protected function assertNoLogEntries() {
+               $logEntries = $this->getLogEntries();
+
+               if (count($logEntries) > $this->expectedLogEntries) {
+                       var_dump(array_values($logEntries));
+                       ob_flush();
+                       $this->fail('The sys_log table contains unexpected entries.');
+               } elseif (count($logEntries) < $this->expectedLogEntries) {
+                       $this->fail('Expected count of sys_log entries no reached.');
+               }
+       }
+
+       /**
+        * Asserts the correct order of elements.
+        *
+        * @param string $table
+        * @param string $field
+        * @param array $expectedOrderOfIds
+        * @param string $message
+        * @return void
+        */
+       protected function assertSortingOrder($table, $field, $expectedOrderOfIds, $message) {
+               $expectedOrderOfIdsCount = count($expectedOrderOfIds);
+               $elements = $this->getAllRecords($table);
+
+               for ($i = 0; $i < $expectedOrderOfIdsCount-1; $i++) {
+                       $this->assertLessThan(
+                               $elements[$expectedOrderOfIds[$i+1]][$field],
+                               $elements[$expectedOrderOfIds[$i]][$field],
+                               $message
+                       );
+               }
+       }
+
+       /**
+        * Asserts reference index elements.
+        *
+        * @param array $assertions
+        * @param boolean $expected
+        */
+       protected function assertReferenceIndex(array $assertions, $expected = TRUE) {
+               $references = $this->getAllRecords('sys_refindex', 'hash');
+
+               foreach ($assertions as $parent => $children) {
+                       foreach ($children as $child) {
+                               $parentItems = explode(':', $parent);
+                               $childItems = explode(':', $child);
+
+                               $assertion = array(
+                                       'tablename' => $parentItems[0],
+                                       'recuid' => $parentItems[1],
+                                       'field' => $parentItems[2],
+                                       'ref_table' => $childItems[0],
+                                       'ref_uid' => $childItems[1],
+                               );
+
+                               $this->assertTrue(
+                                       ($expected === $this->executeAssertionOnElements($assertion, $references)),
+                                       'Expected reference index element for ' . $parent . ' -> ' . $child
+                               );
+                       }
+               }
+       }
+
+       /**
+        * @param string $parentTableName
+        * @param integer $parentId
+        * @param string $parentFieldName
+        * @param array $assertions
+        * @param string $mmTable
+        * @param boolean $expected
+        * @return void
+        */
+       protected function assertChildren($parentTableName, $parentId, $parentFieldName, array $assertions, $mmTable = '', $expected = TRUE) {
+               $tcaFieldConfiguration = $this->getTcaFieldConfiguration($parentTableName, $parentFieldName);
+
+               $loadDbGroup = $this->getLoadDbGroup();
+               $loadDbGroup->start(
+                       $this->getFieldValue($parentTableName, $parentId, $parentFieldName),
+                       $tcaFieldConfiguration['foreign_table'],
+                       $mmTable,
+                       $parentId,
+                       $parentTableName,
+                       $tcaFieldConfiguration
+               );
+
+               $elements = $this->getElementsByItemArray($loadDbGroup->itemArray);
+
+               foreach ($assertions as $index => $assertion) {
+                       $this->assertTrue(
+                               ($expected === $this->executeAssertionOnElements($assertion, $elements)),
+                               'Assertion #' . $index . ' failed'
+                       );
+               }
+       }
+
+       /**
+        * Gets log entries from the sys_log
+        *
+        * @return array
+        */
+       protected function getLogEntries() {
+               return $this->getDatabase()->exec_SELECTgetRows('*', 'sys_log', 'error IN (1,2)');
+       }
+
+       /**
+        * @param  array $assertion
+        * @param  array $elements
+        * @return boolean
+        */
+       protected function executeAssertionOnElements(array $assertion, array $elements) {
+               if (!empty($assertion['tableName'])) {
+                       $tableName = $assertion['tableName'];
+                       unset($assertion['tableName']);
+                       $elements = (array) $elements[$tableName];
+               }
+
+               foreach ($elements as $element) {
+                       $result = FALSE;
+
+                       foreach ($assertion as $field => $value) {
+                               if ($element[$field] == $value) {
+                                       $result = TRUE;
+                               } else {
+                                       $result = FALSE;
+                                       break;
+                               }
+                       }
+
+                       if ($result === TRUE) {
+                               return TRUE;
+                       }
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * @param mixed $element
+        * @return string
+        */
+       protected function elementToString($element) {
+               $result = preg_replace(
+                       '#\n+#',
+                       ' ',
+                       var_export($element, TRUE)
+               );
+
+               return $result;
+       }
+
+       /**
+        * @return string
+        */
+       protected function combine() {
+               return implode(':', func_get_args());
+       }
+
+       /**
+        * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+        */
+       protected function getBackendUser() {
+               return $GLOBALS['BE_USER'];
+       }
+}
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/MToNMMAsymmetric.xml b/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/MToNMMAsymmetric.xml
new file mode 100644 (file)
index 0000000..9c5655f
--- /dev/null
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<dataset>
+       <!-- Tabelle tx_irretutorial_mnmmasym_hotel -->
+       <tx_irretutorial_mnmmasym_hotel>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Rosengarten Hotels Appartment</title>
+               <offers>2</offers>
+       </tx_irretutorial_mnmmasym_hotel>
+       <!-- Tabelle tx_irretutorial_mnmmasym_hotel_offer_rel -->
+       <tx_irretutorial_mnmmasym_hotel_offer_rel>
+               <uid>1</uid>
+               <uid_local>1</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <tablenames></tablenames>
+               <sorting>1</sorting>
+               <sorting_foreign>0</sorting_foreign>
+               <ident></ident>
+       </tx_irretutorial_mnmmasym_hotel_offer_rel>
+       <tx_irretutorial_mnmmasym_hotel_offer_rel>
+               <uid>2</uid>
+               <uid_local>1</uid_local>
+               <uid_foreign>2</uid_foreign>
+               <tablenames></tablenames>
+               <sorting>2</sorting>
+               <sorting_foreign>0</sorting_foreign>
+               <ident></ident>
+       </tx_irretutorial_mnmmasym_hotel_offer_rel>
+       <!-- Tabelle tx_irretutorial_mnmmasym_offer -->
+       <tx_irretutorial_mnmmasym_offer>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Wellness &amp; Beauty Week</title>
+               <hotels>0</hotels>
+               <prices>1</prices>
+       </tx_irretutorial_mnmmasym_offer>
+       <tx_irretutorial_mnmmasym_offer>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>128</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>&quot;Experience it&quot; Week</title>
+               <hotels>0</hotels>
+               <prices>2</prices>
+       </tx_irretutorial_mnmmasym_offer>
+       <!-- Tabelle tx_irretutorial_mnmmasym_offer_price_rel -->
+       <tx_irretutorial_mnmmasym_offer_price_rel>
+               <uid>1</uid>
+               <uid_local>2</uid_local>
+               <uid_foreign>2</uid_foreign>
+               <tablenames></tablenames>
+               <sorting>1</sorting>
+               <sorting_foreign>0</sorting_foreign>
+               <ident></ident>
+       </tx_irretutorial_mnmmasym_offer_price_rel>
+       <tx_irretutorial_mnmmasym_offer_price_rel>
+               <uid>2</uid>
+               <uid_local>2</uid_local>
+               <uid_foreign>3</uid_foreign>
+               <tablenames></tablenames>
+               <sorting>2</sorting>
+               <sorting_foreign>0</sorting_foreign>
+               <ident></ident>
+       </tx_irretutorial_mnmmasym_offer_price_rel>
+       <tx_irretutorial_mnmmasym_offer_price_rel>
+               <uid>3</uid>
+               <uid_local>1</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <tablenames></tablenames>
+               <sorting>1</sorting>
+               <sorting_foreign>0</sorting_foreign>
+               <ident></ident>
+       </tx_irretutorial_mnmmasym_offer_price_rel>
+       <!-- Tabelle tx_irretutorial_mnmmasym_price -->
+       <tx_irretutorial_mnmmasym_price>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Season from January-December</title>
+               <price>400.00</price>
+               <offers>0</offers>
+       </tx_irretutorial_mnmmasym_price>
+       <tx_irretutorial_mnmmasym_price>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>128</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Season from January-June</title>
+               <price>300.00</price>
+               <offers>0</offers>
+       </tx_irretutorial_mnmmasym_price>
+       <tx_irretutorial_mnmmasym_price>
+               <uid>3</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>64</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Season from June-December</title>
+               <price>500.00</price>
+               <offers>0</offers>
+       </tx_irretutorial_mnmmasym_price>
+</dataset>
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMAsymmetricLocalizationKeepTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMAsymmetricLocalizationKeepTest.php
new file mode 100644 (file)
index 0000000..d54c36d
--- /dev/null
@@ -0,0 +1,157 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Oliver Hader <oliver@typo3.org>
+*  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!
+***************************************************************/
+
+require_once(dirname(__FILE__). '/AbstractLocalizationTestCase.php');
+
+/**
+ * Test case for m:n MM localizations using localizationMode 'keep'.
+ *
+ */
+class MtoNMMAsymmetricLocalizationKeepTest extends AbstractLocalizationTestCase {
+
+       /**
+        * Sets up this test case.
+        *
+        * @return void
+        */
+       public function setUp() {
+               parent::setUp();
+
+               // Set the localizazionMode to 'select' for all IRRE fields:
+               foreach ($this->structure as $tableName => $fields) {
+                       foreach ($fields as $fieldName) {
+                               $this->setTcaFieldConfigurationBehaviour(
+                                       $tableName, $fieldName,
+                                       self::BEHAVIOUR_LocalizationMode,
+                                       self::VALUE_LocalizationMode_Keep
+                               );
+                       }
+               }
+
+               $this->importDataSet(dirname(__FILE__) . '/Fixtures/MToNMMAsymmetric.xml');
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function isOnlyParentLocalized() {
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $localizedHotelId = $this->getLocalizationId(self::TABLE_Hotel, 1);
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                       )
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Offer => '1,2',
+                       ),
+                       self::VALUE_LanguageId,
+                       FALSE
+               );
+
+               $this->assertChildren(
+                       self::TABLE_Hotel, $localizedHotelId, self::FIELD_Hotel_Offers,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'uid' => '1',
+                               ),
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'uid' => '2',
+                               ),
+                       ),
+                       self::TABLE_Relation_Hotel_Offer
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areNoChildElementsLocalizedWithParent() {
+               $this->setTcaFieldConfigurationBehaviour(
+                       self::TABLE_Hotel,
+                       self::FIELD_Hotel_Offers,
+                       self::BEHAVIOUR_LocalizeChildrenAtParentLocalization,
+                       TRUE
+               );
+
+               $this->setTcaFieldConfigurationBehaviour(
+                       self::TABLE_Offer,
+                       self::FIELD_Offer_Prices,
+                       self::BEHAVIOUR_LocalizeChildrenAtParentLocalization,
+                       TRUE
+               );
+
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $localizedHotelId = $this->getLocalizationId(self::TABLE_Hotel, 1);
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                       )
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Offer => '1,2',
+                               self::TABLE_Price => '1,2,3',
+                       ),
+                       self::VALUE_LanguageId,
+                       FALSE
+               );
+
+               $this->assertChildren(
+                       self::TABLE_Hotel, $localizedHotelId, self::FIELD_Hotel_Offers,
+                       array(
+                                array(
+                                        'tableName' => self::TABLE_Offer,
+                                        'uid' => '1',
+                                ),
+                                array(
+                                        'tableName' => self::TABLE_Offer,
+                                        'uid' => '2',
+                                ),
+                       ),
+                       self::TABLE_Relation_Hotel_Offer
+               );
+       }
+}
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMAsymmetricLocalizationSelectTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMAsymmetricLocalizationSelectTest.php
new file mode 100644 (file)
index 0000000..e492cb5
--- /dev/null
@@ -0,0 +1,322 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Oliver Hader <oliver@typo3.org>
+*  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!
+***************************************************************/
+
+require_once(dirname(__FILE__). '/AbstractLocalizationTestCase.php');
+
+/**
+ * Testcase for m:n MM localizations using localizationMode 'select'.
+ *
+ */
+class MtoNMMAsymetricLocalizationSelectTest extends AbstractLocalizationTestCase {
+
+       /**
+        * Sets up this test case.
+        *
+        * @return void
+        */
+       public function setUp() {
+               parent::setUp();
+
+               // Set the localizazionMode to 'select' for all IRRE fields:
+               foreach ($this->structure as $tableName => $fields) {
+                       foreach ($fields as $fieldName) {
+                               $this->setTcaFieldConfigurationBehaviour(
+                                       $tableName, $fieldName,
+                                       self::BEHAVIOUR_LocalizationMode,
+                                       self::VALUE_LocalizationMode_Select
+                               );
+                       }
+               }
+
+               $this->importDataSet(dirname(__FILE__) . '/Fixtures/MToNMMAsymmetric.xml');
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function isOnlyParentLocalized() {
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $localizedHotelId = $this->getLocalizationId(self::TABLE_Hotel, 1);
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                       )
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Offer => '1,2',
+                       ),
+                       self::VALUE_LanguageId,
+                       FALSE
+               );
+
+               $this->assertChildren(
+                       self::TABLE_Hotel, $localizedHotelId, self::FIELD_Hotel_Offers,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'uid' => '1',
+                               ),
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'uid' => '2',
+                               ),
+                       ),
+                       self::TABLE_Relation_Hotel_Offer,
+                       FALSE
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areChildElementsLocalized() {
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $localizedHotelId = $this->getLocalizationId(self::TABLE_Hotel, 1);
+
+               $this->simulateCommand(
+                       self::COMMAND_LocalizeSynchronize,
+                       self::FIELD_Hotel_Offers . ',' . self::COMMAND_LocalizeSynchronize_Localize,
+                       array(self::TABLE_Hotel => $localizedHotelId)
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                               self::TABLE_Offer => '1,2',
+                       )
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Price => '1,2,3',
+                       ),
+                       self::VALUE_LanguageId,
+                       FALSE
+               );
+
+               $this->assertChildren(
+                       self::TABLE_Hotel, $localizedHotelId, self::FIELD_Hotel_Offers,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '1',
+                               ),
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '2',
+                               ),
+                       ),
+                       self::TABLE_Relation_Hotel_Offer
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areChildElementsLocalizedWithParent() {
+               $this->setTcaFieldConfigurationBehaviour(
+                       self::TABLE_Offer,
+                       self::FIELD_Offer_Prices,
+                       self::BEHAVIOUR_LocalizeChildrenAtParentLocalization,
+                       TRUE
+               );
+
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $localizedHotelId = $this->getLocalizationId(self::TABLE_Hotel, 1);
+
+               $this->simulateCommand(
+                       self::COMMAND_LocalizeSynchronize,
+                       self::FIELD_Hotel_Offers . ',' . self::COMMAND_LocalizeSynchronize_Localize,
+                       array(self::TABLE_Hotel => $localizedHotelId)
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                               self::TABLE_Offer => '1,2',
+                               self::TABLE_Price => '1,2,3',
+                       )
+               );
+
+               /* Offers */
+               $this->assertChildren(
+                       self::TABLE_Hotel, $localizedHotelId, self::FIELD_Hotel_Offers,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '1',
+                               ),
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '2',
+                               ),
+                       ),
+                       self::TABLE_Relation_Hotel_Offer
+               );
+
+               /* Prices */
+               $this->assertChildren(
+                       self::TABLE_Offer, $this->getLocalizationId(self::TABLE_Offer, 1), self::FIELD_Offer_Prices,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Price,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '1',
+                               ),
+                       ),
+                       self::TABLE_Relation_Offer_Price
+               );
+
+               $this->assertChildren(
+                       self::TABLE_Offer, $this->getLocalizationId(self::TABLE_Offer, 2), self::FIELD_Offer_Prices,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Price,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '2',
+                               ),
+                               array(
+                                       'tableName' => self::TABLE_Price,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '3',
+                               ),
+                       ),
+                       self::TABLE_Relation_Offer_Price
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areDirectChildElementsLocalizedWithParent() {
+               $this->setTcaFieldConfigurationBehaviour(
+                       self::TABLE_Hotel,
+                       self::FIELD_Hotel_Offers,
+                       self::BEHAVIOUR_LocalizeChildrenAtParentLocalization,
+                       TRUE
+               );
+
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $localizedHotelId = $this->getLocalizationId(self::TABLE_Hotel, 1);
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                               self::TABLE_Offer => '1,2',
+                       )
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Price => '1,2,3',
+                       ),
+                       self::VALUE_LanguageId,
+                       FALSE
+               );
+
+               $this->assertChildren(
+                       self::TABLE_Hotel, $localizedHotelId, self::FIELD_Hotel_Offers,
+                       array(
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '1',
+                               ),
+                               array(
+                                       'tableName' => self::TABLE_Offer,
+                                       'sys_language_uid' => self::VALUE_LanguageId,
+                                       'l18n_parent' => '2',
+                               ),
+                       ),
+                       self::TABLE_Relation_Hotel_Offer
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areAllChildElementsLocalizedWithParent() {
+               $this->setTcaFieldConfigurationBehaviour(
+                       self::TABLE_Hotel,
+                       self::FIELD_Hotel_Offers,
+                       self::BEHAVIOUR_LocalizeChildrenAtParentLocalization,
+                       TRUE
+               );
+
+               $this->setTcaFieldConfigurationBehaviour(
+                       self::TABLE_Offer,
+                       self::FIELD_Offer_Prices,
+                       self::BEHAVIOUR_LocalizeChildrenAtParentLocalization,
+                       TRUE
+               );
+
+               $this->simulateCommand(
+                       self::COMMAND_Localize,
+                       self::VALUE_LanguageId,
+                       array(self::TABLE_Hotel => '1')
+               );
+
+               $this->assertLocalizations(
+                       array(
+                               self::TABLE_Hotel => '1',
+                               self::TABLE_Offer => '1,2',
+                               self::TABLE_Price => '1,2,3',
+                       )
+               );
+       }
+}
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ChangeLog b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ChangeLog
new file mode 100644 (file)
index 0000000..128999e
--- /dev/null
@@ -0,0 +1,253 @@
+2013-08-17  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] Modify abstract setUp() to be compatible with TYPO3 6.1
+       * [TASK] Add test-cases for m:n relations stored in MM tables in a workspace
+
+2013-08-15  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] Use backend module dispatcher
+       * [TASK] Use include_once() instead of require_once() for 6.2 compatibility
+
+2013-03-03  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] #29278: Extend test-case for 1n:FF copy localized new structure on workspaces
+
+2013-02-05  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] #29278: Extend test-case for 1n:FF copy actions on workspaces
+       * [BUGFIX] Fix unit-test assertions (array_*_key vs. array_*_assoc)
+       * [TASK] #29278: Extend test-case for copying 1n:CSV & 1n:FF to different page on workspaces
+
+2013-02-04  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] #45132 & #45133: Extend test-case concerning placeholder translation values in workspaces
+       * [TASK] #29278 & #45132 & #45133: Extend test-cases concerning sys_refindex
+       * [TASK] Disable shadowColumnsForNewPlaceholders in favour of #29278 which solves it implicitly in the Core
+       * [TASK] #45151: Extend test-case for 1n:CSV copy actions on workspaces
+
+2013-01-31  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] Trigger localization of children on parent localization
+       * [TASK] #29278: Extend test-case concerning copying and localization of new workspace records
+       * [TASK] Remove checks for TYPO3 versions prior to 4.5.0
+       * [TASK] #29278: Extend test-case concerning placeholder values in workspaces
+
+2012-11-05  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] Added FlexForm for IRRE to tt_content records
+       * [TASK] Utilize foreign_match_fields to distinguish references
+
+2012-10-12  Oliver Hader  <oliver@typo3.org>
+
+       * [TASK] Added localization in pages_language_overlay of 1nff record
+
+2012-03-12  Oliver Hader  <oliver@typo3.org>
+
+       * Fixed bug: Regular non-workspace tests might be executed on a workspace
+
+2012-03-10  Oliver Hader  <oliver@typo3.org>
+
+       * Cleanup: Changed variables, methods, CGL and install repsonse
+       * Release of version 0.4.0
+
+2012-03-06  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Clean-up test cases
+       * Tests: Added test cases for publishing records deleted in workspace
+
+2011-08-12  Oliver Hader  <oliver@typo3.org>
+
+       * Fixed bug: Extensions with hooks in t3lib_TCEmain are not considered to be loaded
+       * Fixed bug: Behaviour in TYPO3 4.6 concerning caches has changed and needs special handling
+
+2011-06-20  Oliver Hader  <oliver@typo3.org>
+
+       * Fixed bug: Typing error in install process
+       * Tests: Modified test cases to clear TSconfig settings options.workspaces
+
+2011-06-14  Oliver Hader  <oliver@typo3.org>
+
+       * Fixed bug: Calls to deprecated and removed functions
+
+2011-04-05  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Separated m:n MM localization tests for localizationModes 'keep' and 'select'
+
+2011-03-30  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Refactored abstract test clases
+       * Fixed bug: TCA of m:n MM tables does not use MM relations with uid
+       * Tests: Extended m:n MM localization tests
+
+2011-03-23  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Added m:n MM localization tests
+       * Tests: Extended m:n MM localization tests
+
+2011-03-22  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Refactoring of structure
+
+2011-03-18  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Added 1:n CSV tests for removing of child records in workspaces
+       * Cleanup: Fixed whitespaces in fixtures
+       * Tests: Extended 1:n CSV and 1:n FF tests for removing child records in workspaces and flushing dependent elements in the workspace module
+
+2011-03-17  Oliver Hader  <oliver@typo3.org>
+
+       * Fixed bug: Workspaces extension must be loaded if using TYPO3 4.5.0+
+       * Tests: Added 1:n FF tests for removing of child records in workspaces
+
+2011-02-09  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Renamed abstract test class to not be considered as testsuite by PHPUnit
+       * Tests: Added skip calls to unsupported test cases that rely on TYPO3 4.5.0
+
+2011-01-21  Oliver Hader  <oliver@typo3.org>
+
+       * Added tabs for forms view for all parent and child tables
+
+2011-01-01  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Fixed 1:n FF test case since checking on a placeholder for an existing record does not make sense
+
+2010-12-31  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Extended 1:n FF tests concerning sorting order of placeholder records
+
+2010-12-26  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Extended 1:n FF tests concerning sorting order of placeholder records
+
+2010-12-23  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Extended 1:n FF tests concerning child records on pages
+
+2010-11-17  Oliver Hader  <oliver@typo3.org>
+
+       * Release of version 0.3.2
+
+2010-11-13  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Fixed tests to be working with TYPO3 4.5 and also versions before
+
+2010-11-13  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Fixed data set of table tx_irretutorial_1nff_price
+       * Tests: Extended unit tests for 1:n CSV and 1:n FF
+       * Updated sample data to import at ./irre_tutorial/res/T3D__IRRE.t3d
+       * Release of version 0.3.1
+
+2010-11-05  Oliver Hader  <oliver@typo3.org>
+
+       * Fixed bug: Inline field for pages table is not available for all doktypes
+
+2010-11-04  Oliver Hader  <oliver@typo3.org>
+
+       * Added parenttable field for prices in 1:n FF context
+
+2010-10-29  Oliver Hader  <oliver@typo3.org>
+
+       * Tests: Fixed labels of error messages to be checked
+
+2010-10-28  Oliver Hader  <oliver@typo3.org>
+
+       * Changed blob fields of 1:n CSV relations to text
+       * Updated README.txt contents
+       * Tests: Extended unit tests for 1:n FF
+       * Tests: Extended unit tests for 1:n CSV
+
+2010-10-27  Oliver Hader  <oliver@typo3.org>
+
+       * Added TCA definition to copy foreign_field and foreign_table_field values to workspace placeholder records
+
+2010-10-20  Oliver Hader  <oliver@typo3.org>
+
+       * Added use case to use 1:n relationships as part of a pages record
+       * Updated sample data to import at ./irre_tutorial/res/T3D__IRRE.t3d
+
+2010-10-10  Oliver Hader  <oliver@typo3.org>
+
+       * Added basic skeleton for unit tests
+       * Tests: Extended unit tests for 1:n FF
+
+2010-08-06  Oliver Hader  <oliver@typo3.org>
+
+       * Added workspaces and versioning field definitions
+       * Raised version number to 0.3.0
+
+2010-02-27  Oliver Hader  <oliver@typo3.org>
+
+       * Release of version 0.2.0
+
+2010-02-27  Oliver Hader  <oliver@typo3.org>
+
+       * Cleanup: Removed whitespaces at end of line
+       * Added definitions for m:n asymmetric structure that uses a regular MM intermediate table with uid_local and uid_foreign
+       * Added configuration for bidirection MM disposals
+       * Updated pre-defined content structure of relational data
+
+2008-02-03  Oliver Hader  <oh@inpublica.de>
+
+       * Changed tca.*.php files to use the new 'behaviour' array in TCA of fields of type 'inline'
+
+2008-01-28  Oliver Hader  <oh@inpublica.de>
+
+       * Added l10n_mode=prefixLangTitle and used new TCA property on select fields
+
+2008-01-27  Oliver Hader  <oh@inpublica.de>
+
+       * Fixed and configured missing required fields (sys_language_uid, l18n_parent, l18n_diffsource) for localization in ext_tables.sql, ext_tables.*.php and tca.*.php
+       * Added localizationMode in $TCA configuration of IRRE parent fields and sample appearance configuration
+
+2008-01-20  Oliver Hader  <oh@inpublica.de>
+
+       * Fixed bug in header of ext_tables.*.php files ("<?" -> "<?php">)
+
+2008-01-04  Oliver Hader  <oh@inpublica.de>
+
+       * Added and configured required fields (sys_language_uid, l18n_parent, l18n_diffsource) for localization in ext_tables.sql, ext_tables.*.php and tca.*.php
+       ! Localizazion is currently still unsupported in TYPO3 4.1.5 and TYPO3 4.2.0-alpha2 - this change is for testing upcoming patches concerning IRRE & localization
+
+2007-03-07  Oliver Hader  <oh@inpublica.de>
+
+       * Updated code blocks in documentation to be correctly rendered on typo3.org
+
+2007-02-20  Oliver Hader  <oh@inpublica.de>
+
+       * Updated documentation to be correctly rendered on typo3.org
+
+2007-02-19  Oliver Hader  <oh@inpublica.de>
+
+       * Integrated first version of documentation
+       * Updated sample data to import at ./irre_tutorial/res/T3D__IRRE.t3d
+
+2007-02-05  Oliver Hader  <oh@inpublica.de>
+
+       * Renamed "anti-symmetric" to "asymmetric"
+       * Created new page "m:n asymmetric selector"
+       * Updated sample data to import at ./irre_tutorial/res/T3D__IRRE.t3d
+
+2007-01-31  Oliver Hader  <oh@inpublica.de>
+
+       * Changed data structure for mnasym part -> prices are integrated as attribute on hotel<->offer intermediate table
+       * Removed table tx_irretutorial_mnasym_offer_price_rel - not required anymore
+       * Implemented new TSconfig.<table>.<field>.config{ ... } feature (available with 4.1rc1)
+
+2007-01-30  Oliver Hader  <oh@inpublica.de>
+
+       * Integrated backend module in Web-Module to import IRRE Tutorial Sample Data
+               - implemented installer
+               - implemented uninstaller
+       * Created data structures and integrated T3D export file
+       * Changed README.txt
+
+2007-01-29  Oliver Hader  <oh@inpublica.de>
+
+       * Changed table icons and labels
+       * Removed typing errors from ext_tables.*.php
+
+2007-01-28  Oliver Hader  <oh@inpublica.de>
+
+       * Initial release (currently not finished and not working)
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.1ncsv.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.1ncsv.php
new file mode 100644 (file)
index 0000000..4fb7166
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_1ncsv_hotel');
+
+$TCA['tx_irretutorial_1ncsv_hotel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_1ncsv_hotel',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.1ncsv.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, offers',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_1ncsv_offer');
+
+$TCA['tx_irretutorial_1ncsv_offer'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_1ncsv_offer',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.1ncsv.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_offer.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, prices',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_1ncsv_price');
+
+$TCA['tx_irretutorial_1ncsv_price'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_1ncsv_price',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.1ncsv.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_price.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, price',
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.1nff.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.1nff.php
new file mode 100644 (file)
index 0000000..572e3a1
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_1nff_hotel');
+
+$TCA['tx_irretutorial_1nff_hotel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_1nff_hotel',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.1nff.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'parentid,parenttable',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, offers',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_1nff_offer');
+
+$TCA['tx_irretutorial_1nff_offer'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_1nff_offer',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.1nff.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_offer.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'parentid,parenttable',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, parentid, parenttable, title, prices',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_1nff_price');
+
+$TCA['tx_irretutorial_1nff_price'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_1nff_price',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.1nff.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_price.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'parentid,parenttable',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, parentid, title, price',
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.general.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.general.php
new file mode 100644 (file)
index 0000000..c36c791
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+if (!defined('TYPO3_MODE')) {
+       die ('Access denied.');
+}
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
+       'pages',
+        array(
+               'tx_irretutorial_hotels' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:pages.tx_irretutorial_hotels',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_1nff_hotel',
+                               'foreign_field' => 'parentid',
+                               'foreign_table_field' => 'parenttable',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       1
+);
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
+       'pages',
+       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:pages.doktype.div.irre, tx_irretutorial_hotels;;;;1-1-1'
+);
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
+       'pages_language_overlay',
+        array(
+               'tx_irretutorial_hotels' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:pages.tx_irretutorial_hotels',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_1nff_hotel',
+                               'foreign_field' => 'parentid',
+                               'foreign_table_field' => 'parenttable',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       1
+);
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
+       'pages_language_overlay',
+       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:pages.doktype.div.irre, tx_irretutorial_hotels;;;;1-1-1'
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
+       'tt_content',
+        array(
+               'tx_irretutorial_flexform' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tt_content.tx_irretutorial_flexform',
+                       'config' => array(
+                               'type' => 'flex',
+                               'ds' => array(
+                                       'default' => 'FILE:EXT:irre_tutorial/Configuration/FlexForms/tt_content_flexform.xml',
+                               ),
+                       )
+               ),
+       ),
+       1
+);
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
+       'tt_content',
+       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tt_content.div.irre, tx_irretutorial_flexform;;;;1-1-1'
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnasym.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnasym.php
new file mode 100644 (file)
index 0000000..8216cce
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnasym_hotel');
+
+$TCA['tx_irretutorial_mnasym_hotel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnasym_hotel',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, offers',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnasym_hotel_offer_rel');
+
+$TCA['tx_irretutorial_mnasym_hotel_offer_rel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnasym_hotel_offer_rel',
+               'label' => 'uid',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel_offer_rel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'hotelid,offerid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, hotelid, offerid, prices, hotelsort, offersort',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnasym_offer');
+
+$TCA['tx_irretutorial_mnasym_offer'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnasym_offer',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_offer.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, hotels',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnasym_price');
+
+$TCA['tx_irretutorial_mnasym_price'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnasym_price',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_price.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'parentid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'hidden, title, parentid, price',
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnattr.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnattr.php
new file mode 100644 (file)
index 0000000..f164177
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnattr_hotel');
+
+$TCA['tx_irretutorial_mnattr_hotel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnattr_hotel',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnattr.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, offers',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnattr_hotel_offer_rel');
+
+$TCA['tx_irretutorial_mnattr_hotel_offer_rel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnattr_hotel_offer_rel',
+               'label' => 'uid',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnattr.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel_offer_rel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'hotelid,offerid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, hotelid, offerid, quality, allincl',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnattr_offer');
+
+$TCA['tx_irretutorial_mnattr_offer'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnattr_offer',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnattr.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_offer.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, hotels',
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnmmasym.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnmmasym.php
new file mode 100644 (file)
index 0000000..a3bbba7
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnmmasym_hotel');
+
+$TCA['tx_irretutorial_mnmmasym_hotel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnmmasym_hotel',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnmmasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, offers',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnmmasym_offer');
+
+$TCA['tx_irretutorial_mnmmasym_offer'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnmmasym_offer',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnmmasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_offer.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, hotels, prices',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnmmasym_price');
+
+$TCA['tx_irretutorial_mnmmasym_price'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_mnmmasym_price',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnmmasym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_price.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'hidden, title, price, offers',
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnsym.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/ExtTables/ext_tables.mnsym.php
new file mode 100644 (file)
index 0000000..7db9cf3
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnsym_hotel');
+
+$TCA['tx_irretutorial_mnsym_hotel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_mnsym_hotel',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'sortby' => 'sorting',
+               'delete' => 'deleted',  
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnsym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, branches',
+       )
+);
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_irretutorial_mnsym_hotel_rel');
+
+$TCA['tx_irretutorial_mnsym_hotel_rel'] = array(
+       'ctrl' => array(
+               'title' => 'LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_mnsym_hotel_rel',
+               'label' => 'uid',       
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'cruser_id' => 'cruser_id',
+               'languageField'            => 'sys_language_uid',
+               'transOrigPointerField'    => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden',
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY).'Configuration/Tca/tca.mnsym.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY).'Resources/Public/Icons/icon_tx_irretutorial_hotel_rel.gif',
+               'versioningWS' => TRUE,
+               'origUid' => 't3_origuid',
+               // @see http://forge.typo3.org/issues/29278 which solves it implicitly in the Core
+               // 'shadowColumnsForNewPlaceholders' => 'hotelid',
+               'dividers2tabs' => TRUE,
+       ),
+       'feInterface' => array(
+               'fe_admin_fieldList' => 'sys_language_uid, l18n_parent, l18n_diffsource, hidden, hotelid, branchid',
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/FlexForms/tt_content_flexform.xml b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/FlexForms/tt_content_flexform.xml
new file mode 100644 (file)
index 0000000..c3c93da
--- /dev/null
@@ -0,0 +1,34 @@
+<T3DataStructure>
+       <meta>
+               <langDisable>1</langDisable>
+       </meta>
+       <ROOT>
+               <type>array</type>
+               <el>
+                       <hotels>
+                               <TCEforms>
+                                       <label>LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tt_content.tx_irretutorial_flexform.hotels</label>
+                                       <config>
+                                               <type>inline</type>
+                                               <foreign_table>tx_irretutorial_1nff_hotel</foreign_table>
+                                               <foreign_field>parentid</foreign_field>
+                                               <foreign_table_field>parenttable</foreign_table_field>
+                                               <foreign_match_fields type="array">
+                                                       <parentidentifier>flexform.hotels</parentidentifier>
+                                               </foreign_match_fields>
+                                               <maxitems>10</maxitems>
+                                               <appearance type="array">
+                                                       <showSynchronizationLink>1</showSynchronizationLink>
+                                                       <showAllLocalizationLink>1</showAllLocalizationLink>
+                                                       <showPossibleLocalizationRecords>1</showPossibleLocalizationRecords>
+                                                       <showRemovedLocalizationRecords>1</showRemovedLocalizationRecords>
+                                               </appearance>
+                                               <behaviour type="array">
+                                                       <localizationMode>select</localizationMode>
+                                               </behaviour>
+                                       </config>
+                               </TCEforms>
+                       </hotels>
+               </el>
+       </ROOT>
+</T3DataStructure>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.1ncsv.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.1ncsv.php
new file mode 100644 (file)
index 0000000..3126106
--- /dev/null
@@ -0,0 +1,258 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die('Access denied.');
+}
+
+$TCA['tx_irretutorial_1ncsv_hotel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_1ncsv_hotel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,offers'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_1ncsv_hotel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_1ncsv_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_1ncsv_hotel.pid=###CURRENT_PID### AND tx_irretutorial_1ncsv_hotel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'offers' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.offers',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_1ncsv_offer',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, offers;;;;3-3-3, ' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_1ncsv_offer'] = array(
+       'ctrl' => $TCA['tx_irretutorial_1ncsv_offer']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,prices'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_1ncsv_offer']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_1ncsv_offer',
+                               'foreign_table_where' => 'AND tx_irretutorial_1ncsv_offer.pid=###CURRENT_PID### AND tx_irretutorial_1ncsv_offer.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'prices' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.prices',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_1ncsv_price',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, prices;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_1ncsv_price'] = array(
+       'ctrl' => $TCA['tx_irretutorial_1ncsv_price']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,price'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_1ncsv_price']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_1ncsv_price',
+                               'foreign_table_where' => 'AND tx_irretutorial_1ncsv_price.pid=###CURRENT_PID### AND tx_irretutorial_1ncsv_price.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'price' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.price',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'double2',
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, price;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, '
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.1nff.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.1nff.php
new file mode 100644 (file)
index 0000000..9452828
--- /dev/null
@@ -0,0 +1,294 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die('Access denied.');
+}
+
+$TCA['tx_irretutorial_1nff_hotel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_1nff_hotel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,offers'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_1nff_hotel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_1nff_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_1nff_hotel.pid=###CURRENT_PID### AND tx_irretutorial_1nff_hotel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'parentid' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'parenttable' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'offers' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.offers',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_1nff_offer',
+                               'foreign_field' => 'parentid',
+                               'foreign_table_field' => 'parenttable',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                                       'localizeChildrenAtParentLocalization' => TRUE,
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, offers;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_1nff_offer'] = array(
+       'ctrl' => $TCA['tx_irretutorial_1nff_offer']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,parentid,parenttable,title,prices'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_1nff_offer']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_1nff_offer',
+                               'foreign_table_where' => 'AND tx_irretutorial_1nff_offer.pid=###CURRENT_PID### AND tx_irretutorial_1nff_offer.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'parentid' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'parenttable' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'prices' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.prices',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_1nff_price',
+                               'foreign_field' => 'parentid',
+                               'foreign_table_field' => 'parenttable',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                                       'localizeChildrenAtParentLocalization' => TRUE,
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, prices;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, parentid, parenttable'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_1nff_price'] = array(
+       'ctrl' => $TCA['tx_irretutorial_1nff_price']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,parentid,title,price'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_1nff_price']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_1nff_price',
+                               'foreign_table_where' => 'AND tx_irretutorial_1nff_price.pid=###CURRENT_PID### AND tx_irretutorial_1nff_price.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'parentid' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'parenttable' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'price' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.price',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'double2',
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, price;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, parentid'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnasym.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnasym.php
new file mode 100644 (file)
index 0000000..94af093
--- /dev/null
@@ -0,0 +1,377 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die('Access denied.');
+}
+
+$TCA['tx_irretutorial_mnasym_hotel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnasym_hotel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,offers'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnasym_hotel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnasym_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnasym_hotel.pid=###CURRENT_PID### AND tx_irretutorial_mnasym_hotel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'offers' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.offers',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnasym_hotel_offer_rel',
+                               'foreign_field' => 'hotelid',
+                               'foreign_sortby' => 'hotelsort',
+                               'foreign_label' => 'offerid',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, offers;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnasym_hotel_offer_rel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnasym_hotel_offer_rel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,hotelid,offerid,prices,hotelsort,offersort'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnasym_hotel_offer_rel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnasym_hotel_offer_rel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnasym_hotel_offer_rel.pid=###CURRENT_PID### AND tx_irretutorial_mnasym_hotel_offer_rel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'hotelid' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.hotelid',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_irretutorial_mnasym_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnasym_hotel.pid=###CURRENT_PID### AND tx_irretutorial_mnasym_hotel.sys_language_uid="###REC_FIELD_sys_language_uid###"',
+                               'maxitems' => 1,
+                               'localizeReferences' => 1,
+                       )
+               ),
+               'offerid' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.offerid',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_irretutorial_mnasym_offer',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnasym_offer.pid=###CURRENT_PID### AND tx_irretutorial_mnasym_offer.sys_language_uid="###REC_FIELD_sys_language_uid###"',
+                               'maxitems' => 1,
+                               'localizeReferences' => 1,
+                       )
+               ),
+               'prices' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.prices',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnasym_price',
+                               'foreign_field' => 'parentid',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+               'hotelsort' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'offersort' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, hotelid;;;;3-3-3, offerid, prices,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, hotelsort, offersort'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnasym_offer'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnasym_offer']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,hotels'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnasym_offer']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnasym_offer',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnasym_offer.pid=###CURRENT_PID### AND tx_irretutorial_mnasym_offer.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'hotels' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.hotels',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnasym_hotel_offer_rel',
+                               'foreign_field' => 'offerid',
+                               'foreign_sortby' => 'offersort',
+                               'foreign_label' => 'hotelid',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, hotels,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnasym_price'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnasym_price']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,parentid,price'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnasym_price']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnasym_price',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnasym_price.pid=###CURRENT_PID### AND tx_irretutorial_mnasym_price.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'parentid' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'price' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.price',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'double2',
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, parentid, price;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, parentid'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnattr.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnattr.php
new file mode 100644 (file)
index 0000000..2ec2259
--- /dev/null
@@ -0,0 +1,294 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die('Access denied.');
+}
+
+$TCA['tx_irretutorial_mnattr_hotel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnattr_hotel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,offers'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnattr_hotel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnattr_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnattr_hotel.pid=###CURRENT_PID### AND tx_irretutorial_mnattr_hotel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'offers' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.offers',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnattr_hotel_offer_rel',
+                               'foreign_field' => 'hotelid',
+                               'foreign_sortby' => 'hotelsort',
+                               'foreign_label' => 'offerid',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, offers;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnattr_hotel_offer_rel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnattr_hotel_offer_rel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,hotelid,offerid,hotelsort,offersort,quality,allincl'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnattr_hotel_offer_rel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnattr_hotel_offer_rel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnattr_hotel_offer_rel.pid=###CURRENT_PID### AND tx_irretutorial_mnattr_hotel_offer_rel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'hotelid' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.hotelid',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_irretutorial_mnattr_hotel',
+                               'maxitems' => 1,
+                               'localizeReferences' => 1,
+                       )
+               ),
+               'offerid' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.offerid',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_irretutorial_mnattr_offer',
+                               'maxitems' => 1,
+                               'localizeReferences' => 1,
+                       )
+               ),
+               'hotelsort' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'offersort' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'quality' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.quality',
+                       'config' => array(
+                               'type' => 'select',
+                               'items' => array(
+                                       Array('LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.quality.I.0', '1'),
+                                       Array('LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.quality.I.1', '2'),
+                                       Array('LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.quality.I.2', '3'),
+                                       Array('LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.quality.I.3', '4'),
+                                       Array('LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.quality.I.4', '5'),
+                               ),
+                       )
+               ),
+               'allincl' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_offer_rel.allincl',
+                       'config' => array(
+                               'type' => 'check',
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, hotelid;;;;3-3-3, offerid, hotelsort, offersort, quality, allincl,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnattr_offer'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnattr_offer']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,hotels'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnattr_offer']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnattr_offer',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnattr_offer.pid=###CURRENT_PID### AND tx_irretutorial_mnattr_offer.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'hotels' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.hotels',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnattr_hotel_offer_rel',
+                               'foreign_field' => 'offerid',
+                               'foreign_sortby' => 'offersort',
+                               'foreign_label' => 'hotelid',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, hotels,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnmmasym.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnmmasym.php
new file mode 100644 (file)
index 0000000..f0298d2
--- /dev/null
@@ -0,0 +1,304 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die('Access denied.');
+}
+
+$TCA['tx_irretutorial_mnmmasym_hotel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnmmasym_hotel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,offers'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnmmasym_hotel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnmmasym_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnmmasym_hotel.pid=###CURRENT_PID### AND tx_irretutorial_mnmmasym_hotel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'offers' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.offers',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnmmasym_offer',
+                               'MM' => 'tx_irretutorial_mnmmasym_hotel_offer_rel',
+                               'MM_hasUidField' => TRUE,
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, offers;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnmmasym_offer'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnmmasym_offer']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,hotels,prices'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnmmasym_offer']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnmmasym_offer',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnmmasym_offer.pid=###CURRENT_PID### AND tx_irretutorial_mnmmasym_offer.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'hotels' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.hotels',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnmmasym_hotel',
+                               'MM' => 'tx_irretutorial_mnmmasym_hotel_offer_rel',
+                               'MM_hasUidField' => TRUE,
+                               'MM_opposite_field' => 'offers',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+               'prices' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_offer.prices',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnmmasym_price',
+                               'MM' => 'tx_irretutorial_mnmmasym_offer_price_rel',
+                               'MM_hasUidField' => TRUE,
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, hotels, prices,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnmmasym_price'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnmmasym_price']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,price,offers'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnmmasym_price']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnmmasym_price',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnmmasym_price.pid=###CURRENT_PID### AND tx_irretutorial_mnmmasym_price.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'price' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.price',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'double2',
+                       )
+               ),
+               'offers' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_price.offers',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnmmasym_offer',
+                               'MM' => 'tx_irretutorial_mnmmasym_offer_price_rel',
+                               'MM_hasUidField' => TRUE,
+                               'MM_opposite_field' => 'prices',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, price;;;;3-3-3, offers,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnsym.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/Tca/tca.mnsym.php
new file mode 100644 (file)
index 0000000..9175220
--- /dev/null
@@ -0,0 +1,185 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die('Access denied.');
+}
+
+$TCA['tx_irretutorial_mnsym_hotel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnsym_hotel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,branches'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnsym_hotel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnsym_hotel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnsym_hotel.pid=###CURRENT_PID### AND tx_irretutorial_mnsym_hotel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 1,
+                       'l10n_mode' => 'prefixLangTitle',
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '30',
+                               'eval' => 'required',
+                       )
+               ),
+               'branches' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel.branches',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_irretutorial_mnsym_hotel_rel',
+                               'foreign_field' => 'hotelid',
+                               'foreign_sortby' => 'hotelsort',
+                               'foreign_label' => 'branchid',
+                               'symmetric_field' => 'branchid',
+                               'symmetric_sortby' => 'branchsort',
+                               'symmetric_label' => 'hotelid',
+                               'maxitems' => 10,
+                               'appearance' => array(
+                                       'showSynchronizationLink' => 1,
+                                       'showAllLocalizationLink' => 1,
+                                       'showPossibleLocalizationRecords' => 1,
+                                       'showRemovedLocalizationRecords' => 1,
+                               ),
+                               'behaviour' => array(
+                                       'localizationMode' => 'select',
+                               ),
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, branches;;;;3-3-3,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+
+
+
+$TCA['tx_irretutorial_mnsym_hotel_rel'] = array(
+       'ctrl' => $TCA['tx_irretutorial_mnsym_hotel_rel']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,hotelid,offerid,hotelsort,offersort'
+       ),
+       'feInterface' => $TCA['tx_irretutorial_mnsym_hotel_rel']['feInterface'],
+       'columns' => array(
+               'sys_language_uid' => array(
+                       'exclude' => 1,
+                       'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
+                       'config' => array(
+                               'type'                => 'select',
+                               'foreign_table'       => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => array(
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
+                                       array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
+                               )
+                       )
+               ),
+               'l18n_parent' => array(
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude'     => 1,
+                       'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
+                       'config'      => array(
+                               'type'  => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'foreign_table'       => 'tx_irretutorial_mnsym_hotel_rel',
+                               'foreign_table_where' => 'AND tx_irretutorial_mnsym_hotel_rel.pid=###CURRENT_PID### AND tx_irretutorial_mnsym_hotel_rel.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => array(
+                       'config' => array(
+                               'type' => 'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check',
+                               'default' => '0'
+                       )
+               ),
+               'hotelid' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_rel.hotelid',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_irretutorial_mnsym_hotel',
+                               'maxitems' => 1,
+                               'localizeReferences' => 1,
+                       )
+               ),
+               'branchid' => array(
+                       'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tx_irretutorial_hotel_rel.branchid',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_irretutorial_mnsym_hotel',
+                               'maxitems' => 1,
+                               'localizeReferences' => 1,
+                       )
+               ),
+               'hotelsort' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+               'branchsort' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+       ),
+       'types' => array(
+               '0' => Array('showitem' =>
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.general, title;;;;2-2-2, hotelid;;;;3-3-3, branchid,' .
+                       '--div--;LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:tabs.visibility, sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, hotelsort, branchsort'
+               )
+       ),
+       'palettes' => array(
+               '1' => Array('showitem' => '')
+       )
+);
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/README.txt b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/README.txt
new file mode 100644 (file)
index 0000000..cef1058
--- /dev/null
@@ -0,0 +1,63 @@
+=====================================================================================================
+TYPO3: Inline Relational Record Editing Tutorial
+(c) 2007-2010 Oliver Hader <oliver@typo3.org> - 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 So
+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.
+=====================================================================================================
+
+
+-----------------------------
+ 1. Installation
+---------------------------
+Download the extension "irre_tutorial" from the TYPO3 Extension Repository at http://www.typo3.org/
+Install the extension using the Extension Manager (EM) in the TYPO3 Backend. You need administrative
+rights (admin user) at your TYPO3 installation to be able to do this.
+
+After this extension was installed, a new backend module "Web>IRRE Tutorial" will appear. By clicking
+on the module link in the left menu frame, you can import a set of sample data.
+
+To uninstall the sample data you have to select "Uninstall sample data" from the upper right corner
+in the "IRRE Tutorial" module. The script looks for a page alias "irre_tutorial_data" and removes, if
+successfully found, this branch from your TYPO3 installation.
+
+
+
+-----------------------------
+ 2. Usage
+---------------------------
+After you imported the IRRE Tutorial sample data, you are can play around, change tca.php files etc.
+You can just do, what ever you'd like to. The ext_tables.php and tca.php have a additional string in
+their filenames. This should help you to find the case you're looking fore faster. See the following
+description what these strings (e.g. like "tx_irretutorial_<string>_hotel or tca.<string>.php) mean:
+
+       * 1ncsv: 1:n relations using comma separated values as list
+       * 1nff: 1:n relations using foreign_field as pointer on child table
+       * mnasym: m:n bidirectional asymmetric relations using intermediate table
+       * mnsym: m:n bidirectional symmetric relations using intermediate table
+       * mnattr: m:n bidirectional asymmetric attributed relations using intermediate table
+       * mnmmasym: m:n bidirectional asymmetric relations using the default MM feature of TYPO3
+
+
+
+-----------------------------
+ 3. To-Do
+---------------------------
+...
+
+
+
+-----------------------------
+ 4. Links
+---------------------------
+Extension:     http://typo3.org/extensions/repository/view/irre_tutorial/
+Thesis:                http://typo3.org/documentation/article/inline-relational-record-editing-irre/
+Video:         http://typo3.org/videos/play/7-minutes-of-fame-inline-relational-record-editing-irre/
+Core API:      http://docs.typo3.org/typo3cms/CoreApiReference/
+Wiki:          http://wiki.typo3.org/IRRE
+XING:          https://www.xing.com/profile/Oliver_Hader
+
+
+=====================================================================================================
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Private/Language/locallang_db.xml b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Private/Language/locallang_db.xml
new file mode 100644 (file)
index 0000000..f5cf6a3
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<T3locallang>
+       <meta type="array">
+               <type>database</type>
+               <description>Language labels for database tables/fields belonging to extension 'irre_tutorial'</description>
+       </meta>
+       <data type="array">
+               <languageKey index="default" type="array">
+                       <label index="tabs.general">General</label>
+                       <label index="tabs.visibility">Visibility</label>
+
+                       <label index="pages.doktype.div.irre">IRRE Tutorial</label>
+                       <label index="pages.doktype.I.233">IRRE Tutorial Test Page</label>
+                       <label index="pages.tx_irretutorial_hotels">Hotels:</label>
+                       <label index="tt_content.tx_irretutorial_flexform">IRRE:</label>
+                       <label index="tt_content.tx_irretutorial_flexform.hotels">IRRE:</label>
+                       <label index="tt_content.div.irre">IRRE Tutorial</label>
+
+                       <label index="tx_irretutorial_1ncsv_hotel">1:n CSV: Hotels</label>
+                       <label index="tx_irretutorial_1ncsv_offer">1:n CSV: Offers</label>
+                       <label index="tx_irretutorial_1ncsv_price">1:n CSV: Prices</label>
+                       <label index="tx_irretutorial_1nff_hotel">1:n FF: Hotels</label>
+                       <label index="tx_irretutorial_1nff_offer">1:n FF: Offers</label>
+                       <label index="tx_irretutorial_1nff_price">1:n FF: Prices</label>
+                       <label index="tx_irretutorial_mnasym_hotel">m:n ASym: Hotels</label>
+                       <label index="tx_irretutorial_mnasym_hotel_offer_rel">m:n ASym: Hotels&lt;-&gt;Offers</label>
+                       <label index="tx_irretutorial_mnasym_offer">m:n ASym: Offers</label>
+                       <label index="tx_irretutorial_mnasym_price">m:n ASym: Prices</label>
+                       <label index="tx_irretutorial_mnmmasym_hotel">m:n (MM) ASym: Hotels</label>
+                       <label index="tx_irretutorial_mnmmasym_offer">m:n (MM) ASym: Offers</label>
+                       <label index="tx_irretutorial_mnmmasym_price">m:n (MM) ASym: Prices</label>
+                       <label index="tx_irretutorial_mnsym_hotel">m:n Sym: Hotels</label>
+                       <label index="tx_irretutorial_mnsym_hotel_rel">m:n Sym: Hotels&lt;-&gt;Hotels</label>
+                       <label index="tx_irretutorial_mnattr_hotel">m:n Attr: Hotels</label>
+                       <label index="tx_irretutorial_mnattr_hotel_offer_rel">m:n Attr: Hotels&lt;-&gt;Offers</label>
+                       <label index="tx_irretutorial_mnattr_offer">m:n Attr: Offers</label>
+
+                       <label index="tx_irretutorial_hotel.title">Title:</label>
+                       <label index="tx_irretutorial_hotel.offers">Offers:</label>
+                       <label index="tx_irretutorial_hotel.branches">Branches:</label>
+                       <label index="tx_irretutorial_hotel_rel">Hotels&lt;-&gt;Hotels</label>
+                       <label index="tx_irretutorial_hotel_rel.hotelid">Hotel:</label>
+                       <label index="tx_irretutorial_hotel_rel.branchid">Branch:</label>
+                       <label index="tx_irretutorial_hotel_offer_rel">Hotels&lt;-&gt;Offers</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.hotelid">Hotel:</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.offerid">Offer:</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.prices">Prices:</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.quality">Quality:</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.quality.I.0">(1 star) *</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.quality.I.1">(2 stars) **</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.quality.I.2">(3 stars) ***</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.quality.I.3">(4 stars) ****</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.quality.I.4">(5 stars) *****</label>
+                       <label index="tx_irretutorial_hotel_offer_rel.allincl">all inclusive:</label>
+
+                       <label index="tx_irretutorial_offer.title">Title:</label>
+                       <label index="tx_irretutorial_offer.hotels">Hotels:</label>
+                       <label index="tx_irretutorial_offer.prices">Prices:</label>
+
+                       <label index="tx_irretutorial_price.title">Title:</label>
+                       <label index="tx_irretutorial_price.offers">Offers:</label>
+                       <label index="tx_irretutorial_price.price">Price (EUR):</label>
+               </languageKey>
+       </data>
+</T3locallang>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel.gif
new file mode 100644 (file)
index 0000000..fa6b46c
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_offer_rel.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_offer_rel.gif
new file mode 100644 (file)
index 0000000..d94d291
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_offer_rel.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_rel.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_rel.gif
new file mode 100644 (file)
index 0000000..1c10e92
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_hotel_rel.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer.gif
new file mode 100644 (file)
index 0000000..a573eb3
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer_price_rel.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer_price_rel.gif
new file mode 100644 (file)
index 0000000..9ae214c
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_offer_price_rel.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_price.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_price.gif
new file mode 100644 (file)
index 0000000..8ab1559
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Resources/Public/Icons/icon_tx_irretutorial_price.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_emconf.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_emconf.php
new file mode 100644 (file)
index 0000000..ecd5656
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+$EM_CONF[$_EXTKEY] = array(
+       'title' => 'Fixture extension for functional tests for Inline Relational Record Editing IRRE',
+       'description' => 'based on irre_tutorial extension created by Oliver Hader, see http://forge.typo3.org/projects/extension-irre_tutorial',
+       'category' => 'example',
+       'shy' => 0,
+       'version' => '0.4.0',
+       'dependencies' => 'workspaces,version',
+       'conflicts' => '',
+       'priority' => '',
+       'loadOrder' => '',
+       'module' => 'mod1',
+       'state' => 'beta',
+       'uploadfolder' => 0,
+       'createDirs' => '',
+       'modify_tables' => '',
+       'clearcacheonload' => 0,
+       'lockType' => '',
+       'author' => 'Oliver Hader',
+       'author_email' => 'oliver@typo3.org',
+       'author_company' => '',
+       'CGLcompliance' => '',
+       'CGLcompliance_note' => '',
+       'constraints' => array(
+               'depends' => array(
+                       'typo3' => '4.5.0-0.0.0',
+                       'workspaces' => '0.0.0-',
+                       'version' => '0.0.0-',
+               ),
+               'conflicts' => array(
+               ),
+               'suggests' => array(
+               ),
+       ),
+       'suggests' => array(
+       ),
+);
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_icon.gif b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_icon.gif
new file mode 100644 (file)
index 0000000..893b87a
Binary files /dev/null and b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_icon.gif differ
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.php
new file mode 100644 (file)
index 0000000..fb32a0f
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+if (!defined ('TYPO3_MODE'))   die ('Access denied.');
+
+       // ext_tables.php is split to each single part of application
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.general.php';
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.1nff.php';
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.mnasym.php';
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.mnmmasym.php';
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.mnsym.php';
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.mnattr.php';
+require(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY)).'Configuration/ExtTables/ext_tables.1ncsv.php';
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.sql b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.sql
new file mode 100644 (file)
index 0000000..98dfc90
--- /dev/null
@@ -0,0 +1,743 @@
+#######################################################################################################################
+# Extend the pages table to have hotels with a 1:n relationship added there
+#######################################################################################################################
+
+#
+# Table structure for table 'pages'
+#
+CREATE TABLE pages (
+    tx_irretutorial_hotels int(11) DEFAULT '0' NOT NULL
+);
+
+
+#
+# Table structure for table 'pages_language_overlay'
+#
+CREATE TABLE pages_language_overlay (
+    tx_irretutorial_hotels int(11) DEFAULT '0' NOT NULL
+);
+
+
+#
+# Table structure for table 'tt_content'
+#
+CREATE TABLE tt_content (
+    tx_irretutorial_flexform mediumtext
+);
+
+
+#######################################################################################################################
+# 1ncsv: 1:n relations using comma separated values as list
+#######################################################################################################################
+
+#
+# Table structure for table 'tx_irretutorial_1ncsv_hotel'
+#
+CREATE TABLE tx_irretutorial_1ncsv_hotel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       offers text NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_1ncsv_offer'
+#
+CREATE TABLE tx_irretutorial_1ncsv_offer (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       prices text NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_1ncsv_price'
+#
+CREATE TABLE tx_irretutorial_1ncsv_price (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       price double(11,2) DEFAULT '0.00' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+#######################################################################################################################
+# 1nff: 1:n relations using foreign_field as pointer on child table
+#######################################################################################################################
+
+#
+# Table structure for table 'tx_irretutorial_1nff_hotel'
+#
+CREATE TABLE tx_irretutorial_1nff_hotel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       parentid int(11) DEFAULT '0' NOT NULL,
+       parenttable tinytext NOT NULL,
+       parentidentifier tinytext NOT NULL,
+       title tinytext NOT NULL,
+       offers int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_1nff_offer'
+#
+CREATE TABLE tx_irretutorial_1nff_offer (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       parentid int(11) DEFAULT '0' NOT NULL,
+       parenttable tinytext NOT NULL,
+       parentidentifier tinytext NOT NULL,
+       title tinytext NOT NULL,
+       prices int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_1nff_price'
+#
+CREATE TABLE tx_irretutorial_1nff_price (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       parentid int(11) DEFAULT '0' NOT NULL,
+       parenttable tinytext NOT NULL,
+       parentidentifier tinytext NOT NULL,
+       title tinytext NOT NULL,
+       price double(11,2) DEFAULT '0.00' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+#######################################################################################################################
+# mnasym: m:n bidirectional anti-symmetric relations using intermediate table
+#######################################################################################################################
+
+#
+# Table structure for table 'tx_irretutorial_mnasym_hotel'
+#
+CREATE TABLE tx_irretutorial_mnasym_hotel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       offers int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnasym_hotel_offer_rel'
+#
+CREATE TABLE tx_irretutorial_mnasym_hotel_offer_rel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       hotelid int(11) DEFAULT '0' NOT NULL,
+       offerid int(11) DEFAULT '0' NOT NULL,
+       hotelsort int(10) DEFAULT '0' NOT NULL,
+       offersort int(10) DEFAULT '0' NOT NULL,
+       prices int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnasym_offer'
+#
+CREATE TABLE tx_irretutorial_mnasym_offer (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       hotels int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnasym_price'
+#
+CREATE TABLE tx_irretutorial_mnasym_price (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       parentid int(11) DEFAULT '0' NOT NULL,
+       title tinytext NOT NULL,
+       price double(11,2) DEFAULT '0.00' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+#######################################################################################################################
+# mnasym: m:n bidirectional anti-symmetric relations using regular MM tables
+#######################################################################################################################
+
+#
+# Table structure for table 'tx_irretutorial_mnmmasym_hotel'
+#
+CREATE TABLE tx_irretutorial_mnmmasym_hotel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       offers int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnmmasym_hotel_offer_rel'
+#
+CREATE TABLE tx_irretutorial_mnmmasym_hotel_offer_rel (
+       uid int(11) NOT NULL auto_increment,
+       uid_local int(11) DEFAULT '0' NOT NULL,
+       uid_foreign int(11) DEFAULT '0' NOT NULL,
+       tablenames varchar(255) DEFAULT '' NOT NULL,
+       sorting int(11) DEFAULT '0' NOT NULL,
+       sorting_foreign int(11) DEFAULT '0' NOT NULL,
+       ident varchar(255) DEFAULT '' NOT NULL,
+
+       KEY uid_local (uid_local),
+       KEY uid_foreign (uid_foreign),
+       PRIMARY KEY (uid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnmmasym_offer'
+#
+CREATE TABLE tx_irretutorial_mnmmasym_offer (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       hotels int(11) DEFAULT '0' NOT NULL,
+       prices int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnmmasym_offer_price_rel'
+#
+CREATE TABLE tx_irretutorial_mnmmasym_offer_price_rel (
+       uid int(11) NOT NULL auto_increment,
+       uid_local int(11) DEFAULT '0' NOT NULL,
+       uid_foreign int(11) DEFAULT '0' NOT NULL,
+       tablenames varchar(255) DEFAULT '' NOT NULL,
+       sorting int(11) DEFAULT '0' NOT NULL,
+       sorting_foreign int(11) DEFAULT '0' NOT NULL,
+       ident varchar(255) DEFAULT '' NOT NULL,
+
+       KEY uid_local (uid_local),
+       KEY uid_foreign (uid_foreign),
+       PRIMARY KEY (uid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnmmasym_price'
+#
+CREATE TABLE tx_irretutorial_mnmmasym_price (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       price double(11,2) DEFAULT '0.00' NOT NULL,
+       offers int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+#######################################################################################################################
+# mnsym: m:n bidirectional symmetric relations using intermediate table
+#######################################################################################################################
+
+#
+# Table structure for table 'tx_irretutorial_mnsym_hotel'
+#
+CREATE TABLE tx_irretutorial_mnsym_hotel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       branches int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnsym_hotel_rel'
+#
+CREATE TABLE tx_irretutorial_mnsym_hotel_rel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       hotelid int(11) DEFAULT '0' NOT NULL,
+       branchid int(11) DEFAULT '0' NOT NULL,
+       hotelsort int(10) DEFAULT '0' NOT NULL,
+       branchsort int(10) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+#######################################################################################################################
+# mnattr: m:n bidirectional (anti-)symmetric attributed relations using intermediate table
+#######################################################################################################################
+
+#
+# Table structure for table 'tx_irretutorial_mnattr_hotel'
+#
+CREATE TABLE tx_irretutorial_mnattr_hotel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       offers int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnattr_hotel_offer_rel'
+#
+CREATE TABLE tx_irretutorial_mnattr_hotel_offer_rel (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       hotelid int(11) DEFAULT '0' NOT NULL,
+       offerid int(11) DEFAULT '0' NOT NULL,
+       hotelsort int(10) DEFAULT '0' NOT NULL,
+       offersort int(10) DEFAULT '0' NOT NULL,
+       quality tinyint(4) DEFAULT '0' NOT NULL,
+       allincl tinyint(4) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
+
+
+
+#
+# Table structure for table 'tx_irretutorial_mnattr_offer'
+#
+CREATE TABLE tx_irretutorial_mnattr_offer (
+       uid int(11) NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+       tstamp int(11) DEFAULT '0' NOT NULL,
+       crdate int(11) DEFAULT '0' NOT NULL,
+       cruser_id int(11) DEFAULT '0' NOT NULL,
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+       sorting int(10) DEFAULT '0' NOT NULL,
+       deleted tinyint(4) DEFAULT '0' NOT NULL,
+       hidden tinyint(4) DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       title tinytext NOT NULL,
+       hotels int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid)
+);
index 73f707e..8766471 100644 (file)
                <deleted>0</deleted>
                <perms_everybody>15</perms_everybody>
        </pages>
+       <pages>
+               <uid>7</uid>
+               <pid>0</pid>
+               <title>Root 2</title>
+               <deleted>0</deleted>
+               <perms_everybody>15</perms_everybody>
+       </pages>
 </dataset>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractOneToNTestCase.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractOneToNTestCase.php
new file mode 100644 (file)
index 0000000..8932cb6
--- /dev/null
@@ -0,0 +1,447 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Oliver Hader <oliver@typo3.org>
+*  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!
+***************************************************************/
+
+require_once(dirname(__FILE__). '/AbstractTestCase.php');
+
+/**
+ * Test case for 1:n csv relations.
+ *
+ */
+abstract class AbstractOneToNTestCase extends AbstractTestCase {
+       const TABLE_Hotel = 'tx_irretutorial_1ncsv_hotel';
+       const TABLE_Offer = 'tx_irretutorial_1ncsv_offer';
+       const TABLE_Price = 'tx_irretutorial_1ncsv_price';
+
+       const FIELD_Hotel_Offers = 'offers';
+       const FIELD_Offers_Prices = 'prices';
+
+       /**
+        * Versionize all children with parent.
+        *
+        * @return array
+        */
+       protected function versionizeAllChildrenWithParent() {
+               $liveElements = array(
+                       static::TABLE_Hotel => '1',
+                       static::TABLE_Offer => '1,2',
+                       // prices 1,2 are children of offer 2
+                       // price 3 is child of offer 1
+                       static::TABLE_Price => '1,2,3',
+               );
+
+               $this->simulateEditing($liveElements);
+
+               return $liveElements;
+       }
+
+       /****************************************************************
+        * PUBLISH/SWAP/CLEAR Behaviour
+        ****************************************************************/
+
+       /**
+        * @return void
+        * @test
+        */
+       public function isChildPublishedSeparatelyIfParentIsVersionized() {
+               $this->setExpectedLogEntries(1);
+
+               $this->versionizeAllChildrenWithParent();
+
+               $versionizedOfferId = $this->getWorkspaceVersionId(static::TABLE_Offer, 1);
+
+               $this->simulateVersionCommand(
+                       array(
+                               'action' => static::COMMAND_Version_Swap,
+                               'swapWith' => $versionizedOfferId,
+                       ),
+                       array(
+                               static::TABLE_Offer => '1',
+                       )
+               );
+
+               $this->assertContains(
+                       'cannot be swapped or published independently, because it is related to other new or modified records',
+                       $this->getLastLogEntryMessage(),
+                       'Expected error was not reported.'
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function isChildSwappedSeparatelyIfParentIsVersionized() {
+               $this->setExpectedLogEntries(2);
+
+               $this->versionizeAllChildrenWithParent();
+
+               $versionizedOfferId = $this->getWorkspaceVersionId(static::TABLE_Offer, 1);
+               $versionizedPriceId = $this->getWorkspaceVersionId(static::TABLE_Price, 3);
+
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Price => array(
+                               '3' => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Swap,
+                                               'swapWith' => $versionizedPriceId,
+                                               'swapIntoWS' => 1,
+                                               'notificationAlternativeRecipients' => array(),
+                                       )
+                               )
+                       ),
+                       static::TABLE_Offer => array(
+                               '1' => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Swap,
+                                               'swapWith' => $versionizedOfferId,
+                                               'swapIntoWS' => 1,
+                                               'notificationAlternativeRecipients' => array(),
+                                       )
+                               )
+                       ),
+               ));
+
+               $this->assertContains(
+                       'cannot be swapped or published independently, because it is related to other new or modified records',
+                       $this->getLastLogEntryMessage(),
+                       'Expected error was not reported.'
+               );
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areAllChildrenSwappedAutomaticallyIfParentIsSwapped() {
+               $this->setWorkspacesConsiderReferences(TRUE);
+
+               $this->versionizeAllChildrenWithParent();
+               $versionizedHotelId = $this->getWorkspaceVersionId(static::TABLE_Hotel, 1);
+
+               $this->getCommandMapAccess(1);
+
+               // Swap to live:
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Hotel => array(
+                               '1' => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Swap,
+                                               'swapWith' => $versionizedHotelId,
+                                               'swapIntoWS' => 1,
+                                               'notificationAlternativeRecipients' => array(),
+                                       )
+                               )
+                       ),
+               ));
+
+               $commandMap = $this->getCommandMap()->get();
+
+               $this->assertTrue(isset($commandMap[static::TABLE_Hotel][1]['version']), static::TABLE_Hotel . ':1 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Offer][1]['version']), static::TABLE_Offer . ':1 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Offer][2]['version']), static::TABLE_Offer . ':2 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Price][1]['version']), static::TABLE_Price . ':1 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Price][2]['version']), static::TABLE_Price . ':2 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Price][3]['version']), static::TABLE_Price . ':3 is not set.');
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areAllChildrenDoubleSwappedAutomaticallyIfParentIsSwapped() {
+               $this->setWorkspacesConsiderReferences(TRUE);
+
+               $this->versionizeAllChildrenWithParent();
+               $versionizedHotelId = $this->getWorkspaceVersionId(static::TABLE_Hotel, 1);
+
+               // Swap to live:
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Hotel => array(
+                               '1' => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Swap,
+                                               'swapWith' => $versionizedHotelId,
+                                               'swapIntoWS' => 1,
+                                               'notificationAlternativeRecipients' => array(),
+                                       )
+                               )
+                       ),
+               ));
+
+               $this->getCommandMapAccess(1);
+
+               // Swap back to workspace:
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Hotel => array(
+                               '1' => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Swap,
+                                               'swapWith' => $versionizedHotelId,
+                                               'swapIntoWS' => 1,
+                                               'notificationAlternativeRecipients' => array(),
+                                       )
+                               )
+                       ),
+               ));
+
+               $commandMap = $this->getCommandMap()->get();
+
+               $this->assertTrue(isset($commandMap[static::TABLE_Hotel][1]['version']), static::TABLE_Hotel . ':1 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Offer][1]['version']), static::TABLE_Offer . ':1 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Offer][2]['version']), static::TABLE_Offer . ':2 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Price][1]['version']), static::TABLE_Price . ':1 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Price][2]['version']), static::TABLE_Price . ':2 is not set.');
+               $this->assertTrue(isset($commandMap[static::TABLE_Price][3]['version']), static::TABLE_Price . ':3 is not set.');
+       }
+
+       /*
+        * Removing child records
+        */
+
+       /**
+        * Live version will be versionized, but one child branch is removed.
+        *
+        * @return void
+        * @test
+        */
+       public function areChildRecordsConsideredToBeRemovedOnEditingParent() {
+               $this->simulateByStructure(
+                       $this->getElementStructureForEditing(array(
+                               static::TABLE_Hotel => '1',
+                       )),
+                       $this->getElementStructureForCommands(static::COMMAND_Delete, 1, array(
+                               static::TABLE_Offer => '1',
+                       ))
+               );
+
+               $this->assertHasDeletePlaceholder(array(
+                       static::TABLE_Offer => '1',
+                       static::TABLE_Price => '3',
+               ));
+       }
+
+       /**
+        * Live version will be versionized, but one child branch is removed.
+        *
+        * @return void
+        * @test
+        */
+       public function areChildRecordsConsideredToBeRemovedOnEditingParentAndChildren() {
+               $this->simulateByStructure(
+                       $this->getElementStructureForEditing(array(
+                               static::TABLE_Hotel => '1',
+                               static::TABLE_Offer => '1',
+                       )),
+                       $this->getElementStructureForCommands(static::COMMAND_Delete, 1, array(
+                               static::TABLE_Offer => '1',
+                       ))
+               );
+
+               $this->assertHasDeletePlaceholder(array(
+                       static::TABLE_Offer => '1',
+                       static::TABLE_Price => '3',
+               ));
+       }
+
+       /**
+        * Versionized version will be modified and one child branch is removed.
+        *
+        * @return void
+        * @test
+        */
+       public function areChildRecordsConsideredToBeRevertedOnEditing() {
+               $this->markTestSkipped('Enable this test once http://forge.typo3.org/issues/29278 is merged');
+
+               $this->versionizeAllChildrenWithParent();
+
+               $versionizedOfferId = $this->getWorkspaceVersionId(static::TABLE_Offer, 1);
+               $versionizedPriceId = $this->getWorkspaceVersionId(static::TABLE_Price, 3);
+
+               $this->simulateCommand(static::COMMAND_Delete, 1, array(static::TABLE_Offer => $versionizedOfferId));
+
+               $this->assertIsDeleted(array(
+                       static::TABLE_Offer => $versionizedOfferId,
+                       static::TABLE_Price => $versionizedPriceId,
+               ));
+       }
+
+       /**
+        * @return void
+        * @test
+        */
+       public function areNestedChildRecordsConsideredToBeRemovedOnDirectRemoval() {
+               $this->simulateCommand(static::COMMAND_Delete, 1, array(static::TABLE_Offer => 1));
+
+               $this->assertHasDeletePlaceholder(array(
+                       static::TABLE_Offer => '1',
+                       static::TABLE_Price => '3',
+               ));
+       }
+
+       /**
+        * Test whether elements that are reverted in the workspace module
+        * also trigger the reverting of child records.
+        *
+        * @return void
+        * @test
+        */
+       public function areChildRecordsRevertedOnRevertingTheRelativeRemovedParent() {
+               $this->setWorkspacesConsiderReferences(TRUE);
+
+               $this->simulateByStructure(
+                       $this->getElementStructureForEditing(array(
+                               static::TABLE_Hotel => '1',
+                               static::TABLE_Offer => '1',
+                       )),
+                       $this->getElementStructureForCommands(static::COMMAND_Delete, 1, array(
+                               static::TABLE_Offer => '1',
+                       ))
+               );
+
+               $versionizedOfferId = $this->getWorkspaceVersionId(static::TABLE_Offer, 1, static::VALUE_WorkspaceId, TRUE);
+
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Offer => array(
+                               $versionizedOfferId => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Clear,
+                                       )
+                               )
+                       ),
+               ));
+
+               $this->assertWorkspaceVersions(array(
+                       static::TABLE_Hotel => '1',
+                       static::TABLE_Offer => '2',
+                       static::TABLE_Price => '1,2',
+               ));
+
+               $this->assertFalse($this->getWorkspaceVersionId(static::TABLE_Offer, 1, static::VALUE_WorkspaceId, TRUE));
+               $this->assertFalse($this->getWorkspaceVersionId(static::TABLE_Price, 3, static::VALUE_WorkspaceId, TRUE));
+       }
+
+       /**
+        * Test whether elements that are reverted in the workspace module
+        * also trigger the reverting of child records.
+        *
+        * @return void
+        * @test
+        */
+       public function areChildRecordsRevertedOnRevertingMultipleElements() {
+               $this->setWorkspacesConsiderReferences(TRUE);
+
+               $this->simulateByStructure(
+                       $this->getElementStructureForEditing(array(
+                               static::TABLE_Hotel => '1',
+                               static::TABLE_Offer => '1',
+                       )),
+                       $this->getElementStructureForCommands(static::COMMAND_Delete, 1, array(
+                               static::TABLE_Offer => '1',
+                       ))
+               );
+
+               $versionizedOfferId = $this->getWorkspaceVersionId(static::TABLE_Offer, 1, static::VALUE_WorkspaceId, TRUE);
+               $versionizedPriceId = $this->getWorkspaceVersionId(static::TABLE_Price, 1);
+
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Offer => array(
+                               $versionizedOfferId => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Clear,
+                                       )
+                               )
+                       ),
+                       static::TABLE_Price => array(
+                               $versionizedPriceId => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Clear,
+                                       )
+                               )
+                       ),
+               ));
+
+               $this->assertWorkspaceVersions(array(
+                       static::TABLE_Hotel => '1',
+                       static::TABLE_Offer => '2',
+                       static::TABLE_Price => '2',
+               ));
+
+               $this->assertFalse($this->getWorkspaceVersionId(static::TABLE_Offer, 1, static::VALUE_WorkspaceId, TRUE));
+               $this->assertFalse($this->getWorkspaceVersionId(static::TABLE_Price, 3, static::VALUE_WorkspaceId, TRUE));
+               $this->assertFalse($this->getWorkspaceVersionId(static::TABLE_Price, 1, static::VALUE_WorkspaceId, TRUE));
+       }
+
+       /**
+        * Tests whether records marked to be deleted in a workspace
+        * are really removed if they are published.
+        *
+        * @return void
+        * @test
+        */
+       public function areParentAndChildRecordsRemovedOnPublishingDeleteAction() {
+               $this->setWorkspacesConsiderReferences(TRUE);
+
+               $this->simulateByStructure(
+                       array(),
+                       $this->getElementStructureForCommands(static::COMMAND_Delete, 1, array(
+                               static::TABLE_Hotel => '1',
+                       ))
+               );
+
+               $versionizedHotelId = $this->getWorkspaceVersionId(static::TABLE_Hotel, 1, static::VALUE_WorkspaceId, TRUE);
+
+               // Swap to live:
+               $this->simulateCommandByStructure(array(
+                       static::TABLE_Hotel => array(
+                               '1' => array(
+                                       'version' => array(
+                                               'action' => static::COMMAND_Version_Swap,
+                                               'swapWith' => $versionizedHotelId,
+                                               'notificationAlternativeRecipients' => array(),
+                                       )
+                               )
+                       ),
+               ));
+
+               $this->assertRecords(
+                       array(
+                               static::TABLE_Hotel => array(
+                                       1 => array('deleted' => '1',),
+                               ),
+                               static::TABLE_Offer => array(
+                                       1 => array('deleted' => '1',),
+                                       2 => array('deleted' => '1',),
+                               ),
+                               static::TABLE_Price => array(
+                                       1 => array('deleted' => '1',),
+                                       2 => array('deleted' => '1',),
+                                       3 => array('deleted' => '1',),
+                               ),
+                       ),
+                       static::VALUE_WorkspaceIdIgnore
+               );
+       }
+}
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php
new file mode 100644 (file)
index 0000000..ed8b04b
--- /dev/null
@@ -0,0 +1,378 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Oliver Hader <oliver@typo3.org>
+*  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!
+***************************************************************/
+
+require_once(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/AbstractTestCase.php');
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Generic test helpers.
+ *
+ * @author Oliver Hader <oliver@typo3.org>
+ */
+abstract class AbstractTestCase extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\InlineRelationalRecordEditing\AbstractTestCase {
+       const VALUE_TimeStamp = 1250000000;
+       const VALUE_Pid = 1;
+       const VALUE_PidAlternative = 7;
+       const VALUE_WorkspaceId = 90;
+       const VALUE_WorkspaceIdIgnore = -1;
+
+       const COMMAND_Version = 'version';
+       const COMMAND_Version_New = 'new';
+       const COMMAND_Version_Swap = 'swap';
+       const COMMAND_Version_Flush = 'flush';
+       const COMMAND_Version_Clear = 'clearWSID';
+
+       protected $coreExtensionsToLoad = array('version', 'workspaces');
+
+       /**
+        * @var integer
+        */
+       private $modifiedTimeStamp;
+
+       /**
+        * @var \TYPO3\CMS\Version\Hook\DataHandlerHook|\PHPUnit_Framework_MockObject_MockObject
+        */
+       protected $versionTceMainHookMock;
+
+       /**
+        * @var \TYPO3\CMS\Version\DataHandler\CommandMap
+        */
+       protected $versionTceMainCommandMap;
+
+       /**
+        * Sets up this test case.
+        *
+        * @return void
+        */
+       public function setUp() {
+               parent::setUp();
+
+               $this->importDataSet(__DIR__ . '/../../Fixtures/sys_workspace.xml');
+
+               $this->getBackendUser()->workspace = self::VALUE_WorkspaceId;
+               $this->setWorkspacesConsiderReferences(FALSE);
+               $this->setWorkspaceChangeStageMode('');
+               $this->setWorkspaceSwapMode('');
+       }
+
+
+       /**
+        * Gets a modified timestamp to ensure that a record is changed.
+        *
+        * @return integer
+        */
+       protected function getModifiedTimeStamp() {
+               if (!isset($this->modifiedTimeStamp)) {
+                       $this->modifiedTimeStamp = self::VALUE_TimeStamp + 100;
+               }
+
+               return $this->modifiedTimeStamp;
+       }
+
+       /**
+        * Gets an element structure of tables and ids used to simulate editing with TCEmain.
+        *
+        * @param array $tables Table names with list of ids to be edited
+        * @return array
+        */
+       protected function getElementStructureForEditing(array $tables) {
+               $editStructure = array();
+
+               foreach ($tables as $tableName => $idList) {
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $editStructure[$tableName][$id] = array(
+                                       'tstamp' => $this->getModifiedTimeStamp(),
+                               );
+                       }
+               }
+
+               return $editStructure;
+       }
+
+       /**
+        * @param  array $tables Table names with list of ids to be edited
+        * @return DataHandler
+        */
+       protected function simulateEditing(array $tables) {
+               return $this->simulateEditingByStructure($this->getElementStructureForEditing($tables));
+       }
+
+       /**
+        * Simulates editing by using DataHandler.
+        *
+        * @param  array $elements The datamap to be delivered to DataHandler
+        * @return DataHandler
+        */
+       protected function simulateEditingByStructure(array $elements) {
+               $tceMain = $this->getTceMain();
+               $tceMain->start($elements, array());
+               $tceMain->process_datamap();
+
+               return $tceMain;
+       }
+
+       /**
+        * @param array $commands
+        * @param array $tables
+        * @return DataHandler
+        */
+       protected function simulateVersionCommand(array $commands, array $tables) {
+               return $this->simulateCommand(
+                       self::COMMAND_Version,
+                       $commands,
+                       $tables
+               );
+       }
+
+       /**
+        * Simulates editing and command by structure.
+        *
+        * @param array $editingElements
+        * @param array $commandElements
+        * @return DataHandler
+        */
+       protected function simulateByStructure(array $editingElements, array $commandElements) {
+               $tceMain = $this->getTceMain();
+               $tceMain->start($editingElements, $commandElements);
+               $tceMain->process_datamap();
+               $tceMain->process_cmdmap();
+
+               return $tceMain;
+       }
+
+       /**
+        * Asserts that accordant workspace version exist for live versions.
+        *
+        * @param array $tables Table names with list of ids to be edited
+        * @param integer $workspaceId Workspace to be used
+        * @param boolean $expected The expected value
+        * @return void
+        */
+       protected function assertWorkspaceVersions(array $tables, $workspaceId = self::VALUE_WorkspaceId, $expected = TRUE) {
+               foreach ($tables as $tableName => $idList) {
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $workspaceVersion = BackendUtility::getWorkspaceVersionOfRecord($workspaceId, $tableName, $id);
+                               $this->assertTrue(
+                                       ($expected ? $workspaceVersion !== FALSE : $workspaceVersion === FALSE),
+                                       'Workspace version for ' . $tableName . ':' . $id . ($expected ? ' not' : '') . ' available'
+                               );
+                       }
+               }
+       }
+
+       /**
+        * Gets a \TYPO3\CMS\Version\Hook\DataHandlerHook mock.
+        *
+        * @param integer $expectsGetCommandMap (optional) Expects number of invocations to getCommandMap method
+        * @return \TYPO3\CMS\Version\Hook\DataHandlerHook
+        */
+       protected function getVersionTceMainHookMock($expectsGetCommandMap = NULL) {
+               $this->versionTceMainHookMock = $this->getMock('TYPO3\\CMS\\Version\\Hook\\DataHandlerHook', array('getCommandMap'));
+
+               if (is_integer($expectsGetCommandMap) && $expectsGetCommandMap >= 0) {
+                       $this->versionTceMainHookMock->expects($this->exactly($expectsGetCommandMap))->method('getCommandMap')
+                               ->will($this->returnCallback(array($this, 'getVersionTceMainCommandMapCallback')));
+               } elseif (!is_null($expectsGetCommandMap)) {
+                       $this->fail('Expected invocation of getCommandMap must be integer >= 0.');
+               }
+
+               return $this->versionTceMainHookMock;
+       }
+
+       /**
+        * Gets access to the command map.
+        *
+        * @param integer $expectsGetCommandMap Expects number of invocations to getCommandMap method
+        * @return void
+        */
+       protected function getCommandMapAccess($expectsGetCommandMap) {
+               $hookReferenceString = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass']['version'];
+               $GLOBALS['T3_VAR']['getUserObj'][$hookReferenceString] = $this->getVersionTceMainHookMock($expectsGetCommandMap);
+       }
+
+       /**
+        * @param string $tableName
+        * @param integer $id
+        * @param integer $workspaceId
+        * @param boolean $directLookup
+        * @return boolean
+        */
+       protected function getWorkspaceVersionId($tableName, $id, $workspaceId = self::VALUE_WorkspaceId, $directLookup = FALSE) {
+               if ($directLookup) {
+                       $records = $this->getAllRecords($tableName);
+                       foreach ($records as $record) {
+                               if (($workspaceId === self::VALUE_WorkspaceIdIgnore || $record['t3ver_wsid'] == $workspaceId) && $record['t3ver_oid'] == $id) {
+                                       return $record['uid'];
+                               }
+                       }
+               } else {
+                       $workspaceVersion = BackendUtility::getWorkspaceVersionOfRecord($workspaceId, $tableName, $id);
+                       if ($workspaceVersion !== FALSE) {
+                               return $workspaceVersion['uid'];
+                       }
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * Asserts the existence of a delete placeholder record.
+        *
+        * @param array $tables
+        * @return void
+        */
+       protected function assertHasDeletePlaceholder(array $tables) {
+               foreach ($tables as $tableName => $idList) {
+                       $records = $this->getAllRecords($tableName);
+
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $failureMessage = 'Delete placeholder of "' . $tableName . ':' . $id . '"';
+                               $versionizedId = $this->getWorkspaceVersionId($tableName, $id);
+                               $this->assertTrue(isset($records[$versionizedId]), $failureMessage . ' does not exist');
+                               $this->assertEquals($id, $records[$versionizedId]['t3_origuid'], $failureMessage . ' has wrong relation to live workspace');
+                               $this->assertEquals($id, $records[$versionizedId]['t3ver_oid'], $failureMessage . ' has wrong relation to live workspace');
+                               $this->assertEquals(2, $records[$versionizedId]['t3ver_state'], $failureMessage . ' is not marked as DELETED');
+                               $this->assertEquals('DELETED!', $records[$versionizedId]['t3ver_label'], $failureMessage . ' is not marked as DELETED');
+                       }
+               }
+       }
+
+       /**
+        * @param array $tables
+        * @return void
+        */
+       protected function assertIsDeleted(array $tables) {
+               foreach ($tables as $tableName => $idList) {
+                       $records = $this->getAllRecords($tableName);
+
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $failureMessage = 'Workspace version "' . $tableName . ':' . $id . '"';
+                               $this->assertTrue(isset($records[$id]), $failureMessage . ' does not exist');
+                               $this->assertEquals(0, $records[$id]['t3ver_state']);
+                               $this->assertEquals(1, $records[$id]['deleted']);
+                       }
+               }
+       }
+
+       /**
+        * @param array $tables
+        * @return void
+        */
+       protected function assertIsCleared(array $tables) {
+               foreach ($tables as $tableName => $idList) {
+                       $records = $this->getAllRecords($tableName);
+
+                       $ids = GeneralUtility::trimExplode(',', $idList, TRUE);
+                       foreach ($ids as $id) {
+                               $failureMessage = 'Workspace version "' . $tableName . ':' . $id . '"';
+                               $this->assertTrue(isset($records[$id]), $failureMessage . ' does not exist');
+                               $this->assertEquals(0, $records[$id]['t3ver_state'], $failureMessage . ' has wrong state value');
+                               $this->assertEquals(0, $records[$id]['t3ver_wsid'], $failureMessage . ' is still in offline workspace');
+                               $this->assertEquals(-1, $records[$id]['pid'], $failureMessage . ' has wrong pid value');
+                       }
+               }
+       }
+
+       /**
+        * @param array $assertions
+        * @param integer $workspaceId
+        */
+       protected function assertRecords(array $assertions, $workspaceId = NULL) {
+               foreach ($assertions as $table => $elements) {
+                       $records = $this->getAllRecords($table);
+
+                       foreach ($elements as $uid => $data) {
+                               $intersection = array_intersect_assoc($data, $records[$uid]);
+                               $differences = array_intersect_key($records[$uid], array_diff_assoc($data, $records[$uid]));
+
+                               $this->assertTrue(
+                                       count($data) === count($intersection),
+                                       'Expected ' . $this->elementToString($data) . ' got differences in ' . $this->elementToString($differences) . ' for table ' . $table
+                               );
+
+                               if (is_integer($workspaceId)) {
+                                       $workspaceVersionId = $this->getWorkspaceVersionId($table, $uid, $workspaceId, TRUE);
+                                       $intersection = array_intersect_assoc($data, $records[$workspaceVersionId]);
+                                       $differences = array_intersect_key($records[$workspaceVersionId], array_diff_assoc($data, $records[$workspaceVersionId]));
+
+                                       $this->assertTrue(
+                                               count($data) === count($intersection),
+                                               'Expected ' . $this->elementToString($data) . ' got differences in ' . $this->elementToString($differences) . ' for table ' . $table
+                                       );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Sets the User TSconfig property options.workspaces.considerReferences.
+        *
+        * @param boolean $workspacesConsiderReferences
+        * @return void
+        */
+       protected function setWorkspacesConsiderReferences($workspacesConsiderReferences = TRUE) {
+               $this->getBackendUser()->userTS['options.']['workspaces.']['considerReferences'] = ($workspacesConsiderReferences ? 1 : 0);
+       }
+
+       /**
+        * Sets the User TSconfig property options.workspaces.swapMode.
+        *
+        * @param string $workspaceSwapMode
+        * @return void
+        */
+       protected function setWorkspaceSwapMode($workspaceSwapMode = 'any') {
+               $this->getBackendUser()->userTS['options.']['workspaces.']['swapMode'] = $workspaceSwapMode;
+       }
+
+       /**
+        * Sets the User TSconfig property options.workspaces.changeStageMode.
+        *
+        * @param string $workspaceChangeStateMode
+        * @return void
+        */
+       protected function setWorkspaceChangeStageMode($workspaceChangeStateMode = 'any') {
+               $this->getBackendUser()->userTS['options.']['workspaces.']['changeStageMode'] = $workspaceChangeStateMode;
+       }
+
+       public function getVersionTceMainCommandMapCallback(DataHandler $tceMain, array $commandMap) {
+               $this->versionTceMainCommandMap = GeneralUtility::makeInstance('TYPO3\\CMS\\Version\\DataHandler\\CommandMap', $this->versionTceMainHookMock, $tceMain, $commandMap);
+               return $this->versionTceMainCommandMap;
+       }
+
+       /**
+        * @return \TYPO3\CMS\Version\DataHandler\CommandMap
+        */
+       protected function getCommandMap() {
+               return $this->versionTceMainCommandMap;
+       }
+}
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/OneToNCSV.xml b/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/OneToNCSV.xml
new file mode 100644 (file)
index 0000000..575c3ed
--- /dev/null
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<dataset>
+       <!-- Tabelle tx_irretutorial_1ncsv_hotel -->
+       <tx_irretutorial_1ncsv_hotel>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Wellness Well-Being Hotel Rosengarten</title>
+               <offers>1,2</offers>
+       </tx_irretutorial_1ncsv_hotel>
+       <!-- Tabelle tx_irretutorial_1ncsv_offer -->
+       <tx_irretutorial_1ncsv_offer>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>&quot;Experience it&quot; Week</title>
+               <prices>3</prices>
+       </tx_irretutorial_1ncsv_offer>
+       <tx_irretutorial_1ncsv_offer>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>128</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Wellness &amp; Beauty Week</title>
+               <prices>1,2</prices>
+       </tx_irretutorial_1ncsv_offer>
+       <!-- Tabelle tx_irretutorial_1ncsv_price -->
+       <tx_irretutorial_1ncsv_price>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Season from January-June (price per day)</title>
+               <price>200.00</price>
+       </tx_irretutorial_1ncsv_price>
+       <tx_irretutorial_1ncsv_price>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>128</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Season from July-December (price per day)</title>
+               <price>300.00</price>
+       </tx_irretutorial_1ncsv_price>
+       <tx_irretutorial_1ncsv_price>
+               <uid>3</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>64</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Season from January-December (price per day)</title>
+               <price>350.00</price>
+       </tx_irretutorial_1ncsv_price>
+</dataset>
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/OneToNForeignField.xml b/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/OneToNForeignField.xml
new file mode 100644 (file)
index 0000000..d62e95e
--- /dev/null
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<dataset>
+       <!-- Tabelle tx_irretutorial_1nff_hotel -->
+       <tx_irretutorial_1nff_hotel>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Wellness Well-Being Hotel Rosengarten</title>
+               <offers>2</offers>
+       </tx_irretutorial_1nff_hotel>
+       <tx_irretutorial_1nff_hotel>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>256</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <title>Wellness Well-Being Hotel Rosengarten</title>
+               <offers>0</offers>
+               <parentid>1</parentid>
+               <parenttable>pages</parenttable>
+       </tx_irretutorial_1nff_hotel>
+       <!-- Tabelle tx_irretutorial_1nff_offer -->
+       <tx_irretutorial_1nff_offer>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>1</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <parentid>1</parentid>
+               <parenttable>tx_irretutorial_1nff_hotel</parenttable>
+               <title>Wellness &amp; Beauty Week</title>
+               <prices>1</prices>
+       </tx_irretutorial_1nff_offer>
+       <tx_irretutorial_1nff_offer>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>2</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <parentid>1</parentid>
+               <parenttable>tx_irretutorial_1nff_hotel</parenttable>
+               <title>&quot;Experience it&quot; Week</title>
+               <prices>2</prices>
+       </tx_irretutorial_1nff_offer>
+       <!-- Tabelle tx_irretutorial_1nff_price -->
+       <tx_irretutorial_1nff_price>
+               <uid>1</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>1</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <parentid>2</parentid>
+               <parenttable>tx_irretutorial_1nff_offer</parenttable>
+               <title>Season from July-December (price per day)</title>
+               <price>300.00</price>
+       </tx_irretutorial_1nff_price>
+       <tx_irretutorial_1nff_price>
+               <uid>2</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>2</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <parentid>2</parentid>
+               <parenttable>tx_irretutorial_1nff_offer</parenttable>
+               <title>Season from January-June (price per day)</title>
+               <price>200.00</price>
+       </tx_irretutorial_1nff_price>
+       <tx_irretutorial_1nff_price>
+               <uid>3</uid>
+               <pid>1</pid>
+               <tstamp>1250000000</tstamp>
+               <sys_language_uid>0</sys_language_uid>
+               <l18n_parent>0</l18n_parent>
+               <sorting>1</sorting>
+               <deleted>0</deleted>
+               <hidden>0</hidden>
+               <t3ver_oid>0</t3ver_oid>
+               <t3ver_id>0</t3ver_id>
+               <t3ver_wsid>0</t3ver_wsid>
+               <t3ver_label></t3ver_label>
+               <t3ver_state>0</t3ver_state>
+               <t3ver_stage>0</t3ver_stage>
+               <t3ver_count>0</t3ver_count>
+               <t3ver_tstamp>0</t3ver_tstamp>
+               <t3ver_move_id>0</t3ver_move_id>
+               <t3_origuid>0</t3_origuid>
+               <parentid>1</parentid>
+               <parenttable>tx_irretutorial_1nff_offer</parenttable>
+               <title>Season from January-December (price per day)</title>
+               <price>350.00</price>
+       </tx_irretutorial_1nff_price>
+</dataset>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/InlineRelationalRecordEditing/MToNMMTest.php
new file mode 100644 (file)
index 0000000..793fc16
--- /dev/null
@@ -0,0 +1,213 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\InlineRelationalRecordEditing;
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2013 Oliver Hader <oliver@typo3.org>
+*  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!
+***************************************************************/
+
+require_once(dirname(__FILE__). '/AbstractTestCase.php');
+
+/**
+ * Test case for m:n MM relations
+ *
+ */
+class MToNMMTest extends AbstractTestCase {
+       const TABLE_Hotel = 'tx_irretutorial_mnmmasym_hotel';
+       const TABLE_Offer = 'tx_irretutorial_mnmmasym_offer';
+       const TABLE_Price = 'tx_irretutorial_mnmmasym_price';
+       const TABLE_Relation_Hotel_Offer = 'tx_irretutorial_mnmmasym_hotel_offer_rel';
+       const TABLE_Relation_Offer_Price = 'tx_irretutorial_mnmmasym_offer_price_rel';
+
+       const FIELD_Hotel_Offers = 'offers';
+       const FIELD_Offer_Hotels = 'hotels';
+       const FIELD_Offer_Prices = 'prices';
+       const FIELD_Price_Offers = 'offers';
+
+       /**
+        * @var array
+        */
+       protected $structure = array(
+               self::TABLE_Hotel => array(self::FIELD_Hotel_Offers),
+               self::TABLE_Offer => array(self::FIELD_Offer_Hotels, self::FIELD_Offer_Prices),
+               self::TABLE_Price => array(self::FIELD_Price_Offers),
+       );
+
+       /**
+        * Sets up this test case.
+        *
+        * @return void
+        */
+       public function setUp() {
+               parent::setUp();
+
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/DataHandling/InlineRelationalRecordEditing/Fixtures/MToNMMAsymmetric.xml');
+       }
+
+       /**
+        * @test
+        */
+       public function isManyToManyRelationUpdatedForVersionedRecordsOnLocalSide() {
+               $this->markTestSkipped('This test is failing - the Core needs to be fixed');
+               $editingElements = array(
+                       self::TABLE_Hotel => 1,
+               );
+               $tceMain = $this->simulateEditing($editingElements);
+               $versionedHotelId = $tceMain->getAutoVersionId(self::TABLE_Hotel, 1);
+
+               $this->assertGreaterThan(1, $versionedHotelId);
+               $this->assertArrayHasValues(
+                       array(
+                               $versionedHotelId . '->' . '1',
+                               $versionedHotelId . '->' . '2',
+                       ),
+                       $this->getManyToManyRelations(self::TABLE_Relation_Hotel_Offer)
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function isManyToManyRelationUpdatedForVersionedRecordsOnForeignSide() {
+               $this->markTestSkipped('This test is failing - the Core needs to be fixed');
+               $editingElements = array(
+                       self::TABLE_Offer => 1,
+               );
+
+               $tceMain = $this->simulateEditing($editingElements);
+               $versionedOfferId = $tceMain->getAutoVersionId(self::TABLE_Offer, 1);
+
+               $this->assertGreaterThan(1, $versionedOfferId);
+               $this->assertArrayHasValues(
+                       array(
+                               '1' . '->' . $versionedOfferId,
+                               '1' . '->' . '2',
+                       ),
+                       $this->getManyToManyRelations(self::TABLE_Relation_Hotel_Offer)
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function isManyToManyRelationUpdatedForVersionedRecordsOnBothSides() {
+               $this->markTestSkipped('This test is failing - the Core needs to be fixed');
+               $editingElements = array(
+                       self::TABLE_Hotel => 1,
+                       self::TABLE_Offer => 1,
+               );
+
+               $tceMain = $this->simulateEditing($editingElements);
+               $versionedHotelId = $tceMain->getAutoVersionId(self::TABLE_Hotel, 1);
+               $versionedOfferId = $tceMain->getAutoVersionId(self::TABLE_Offer, 1);
+
+               $this->assertGreaterThan(1, $versionedHotelId);
+               $this->assertGreaterThan(2, $versionedOfferId);
+               $this->assertArrayHasValues(
+                       array(
+                               $versionedHotelId . '->' . $versionedOfferId,
+                               $versionedHotelId . '->' . '2',
+                       ),
+                       $this->getManyToManyRelations(self::TABLE_Relation_Hotel_Offer)
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function isManyToManyRelationUpdatedForVersionedRecordsOnBothSidesWithDifferentRelations() {
+               $this->markTestSkipped('This test is failing - the Core needs to be fixed');
+
+               $editingElements = array(
+                       self::TABLE_Hotel => 1,
+                       self::TABLE_Offer => 1,
+               );
+
+               $modificationStructure = array(
+                       self::TABLE_Hotel => array(
+                               1 => array(
+                                       self::FIELD_Hotel_Offers => '1',
+                               ),
+                       ),
+               );
+
+               $tceMain = $this->simulateEditing($editingElements);
+               $versionedHotelId = $tceMain->getAutoVersionId(self::TABLE_Hotel, 1);
+               $versionedOfferId = $tceMain->getAutoVersionId(self::TABLE_Offer, 1);
+
+               $tceMain = $this->simulateEditingByStructure($modificationStructure);
+               $relations = $this->getManyToManyRelations(self::TABLE_Relation_Hotel_Offer);
+
+               $this->assertGreaterThan(1, $versionedHotelId);
+               $this->assertGreaterThan(2, $versionedOfferId);
+               $this->assertArrayHasValues(
+                       array(
+                               $versionedHotelId . '->' . $versionedOfferId,
+                       ),
+                       $relations
+               );
+
+               $this->assertArrayDoesNotHaveValues(
+                       array(
+                               $versionedHotelId . '->' . '2',
+                       ),
+                       $relations
+               );
+       }
+
+       /**
+        * @param string $tableName
+        * @return array
+        */
+       protected function getManyToManyRelations($tableName) {
+               $relations = array();
+
+               foreach ($this->getAllRecords($tableName) as $relation) {
+                       $relations[] = $relation['uid_local'] . '->' . $relation['uid_foreign'];
+               }
+
+               return $relations;
+       }
+
+       /**
+        * @param array $expected
+        * @param array $actual
+        */
+       protected function assertArrayHasValues(array $expected, array $actual) {
+               $differences = array_diff($expected, $actual);
+
+               if (count($differences) > 0) {
+                       $this->fail('Unmatched values: ' . implode(', ', $differences));
+               }
+       }
+
+       /**
+        * @param array $unexpected
+        * @param array $actual
+        */
+       protected function assertArrayDoesNotHaveValues(array $unexpected, array $actual) {
+               $intersection = array_intersect($unexpected, $actual);
+
+               if (count($intersection) > 0) {
+&nb