From 08ae979e21c2004fe055c2ceaed97aea5e3fdb5e Mon Sep 17 00:00:00 2001 From: Alexander Bohndorf <bohndorf@web.de> Date: Thu, 29 Nov 2018 13:40:51 +0100 Subject: [PATCH] [BUGFIX] Allow unique for fields with l10n_mode=exclude Ignore uniqueness in translated records with same value Resolves: #87038 Releases: master Change-Id: I2b074e4a9c457a8a658bdc3f74c212a3976fe0fa Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/58979 Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Daniel Goerz <daniel.goerz@posteo.de> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Tobi Kretschmann <tobi@tobishome.de> Reviewed-by: Ulrich Mathes <mathes@sitegeist.de> Reviewed-by: Benni Mack <benni@typo3.org> --- .../core/Classes/DataHandling/DataHandler.php | 21 ++++- .../DataHandler/DataSet/LiveDefaultPages.csv | 12 +-- .../DataHandler/GetUniqueTranslationTest.php | 77 +++++++++++++++++++ 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php index 0cce838aedb1..ca79781e3903 100644 --- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php +++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php @@ -2425,6 +2425,26 @@ class DataHandler implements LoggerAwareInterface $queryBuilder->expr()->eq($field, $queryBuilder->createPositionalParameter($value, \PDO::PARAM_STR)), $queryBuilder->expr()->neq('uid', $queryBuilder->createPositionalParameter($uid, \PDO::PARAM_INT)) ); + // ignore translations of current record if field is configured with l10n_mode = "exclude" + if ($GLOBALS['TCA'][$table]['columns'][$field]['l10n_mode'] ?? '' === 'exclude' + && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] ?? '' !== '' + && $GLOBALS['TCA'][$table]['columns'][$field]['languageField'] ?? '' !== '') { + $queryBuilder + ->andWhere( + $queryBuilder->expr()->orX( + // records without l10n_parent must be taken into account (in any language) + $queryBuilder->expr()->eq( + $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], + $queryBuilder->createPositionalParameter(0, \PDO::PARAM_INT) + ), + // translations of other records must be taken into account + $queryBuilder->expr()->neq( + $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], + $queryBuilder->createPositionalParameter($uid, \PDO::PARAM_INT) + ) + ) + ); + } if ($pid !== 0) { $queryBuilder->andWhere( $queryBuilder->expr()->eq('pid', $queryBuilder->createPositionalParameter($pid, \PDO::PARAM_INT)) @@ -2435,7 +2455,6 @@ class DataHandler implements LoggerAwareInterface $queryBuilder->expr()->gte('pid', $queryBuilder->createPositionalParameter(0, \PDO::PARAM_INT)) ); } - return $queryBuilder->execute(); } diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/LiveDefaultPages.csv b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/LiveDefaultPages.csv index 2f118c797f9f..5eaacc9a803b 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/LiveDefaultPages.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/DataSet/LiveDefaultPages.csv @@ -1,6 +1,6 @@ -"pages",,,,,,,,,,,, -,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title","keywords" -,1,0,256,0,0,0,0,0,0,0,"FunctionalTest","functional" -,88,1,256,0,0,0,0,0,0,0,"DataHandlerTest","datahandler" -,89,88,256,0,0,0,0,0,0,0,"Relations","relations" -,90,88,512,0,0,0,0,0,0,0,"Target","target" +"pages",,,,,,,,,,,,, +,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title","keywords","nav_title" +,1,0,256,0,0,0,0,0,0,0,"FunctionalTest","functional","" +,88,1,256,0,0,0,0,0,0,0,"DataHandlerTest","datahandler","datahandler" +,89,88,256,0,0,0,0,0,0,0,"Relations","relations","" +,90,88,512,0,0,0,0,0,0,0,"Target","target","" diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/GetUniqueTranslationTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/GetUniqueTranslationTest.php index 01b9b81b0fad..d08f52fd5f6f 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/GetUniqueTranslationTest.php +++ b/typo3/sysext/core/Tests/Functional/DataHandling/DataHandler/GetUniqueTranslationTest.php @@ -33,13 +33,90 @@ class GetUniqueTranslationTest extends AbstractDataHandlerActionTestCase { // Mis-using the "keywords" field in the scenario data-set to check for uniqueness $GLOBALS['TCA']['pages']['columns']['keywords']['l10n_mode'] = 'exclude'; + $GLOBALS['TCA']['pages']['columns']['keywords']['transOrigPointerField'] = 'l10n_parent'; + $GLOBALS['TCA']['pages']['columns']['keywords']['languageField'] = 'sys_language_uid'; $GLOBALS['TCA']['pages']['columns']['keywords']['config']['eval'] = 'unique'; $map = $this->actionService->localizeRecord('pages', self::PAGE_DATAHANDLER, 1); $newPageId = $map['pages'][self::PAGE_DATAHANDLER]; + $originalLanguageRecord = BackendUtility::getRecord('pages', self::PAGE_DATAHANDLER); $translatedRecord = BackendUtility::getRecord('pages', $newPageId); self::assertEquals('datahandler', $originalLanguageRecord['keywords']); self::assertEquals('datahandler', $translatedRecord['keywords']); } + + /** + * @test + */ + public function valueOfUniqueFieldExcludedInTranslationIsUntouchedInOriginalLanguage(): void + { + // Mis-using the "nav_title" field in the scenario data-set to check for uniqueness + $GLOBALS['TCA']['pages']['columns']['nav_title']['l10n_mode'] = 'exclude'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['transOrigPointerField'] = 'l10n_parent'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['languageField'] = 'sys_language_uid'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['config']['eval'] = 'unique'; + $map = $this->actionService->localizeRecord('pages', self::PAGE_DATAHANDLER, 1); + $newPageId = $map['pages'][self::PAGE_DATAHANDLER]; + + $translatedRecord = BackendUtility::getRecord('pages', $newPageId); + $this->actionService->modifyRecord('pages', self::PAGE_DATAHANDLER, [ + 'title' => 'DataHandlerTest changed', + 'nav_title' => 'datahandler' + ]); + $originalLanguageRecord = BackendUtility::getRecord('pages', self::PAGE_DATAHANDLER); + + $this->assertEquals('DataHandlerTest changed', $originalLanguageRecord['title']); + $this->assertEquals('datahandler', $originalLanguageRecord['nav_title']); + $this->assertEquals('datahandler', $translatedRecord['nav_title']); + } + + /** + * @test + */ + public function valueOfUniqueFieldExcludedInTranslationIsIncrementedInNewOriginalRecord(): void + { + // Mis-using the "nav_title" field in the scenario data-set to check for uniqueness + $GLOBALS['TCA']['pages']['columns']['nav_title']['l10n_mode'] = 'exclude'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['transOrigPointerField'] = 'l10n_parent'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['languageField'] = 'sys_language_uid'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['config']['eval'] = 'unique'; + $map = $this->actionService->createNewRecord('pages', -self::PAGE_DATAHANDLER, [ + 'title' => 'New Page', + 'doktype' => 1 + ]); + $newPageId = $map['pages'][0]; + + $this->actionService->modifyRecord('pages', $newPageId, [ + 'nav_title' => 'datahandler' + ]); + $originalLanguageRecord = BackendUtility::getRecord('pages', self::PAGE_DATAHANDLER); + $newRecord = BackendUtility::getRecord('pages', $newPageId); + $this->assertEquals('datahandler', $originalLanguageRecord['nav_title']); + $this->assertEquals('datahandler0', $newRecord['nav_title']); + } + + /** + * @test + */ + public function valueOfUniqueFieldExcludedInTranslationIsIncrementedInNewTranslatedRecord(): void + { + // Mis-using the "nav_title" field in the scenario data-set to check for uniqueness + $GLOBALS['TCA']['pages']['columns']['nav_title']['l10n_mode'] = 'exclude'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['transOrigPointerField'] = 'l10n_parent'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['languageField'] = 'sys_language_uid'; + $GLOBALS['TCA']['pages']['columns']['nav_title']['config']['eval'] = 'unique'; + $map = $this->actionService->createNewRecord('pages', -self::PAGE_DATAHANDLER, [ + 'title' => 'New Page', + 'doktype' => 1, + 'nav_title' => 'datahandler', + 'sys_language_uid' => 1 + ]); + $newPageId = $map['pages'][0]; + + $defaultLanguageRecord = BackendUtility::getRecord('pages', self::PAGE_DATAHANDLER); + $newRecord = BackendUtility::getRecord('pages', $newPageId); + $this->assertEquals('datahandler', $defaultLanguageRecord['nav_title']); + $this->assertEquals('datahandler0', $newRecord['nav_title']); + } } -- GitLab