From dab027bd42ebaf535286acfff88369948811b8be Mon Sep 17 00:00:00 2001
From: Xavier Perseguers <xavier@typo3.org>
Date: Wed, 13 May 2020 11:52:20 +0200
Subject: [PATCH] [BUGFIX] Exclude current record when checking slug's
 uniqueness

The current record constraint was forgotten in the
implementation of uniqueInTable and is now added.

Resolves: #91378
Related: #91235
Releases: master, 9.5
Change-Id: Ie7862b22a06996a9d7ca484a01d7a1859c8f7276
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64482
Tested-by: Helmut Hummel <typo3@helhum.io>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../core/Classes/DataHandling/SlugHelper.php  |  2 +
 .../DataSet/TestSlugUniqueNewRecordResult.csv |  6 ++
 ...TestSlugUniqueWithDeduplicatedSlugBase.csv |  5 ++
 .../DataHandler/SlugUniqueTest.php            | 57 ++++++++++++++++++-
 4 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueNewRecordResult.csv
 create mode 100644 typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueWithDeduplicatedSlugBase.csv

diff --git a/typo3/sysext/core/Classes/DataHandling/SlugHelper.php b/typo3/sysext/core/Classes/DataHandling/SlugHelper.php
index 6d13acb511c6..77aee4f2a7f2 100644
--- a/typo3/sysext/core/Classes/DataHandling/SlugHelper.php
+++ b/typo3/sysext/core/Classes/DataHandling/SlugHelper.php
@@ -335,10 +335,12 @@ class SlugHelper
      */
     public function isUniqueInTable(string $slug, RecordState $state): bool
     {
+        $recordId = $state->getSubject()->getIdentifier();
         $languageId = $state->getContext()->getLanguageId();
 
         $queryBuilder = $this->createPreparedQueryBuilder();
         $this->applySlugConstraint($queryBuilder, $slug);
+        $this->applyRecordConstraint($queryBuilder, $recordId);
         $this->applyLanguageConstraint($queryBuilder, $languageId);
         $this->applyWorkspaceConstraint($queryBuilder, $state);
         $statement = $queryBuilder->execute();
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueNewRecordResult.csv b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueNewRecordResult.csv
new file mode 100644
index 000000000000..0ee4a65d1b74
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueNewRecordResult.csv
@@ -0,0 +1,6 @@
+"pages",,,,
+,"uid","pid","title","slug"
+,1,0,"root","/"
+,2,1,"Page One","/page-one"
+,3,1,"Page Two","/page-two"
+,4,1,"Page Two","/page-two-1"
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueWithDeduplicatedSlugBase.csv b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueWithDeduplicatedSlugBase.csv
new file mode 100644
index 000000000000..090cffb65d59
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueWithDeduplicatedSlugBase.csv
@@ -0,0 +1,5 @@
+"pages",,,,
+,"uid","pid","title","slug"
+,1,0,"root","/"
+,2,1,"Page One","/page-one"
+,3,1,"Page One","/page-one-1"
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/SlugUniqueTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/SlugUniqueTest.php
index fbecb711aa82..28401649f2c3 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/SlugUniqueTest.php
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/SlugUniqueTest.php
@@ -30,7 +30,6 @@ class SlugUniqueTest extends AbstractDataHandlerActionTestCase
     {
         parent::setUp();
         $this->setUpFrontendSite(1);
-        $this->importCSVDataSet(__DIR__ . '/DataSet/TestSlugUniqueBase.csv');
     }
 
     /**
@@ -51,8 +50,9 @@ class SlugUniqueTest extends AbstractDataHandlerActionTestCase
      * @test
      * @param string $uniqueSetting
      */
-    public function differentUniqueEvalSettingsDeDuplicateSlug(string $uniqueSetting)
+    public function differentUniqueEvalSettingsDeDuplicateSlug(string $uniqueSetting): void
     {
+        $this->importCSVDataSet(__DIR__ . '/DataSet/TestSlugUniqueBase.csv');
         $GLOBALS['TCA']['pages']['columns']['slug']['config']['eval'] = $uniqueSetting;
         $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
         $dataHandler->enableLogging = false;
@@ -68,7 +68,60 @@ class SlugUniqueTest extends AbstractDataHandlerActionTestCase
             []
         );
         $dataHandler->process_datamap();
+        $this->assertCSVDataSet('typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueResult.csv');
+    }
+
+    /**
+     * @dataProvider getEvalSettingDataProvider
+     * @test
+     * @param string $uniqueSetting
+     */
+    public function currentRecordIsExcludedWhenDeDuplicateSlug(string $uniqueSetting): void
+    {
+        $this->importCSVDataSet(__DIR__ . '/DataSet/TestSlugUniqueWithDeduplicatedSlugBase.csv');
+        $GLOBALS['TCA']['pages']['columns']['slug']['config']['eval'] = $uniqueSetting;
+        $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
+        $dataHandler->enableLogging = false;
+        $dataHandler->start(
+            [
+                'pages' => [
+                    3 => [
+                        'slug' => 'page-one-1',
+                    ],
+                ],
+            ],
+            []
+        );
+        $dataHandler->process_datamap();
 
         $this->assertCSVDataSet('typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueResult.csv');
     }
+
+    /**
+     * @dataProvider getEvalSettingDataProvider
+     * @test
+     * @param string $uniqueSetting
+     */
+    public function differentUniqueEvalSettingsDeDuplicateSlugWhenCreatingNewRecords(string $uniqueSetting): void
+    {
+        $this->importCSVDataSet(__DIR__ . '/DataSet/TestSlugUniqueBase.csv');
+        $GLOBALS['TCA']['pages']['columns']['slug']['config']['eval'] = $uniqueSetting;
+        $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
+        $dataHandler->enableLogging = false;
+        $dataHandler->start(
+            [
+                'pages' => [
+                    'NEW-1' => [
+                        'pid' => 1,
+                        'title' => 'Page Two',
+                        'slug' => '',
+                    ],
+                ],
+            ],
+            []
+        );
+        $dataHandler->process_datamap();
+
+        $this->assertCSVDataSet('typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/TestSlugUniqueNewRecordResult.csv');
+    }
 }
-- 
GitLab