[FOLLOWUP][TASK] Enhance DataHandler translation and synchronization handling 84/51784/5
authorOliver Hader <oliver@typo3.org>
Tue, 21 Feb 2017 20:52:20 +0000 (21:52 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Mon, 27 Feb 2017 13:00:02 +0000 (14:00 +0100)
Copying a page translation having an 1:n monoglot inline relation leads
to an SQL error which is silently put to sys_log in DataHandler. Besides
that, the inline children are superfluously duplicated since there is no
connection between those copied records anymore.

Resolves: #79856
Releases: master
Change-Id: Ife5cfdea1c1d9dff764ea3d28e0a35a83d5919e1
Reviewed-on: https://review.typo3.org/51784
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
typo3/sysext/core/Classes/DataHandling/Localization/DataMapProcessor.php
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/ActionTest.php
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageAddMonoglotHotelChildNCopyPageWSynchronization.csv [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/ActionTest.php
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeContentWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPage.csv [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPageWSynchronization.csv [new file with mode: 0644]

index a2e2b57..f26f031 100644 (file)
@@ -52,6 +52,11 @@ class DataMapProcessor
     protected $dataMap = [];
 
     /**
+     * @var array
+     */
+    protected $sanitizationMap = [];
+
+    /**
      * @var BackendUserAuthentication
      */
     protected $backendUser;
@@ -221,10 +226,17 @@ class DataMapProcessor
             $this->getFieldNamesForItemScope($item, DataMapItem::SCOPE_PARENT, !$item->isNew()),
             $this->getFieldNamesForItemScope($item, DataMapItem::SCOPE_SOURCE, !$item->isNew())
         );
+
+        $fieldNameMap = array_combine($fieldNames, $fieldNames);
+        // separate fields, that are submitted in data-map, but not defined as custom
+        $this->sanitizationMap[$item->getTableName()][$item->getId()] = array_intersect_key(
+            $this->dataMap[$item->getTableName()][$item->getId()],
+            $fieldNameMap
+        );
         // remove fields, that are submitted in data-map, but not defined as custom
         $this->dataMap[$item->getTableName()][$item->getId()] = array_diff_key(
             $this->dataMap[$item->getTableName()][$item->getId()],
-            array_combine($fieldNames, $fieldNames)
+            $fieldNameMap
         );
     }
 
@@ -489,6 +501,22 @@ class DataMapProcessor
             );
             return;
         }
+        // In case only missing elements shall be created, re-use previously sanitized
+        // values IF child table cannot be translated, the relation parent item is new
+        // and the count of missing relations equals the count of previously sanitized
+        // relations. This is caused during copy processes, when the child relations
+        // already have been cloned in DataHandler::copyRecord_procBasedOnFieldType()
+        // without the possibility to resolve the initial connections at this point.
+        // Otherwise child relations would superfluously be duplicated again here.
+        // @todo Invalid manually injected child relations cannot be determined here
+        $sanitizedValue = $this->sanitizationMap[$item->getTableName()][$item->getId()][$fieldName] ?? null;
+        if (!empty($missingAncestorIds) && $item->isNew()
+            && $sanitizedValue !== null && !$isTranslatable
+            && count(GeneralUtility::trimExplode(',', $sanitizedValue)) === count($missingAncestorIds)
+        ) {
+            $this->dataMap[$item->getTableName()][$item->getId()][$fieldName] = $sanitizedValue;
+            return;
+        }
 
         $localCommandMap = [];
         foreach ($removeIds as $removeId) {
@@ -753,7 +781,7 @@ class DataMapProcessor
         // fetch by origin dependency ("copied from")
         } elseif (!empty($fieldNames['origin'])) {
             $predicates = [
-                $queryBuilder->expr()->eq(
+                $queryBuilder->expr()->in(
                     $fieldNames['origin'],
                     $idsParameter
                 )
index a8cde50..71f47a7 100644 (file)
@@ -606,4 +606,20 @@ class ActionTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\IRRE\Fore
             ->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
+     */
+    public function localizePageAddMonoglotHotelChildAndCopyPageWithLanguageSynchronization()
+    {
+        parent::localizePageAndAddMonoglotHotelChildWithLanguageSynchronization();
+        parent::copyPage();
+        $this->assertAssertionDataSet('localizePageAddMonoglotHotelChildNCopyPageWSynchronization');
+
+        $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('Hotel #0', 'Hotel #007'));
+    }
 }
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageAddMonoglotHotelChildNCopyPageWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageAddMonoglotHotelChildNCopyPageWSynchronization.csv
new file mode 100644 (file)
index 0000000..12f9156
--- /dev/null
@@ -0,0 +1,59 @@
+pages
+,uid,pid,sorting,deleted,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,tx_irretutorial_hotels
+,1,0,256,0,0,0,0,0,0,0,FunctionalTest,0
+,88,1,256,0,0,0,0,0,0,0,DataHandlerTest,0
+,89,88,256,0,0,0,0,0,0,0,Relations,2
+,90,88,512,0,0,0,0,0,0,0,Target,0
+,91,90,256,0,89,0,0,0,0,0,Relations,2
+pages_language_overlay
+,uid,pid,deleted,sys_language_uid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,title,tx_irretutorial_hotels,l10n_state
+,1,89,0,1,0,0,0,0,"[Translate to Dansk:] Relations",2,"{""tx_irretutorial_hotels"":""parent""}"
+,2,91,0,1,0,0,0,0,"[Translate to Dansk:] Relations",2,"{""tx_irretutorial_hotels"":""parent""}"
+tt_content
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header,tx_irretutorial_1nff_hotels
+,297,89,256,0,0,0,0,0,0,0,0,0,"Regular Element #1",2
+,298,89,512,0,0,0,0,0,0,0,0,0,"Regular Element #2",1
+,299,91,256,0,0,0,298,0,0,0,0,0,"Regular Element #2",1
+,300,91,128,0,0,0,297,0,0,0,0,0,"Regular Element #1",2
+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,1,0,0,0,0,0,0,0,0,0,"Hotel #0",89,pages,,0
+,3,89,1280,0,0,0,0,0,0,0,0,0,"Hotel #1",297,tt_content,,2
+,4,89,1792,0,0,0,0,0,0,0,0,0,"Hotel #2",297,tt_content,,1
+,5,89,1536,0,0,0,0,0,0,0,0,0,"Hotel #1",298,tt_content,,1
+,6,89,1,0,0,0,2,0,0,0,0,0,"Hotel #0",1,pages_language_overlay,,0
+,7,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",89,pages,,0
+,8,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",1,pages_language_overlay,,0
+,9,91,1,0,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,0
+,10,91,2,0,0,0,7,0,0,0,0,0,"Hotel #007",91,pages,,0
+,11,91,1,0,0,0,6,0,0,0,0,0,"Hotel #0",2,pages_language_overlay,,0
+,12,91,2,0,0,0,8,0,0,0,0,0,"Hotel #007",2,pages_language_overlay,,0
+,13,91,1,0,0,0,5,0,0,0,0,0,"Hotel #1",299,tt_content,,1
+,14,91,1,0,0,0,3,0,0,0,0,0,"Hotel #1",300,tt_content,,2
+,15,91,2,0,0,0,4,0,0,0,0,0,"Hotel #2",300,tt_content,,1
+tx_irretutorial_1nff_offer
+,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,prices
+,5,89,1,0,0,0,0,0,0,0,0,0,"Offer #1.1",3,tx_irretutorial_1nff_hotel,,3
+,6,89,2,0,0,0,0,0,0,0,0,0,"Offer #1.2",3,tx_irretutorial_1nff_hotel,,2
+,7,89,1,0,0,0,0,0,0,0,0,0,"Offer #2.1",4,tx_irretutorial_1nff_hotel,,1
+,8,89,1,0,0,0,0,0,0,0,0,0,"Offer #1.1",5,tx_irretutorial_1nff_hotel,,1
+,9,91,1,0,0,0,8,0,0,0,0,0,"Offer #1.1",13,tx_irretutorial_1nff_hotel,,1
+,10,91,1,0,0,0,5,0,0,0,0,0,"Offer #1.1",14,tx_irretutorial_1nff_hotel,,3
+,11,91,2,0,0,0,6,0,0,0,0,0,"Offer #1.2",14,tx_irretutorial_1nff_hotel,,2
+,12,91,1,0,0,0,7,0,0,0,0,0,"Offer #2.1",15,tx_irretutorial_1nff_hotel,,1
+tx_irretutorial_1nff_price
+,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
+,7,89,1,0,0,0,0,0,0,0,0,0,"Price #1.1.1",5,tx_irretutorial_1nff_offer,
+,8,89,2,0,0,0,0,0,0,0,0,0,"Price #1.1.2",5,tx_irretutorial_1nff_offer,
+,9,89,3,0,0,0,0,0,0,0,0,0,"Price #1.1.3",5,tx_irretutorial_1nff_offer,
+,10,89,1,0,0,0,0,0,0,0,0,0,"Price #1.2.1",6,tx_irretutorial_1nff_offer,
+,11,89,2,0,0,0,0,0,0,0,0,0,"Price #1.2.2",6,tx_irretutorial_1nff_offer,
+,12,89,1,0,0,0,0,0,0,0,0,0,"Price #2.1.1",7,tx_irretutorial_1nff_offer,
+,13,89,1,0,0,0,0,0,0,0,0,0,"Price #1.1.1",8,tx_irretutorial_1nff_offer,
+,14,91,1,0,0,0,13,0,0,0,0,0,"Price #1.1.1",9,tx_irretutorial_1nff_offer,
+,15,91,1,0,0,0,7,0,0,0,0,0,"Price #1.1.1",10,tx_irretutorial_1nff_offer,
+,16,91,2,0,0,0,8,0,0,0,0,0,"Price #1.1.2",10,tx_irretutorial_1nff_offer,
+,17,91,3,0,0,0,9,0,0,0,0,0,"Price #1.1.3",10,tx_irretutorial_1nff_offer,
+,18,91,1,0,0,0,10,0,0,0,0,0,"Price #1.2.1",11,tx_irretutorial_1nff_offer,
+,19,91,2,0,0,0,11,0,0,0,0,0,"Price #1.2.2",11,tx_irretutorial_1nff_offer,
+,20,91,1,0,0,0,12,0,0,0,0,0,"Price #2.1.1",12,tx_irretutorial_1nff_offer,
index c5e9f5b..ca0219b 100644 (file)
@@ -380,6 +380,21 @@ class ActionTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\Regular\A
 
     /**
      * @test
+     * @see DataSet/localizeNCopyPage.csv
+     */
+    public function localizeAndCopyPage()
+    {
+        parent::localizePage();
+        parent::copyPage();
+        $this->assertAssertionDataSet('localizeNCopyPage');
+
+        $responseSections = $this->getFrontendResponse($this->recordIds['newPageId'], self::VALUE_LanguageId)->getResponseSections();
+        $this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
+            ->setTable(self::TABLE_Page)->setField('title')->setValues('[Translate to Dansk:] Relations'));
+    }
+
+    /**
+     * @test
      * @see DataSet/localizePageWSynchronization.csv
      */
     public function localizePageWithLanguageSynchronization()
@@ -394,6 +409,21 @@ class ActionTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\Regular\A
 
     /**
      * @test
+     * @see DataSet/localizeNCopyPageWSynchronization.csv
+     */
+    public function localizeAndCopyPageWithLanguageSynchronization()
+    {
+        parent::localizePageWithLanguageSynchronization();
+        parent::copyPage();
+        $this->assertAssertionDataSet('localizeNCopyPageWSynchronization');
+
+        $responseSections = $this->getFrontendResponse(self::VALUE_PageId, self::VALUE_LanguageId)->getResponseSections();
+        $this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
+            ->setTable(self::TABLE_Page)->setField('title')->setValues('Testing #1'));
+    }
+
+    /**
+     * @test
      * @see DataSet/changePageRecordSorting.csv
      */
     public function changePageSorting()
index 741cfaa..4d65cc9 100644 (file)
@@ -1,9 +1,9 @@
-tt_content,,,,,,,,,,,,,,
-,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l10n_source,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header
-,297,89,256,0,0,0,0,0,0,0,0,0,0,Regular Element #1
-,298,89,512,0,0,0,0,0,0,0,0,0,0,Testing #1
-,299,89,768,0,0,0,0,0,0,0,0,0,0,Regular Element #3
-,300,89,1024,0,1,299,299,299,0,0,0,0,0,[Translate to Dansk:] Regular Element #3
-,301,89,384,0,1,297,297,297,0,0,0,0,0,[Translate to Dansk:] Regular Element #1
-,302,89,448,0,2,297,301,301,0,0,0,0,0,[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1
-,303,89,416,0,1,298,298,298,0,0,0,0,0,Testing #1
+tt_content
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l10n_source,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header,l10n_state
+,297,89,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #1",
+,298,89,512,0,0,0,0,0,0,0,0,0,0,"Testing #1",\NULL
+,299,89,768,0,0,0,0,0,0,0,0,0,0,"Regular Element #3",
+,300,89,1024,0,1,299,299,299,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3",
+,301,89,384,0,1,297,297,297,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1",
+,302,89,448,0,2,297,301,301,0,0,0,0,0,"[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1",
+,303,89,416,0,1,298,298,298,0,0,0,0,0,"Testing #1","{""header"":""parent""}"
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPage.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPage.csv
new file mode 100644 (file)
index 0000000..a28e910
--- /dev/null
@@ -0,0 +1,25 @@
+pages
+,uid,pid,sorting,deleted,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title
+,1,0,256,0,0,0,0,0,0,0,FunctionalTest
+,88,1,256,0,0,0,0,0,0,0,DataHandlerTest
+,89,88,256,0,0,0,0,0,0,0,Relations
+,90,88,512,0,0,0,0,0,0,0,Target
+,91,90,256,0,89,0,0,0,0,0,Relations
+pages_language_overlay
+,uid,pid,deleted,sys_language_uid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,title
+,1,89,0,1,0,0,0,0,"[Translate to Dansk:] Relations"
+,2,91,0,1,0,0,0,0,"[Translate to Dansk:] Relations"
+tt_content
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l10n_source,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header
+,297,89,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #1"
+,298,89,512,0,0,0,0,0,0,0,0,0,0,"Regular Element #2"
+,299,89,768,0,0,0,0,0,0,0,0,0,0,"Regular Element #3"
+,300,89,1024,0,1,299,299,299,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3"
+,301,89,384,0,1,297,297,297,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1"
+,302,89,448,0,2,297,301,301,0,0,0,0,0,"[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1"
+,303,91,256,0,0,0,0,299,0,0,0,0,0,"Regular Element #3"
+,304,91,128,0,1,303,303,300,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3"
+,305,91,64,0,0,0,0,298,0,0,0,0,0,"Regular Element #2"
+,306,91,32,0,0,0,0,297,0,0,0,0,0,"Regular Element #1"
+,307,91,16,0,1,306,306,301,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1"
+,308,91,8,0,2,306,307,302,0,0,0,0,0,"[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1"
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPageWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPageWSynchronization.csv
new file mode 100644 (file)
index 0000000..fbd4291
--- /dev/null
@@ -0,0 +1,25 @@
+pages
+,uid,pid,sorting,deleted,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title
+,1,0,256,0,0,0,0,0,0,0,FunctionalTest
+,88,1,256,0,0,0,0,0,0,0,DataHandlerTest
+,89,88,256,0,0,0,0,0,0,0,"Testing #1"
+,90,88,512,0,0,0,0,0,0,0,Target
+,91,90,256,0,89,0,0,0,0,0,"Testing #1"
+pages_language_overlay
+,uid,pid,deleted,sys_language_uid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,title,l10n_state
+,1,89,0,1,0,0,0,0,"Testing #1","{""title"":""parent""}"
+,2,91,0,1,0,0,0,0,"Testing #1","{""title"":""parent""}"
+tt_content
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l10n_source,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header
+,297,89,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #1"
+,298,89,512,0,0,0,0,0,0,0,0,0,0,"Regular Element #2"
+,299,89,768,0,0,0,0,0,0,0,0,0,0,"Regular Element #3"
+,300,89,1024,0,1,299,299,299,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3"
+,301,89,384,0,1,297,297,297,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1"
+,302,89,448,0,2,297,301,301,0,0,0,0,0,"[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1"
+,303,91,256,0,0,0,0,299,0,0,0,0,0,"Regular Element #3"
+,304,91,128,0,1,303,303,300,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3"
+,305,91,64,0,0,0,0,298,0,0,0,0,0,"Regular Element #2"
+,306,91,32,0,0,0,0,297,0,0,0,0,0,"Regular Element #1"
+,307,91,16,0,1,306,306,301,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1"
+,308,91,8,0,2,306,307,302,0,0,0,0,0,"[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1"