From 4770e0b787682dd5d3f18326834604dad370604b Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Mon, 13 Nov 2017 20:33:53 +0100
Subject: [PATCH] [BUGFIX] Ensure "pid" and "parentid" of pages - inline fields
 are correct

When doing translations with pages and inline elements (e.g. pages.media),
there is an inconsistency when an additional inline element is added to the
TRANSLATED page (e.g. language=1).

Current (wrong) when adding a translation to a page
- localized IRRE children get pid = default page ID (correct)
- localized IRRE children only localization get parentid = default page ID (should be translated page ID)

Current (wrong) behaviour when adding a IRRE child only available in a translation:
- parentid gets localized page => correct
- pid gets set to localized page => must be default language

The patch corrects this behaviour by always set
- the relation (parentid) to the localized page ID
- the page ID (pid) to the default language page ID

Additionally, when adding an Inline element (IRRE) via AJAX
on page properties, the PID gets resolved correctly to be sent
to DataHandler.

Resolves: #82983
Releases: master
Change-Id: Id8bf39524ee608acf452e2b7103087d4299c1e28
Reviewed-on: https://review.typo3.org/54632
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Daniel Gorges <daniel.gorges@b13.de>
Tested-by: Daniel Gorges <daniel.gorges@b13.de>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
---
 .../Form/FormDataProvider/TcaInline.php        |  4 ++++
 .../core/Classes/DataHandling/DataHandler.php  | 13 ++++++++++++-
 .../ForeignField/AbstractActionTestCase.php    | 18 ++++++++++++++++++
 .../IRRE/ForeignField/Modify/ActionTest.php    | 18 ++++++++++++++++++
 ...hSynchronizationAndCustomLocalizedHotel.csv | 15 +++++++++++++++
 5 files changed, 67 insertions(+), 1 deletion(-)
 create mode 100644 typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWithSynchronizationAndCustomLocalizedHotel.csv

diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php
index 18401cfb6885..6fc3d6dd50e8 100644
--- a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php
+++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php
@@ -106,6 +106,10 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid
             } else {
                 $pid = $row['pid'];
             }
+            $pageRecord = BackendUtility::getRecord('pages', $pid);
+            if ((int)$pageRecord['l10n_parent'] > 0) {
+                $pid = (int)$pageRecord['l10n_parent'];
+            }
             $result['inlineFirstPid'] = (int)$pid;
         }
         return $result;
diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
index 53c95637e4bf..90446007b082 100644
--- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php
+++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
@@ -1316,6 +1316,11 @@ class DataHandler implements LoggerAwareInterface
         $sortRow = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
         // Points to a page on which to insert the element, possibly in the top of the page
         if ($pid >= 0) {
+            // Ensure that the "pid" is not a translated page ID, but the default page ID
+            $localizationParent = $this->recordInfo('pages', $pid, 'l10n_parent');
+            if ($localizationParent['l10n_parent'] > 0) {
+                $pid = (int)$localizationParent['l10n_parent'];
+            }
             // The numerical pid is inserted in the data array
             $fieldArray['pid'] = $pid;
             // If this table is sorted we better find the top sorting number
@@ -1332,7 +1337,13 @@ class DataHandler implements LoggerAwareInterface
         } else {
             // Here we fetch the PID of the record that we point to
             $record = $this->recordInfo($table, abs($pid), 'pid');
-            $fieldArray['pid'] = $record['pid'];
+            $pid = $record['pid'];
+            // Ensure that the "pid" is not a translated page ID, but the default page ID
+            $localizationParent = $this->recordInfo('pages', $pid, 'l10n_parent');
+            if ($localizationParent['l10n_parent'] > 0) {
+                $pid = (int)$localizationParent['l10n_parent'];
+            }
+            $fieldArray['pid'] = $pid;
         }
         return $fieldArray;
     }
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php
index caf26096f77d..c4599ca0bea1 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php
@@ -493,4 +493,22 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
         $newTableIds = $this->actionService->copyRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_PageIdTarget);
         $this->recordIds['newPageId'] = $newTableIds[self::TABLE_Page][self::VALUE_PageId];
     }
+
+    public function localizePageWithSynchronizationAndCustomLocalizedHotel()
+    {
+        // in these test cases we expect new pages not to be hidden in order to
+        // verify proper overlaying behavior during the frontend render process
+        $GLOBALS['TCA'][self::TABLE_Page]['columns']['hidden']['config']['default'] = 0;
+        $GLOBALS['TCA'][self::TABLE_Page]['columns'][self::FIELD_PageHotel]['config']['behaviour']['allowLanguageSynchronization'] = true;
+        $localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_LanguageId);
+        $this->recordIds['localizedPageId'] = $localizedTableIds[self::TABLE_Page][self::VALUE_PageId];
+        // Using "localized page ID" on purpose because BE editing uses a "page" record and data handler
+        $this->actionService->modifyRecords(
+            $this->recordIds['localizedPageId'],
+            [
+                self::TABLE_Page => ['uid' => $this->recordIds['localizedPageId'], self::FIELD_PageHotel => '6,__nextUid'],
+                self::TABLE_Hotel => ['uid' => '__NEW', 'sys_language_uid' => self::VALUE_LanguageId, 'title' => 'Hotel in dansk page only'],
+            ]
+        );
+    }
 }
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/ActionTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/ActionTest.php
index 5b60ba9d8f7a..626e87e2d7d5 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/ActionTest.php
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/ActionTest.php
@@ -547,6 +547,24 @@ class ActionTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\IRRE\Fore
             ->setTable(self::TABLE_Hotel)->setField('title')->setValues('[Translate to Dansk:] Hotel #0'));
     }
 
+    /**
+     * Checks for a page having a IRRE record. The page is then localized and
+     * an IRRE record is then added to the localized page
+     *
+     * @test
+     * @see DataSet/localizePageWithSynchronizationAndCustomLocalizedHotel.csv
+     */
+    public function localizePageWithSynchronizationAndCustomLocalizedHotel()
+    {
+        parent::localizePageWithSynchronizationAndCustomLocalizedHotel();
+        $this->assertAssertionDataSet('localizePageWithSynchronizationAndCustomLocalizedHotel');
+
+        $responseSections = $this->getFrontendResponse(self::VALUE_PageId, self::VALUE_LanguageId)->getResponseSections();
+        $this->assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
+            ->setRecordIdentifier(self::TABLE_Page . ':' . self::VALUE_PageId)->setRecordField(self::FIELD_PageHotel)
+            ->setTable(self::TABLE_Hotel)->setField('title')->setValues('[Translate to Dansk:] Hotel #0'));
+    }
+
     /**
      * @test
      * @see DataSet/localizePageAddMonoglotHotelChildNCopyPageWSynchronization.csv
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWithSynchronizationAndCustomLocalizedHotel.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWithSynchronizationAndCustomLocalizedHotel.csv
new file mode 100644
index 000000000000..57676d2e07d3
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWithSynchronizationAndCustomLocalizedHotel.csv
@@ -0,0 +1,15 @@
+pages
+,uid,pid,sorting,deleted,sys_language_uid,l10n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,tx_irretutorial_hotels,l10n_state
+,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest,0,
+,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest,0,
+,89,88,256,0,0,0,0,0,0,0,0,0,Relations,1,
+,90,88,512,0,0,0,0,0,0,0,0,0,Target,0,
+,91,88,256,0,1,89,0,0,0,0,0,0,"[Translate to Dansk:] Relations",2,"{""url"":""parent"",""lastUpdated"":""parent"",""newUntil"":""parent"",""no_search"":""parent"",""shortcut"":""parent"",""shortcut_mode"":""parent"",""author"":""parent"",""author_email"":""parent"",""media"":""parent"",""tx_irretutorial_hotels"":""parent""}"
+tx_irretutorial_1nff_hotel
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,parentid,parenttable,parentidentifier,offers
+,2,89,512,0,0,0,0,0,0,0,0,0,"Hotel #0",89,pages,,0
+,3,89,1024,0,0,0,0,0,0,0,0,0,"Hotel #1",297,tt_content,,2
+,4,89,1536,0,0,0,0,0,0,0,0,0,"Hotel #2",297,tt_content,,1
+,5,89,1280,0,0,0,0,0,0,0,0,0,"Hotel #1",298,tt_content,,1
+,6,89,1,0,1,2,2,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",91,pages,,0
+,7,89,2,0,1,0,0,0,0,0,0,0,"Hotel in dansk page only",91,pages,,0
-- 
GitLab