From 355be2e77f9877858498756affa3b75296078918 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Thu, 2 Nov 2017 12:29:51 +0100 Subject: [PATCH] [!!!][TASK] Migrate pages_language_overlay into pages The patch migrates all data from pages_language_overlay into pages, and moves all API calls to overlay pages. The following restrictions are set: * Backend is always showing pages only for "sys_language_uid=0" for the page tree, element browser (e.g. "linking to default language page"), except where explicitly requested like the Page Module => Languages view. * pid and sorting are always the same for all translations and their default language page * Elements on a page are always keeping the field "pid" to the default language page (no change) * Permission checks for Backend users are always made against the default language page (perms_* fields and webmounts) Resolves: #82445 Releases: master Change-Id: I62536e21d7110fa434c75fbd4470a3f53b79d260 Reviewed-on: https://review.typo3.org/51272 Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Frans Saris <franssaris@gmail.com> Tested-by: Frans Saris <franssaris@gmail.com> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> Reviewed-by: Frank Naegler <frank.naegler@typo3.org> Tested-by: Frank Naegler <frank.naegler@typo3.org> Reviewed-by: Andreas Fernandez <typo3@scripting-base.de> Tested-by: Andreas Fernandez <typo3@scripting-base.de> --- .../backend/Classes/Clipboard/Clipboard.php | 2 +- .../TranslationConfigurationProvider.php | 44 +-- .../Controller/EditDocumentController.php | 19 +- .../Controller/NewRecordController.php | 7 +- .../Controller/PageLayoutController.php | 43 +-- .../backend/Classes/Form/FormDataCompiler.php | 3 + .../FormDataProvider/AbstractItemProvider.php | 3 +- .../DatabaseDefaultLanguagePageRow.php | 41 +++ .../FormDataProvider/DatabaseLanguageRows.php | 10 +- .../DatabasePageLanguageOverlayRows.php | 6 +- .../DatabaseUserPermissionCheck.php | 2 +- .../Form/FormDataProvider/TcaInline.php | 3 - .../Classes/RecordList/AbstractRecordList.php | 6 +- .../Classes/Tree/Pagetree/DataProvider.php | 5 + .../Classes/Tree/View/PageTreeView.php | 2 +- .../Classes/Utility/BackendUtility.php | 16 +- .../backend/Classes/View/PageLayoutView.php | 115 +++---- .../Public/JavaScript/PageActions.js | 7 +- .../FormInlineAjaxControllerTest.php | 1 - .../DatabaseDefaultLanguagePageRowTest.php | 103 ++++++ .../BackendUserAuthentication.php | 32 +- .../core/Classes/DataHandling/DataHandler.php | 209 ++++++++----- .../DataHandling/Localization/DataMapItem.php | 26 -- .../Localization/DataMapProcessor.php | 84 ++--- .../core/Classes/Migrations/TcaMigration.php | 78 ++--- .../core/Classes/Utility/RootlineUtility.php | 4 +- .../Configuration/DefaultConfiguration.php | 7 +- typo3/sysext/core/Configuration/TCA/pages.php | 124 +++++++- ...reaking-82445-PagesAndPageTranslations.rst | 61 ++++ ...45-PageTranslationRelatedFunctionality.rst | 47 +++ ...5-MigratePagesLanguageOverlayIntoPages.rst | 53 ++++ .../Language/locallang_csh_pageslol.xlf | 119 ------- .../Language/locallang_csh_syslang.xlf | 6 +- .../ForeignField/AbstractActionTestCase.php | 35 ++- .../localizeNCopyPageWSynchronization.csv | 56 ++-- ...lotHotelChildNCopyPageWSynchronization.csv | 62 ++-- .../localizePageNAddHotelChildWExclude.csv | 20 +- ...lizePageNAddHotelChildWSynchronization.csv | 18 +- ...NAddMonoglotHotelChildWSynchronization.csv | 18 +- .../Modify/DataSet/localizePageWExclude.csv | 16 +- .../DataSet/localizePageWSynchronization.csv | 16 +- .../Regular/AbstractActionTestCase.php | 12 +- .../Regular/DataSet/LiveDefaultPages.csv | 10 +- .../Modify/DataSet/localizeNCopyPage.csv | 30 +- .../localizeNCopyPageWSynchronization.csv | 30 +- .../Regular/Modify/DataSet/localizePage.csv | 14 +- .../DataSet/localizePageWSynchronization.csv | 14 +- .../TCA/Overrides/pages_language_overlay.php | 28 -- .../Extensions/irre_tutorial/ext_tables.sql | 9 - .../Fixtures/pages_language_overlay.xml | 19 -- .../Database/Schema/Fixtures/tablebuilder.sql | 2 +- .../Schema/Parser/TableBuilderTest.php | 2 +- .../Unit/Migrations/TcaMigrationTest.php | 46 +-- typo3/sysext/core/ext_tables.php | 1 - typo3/sysext/core/ext_tables.sql | 5 + .../Generic/Storage/Typo3DbBackend.php | 2 - .../Persistence/TranslatedContentTest.php | 2 +- typo3/sysext/filelist/Classes/FileList.php | 6 +- .../Menu/AbstractMenuContentObject.php | 2 +- .../TypoScriptFrontendController.php | 2 +- .../frontend/Classes/Page/PageRepository.php | 29 +- .../frontend/Classes/View/AdminPanelView.php | 10 +- .../TCA/pages_language_overlay.php | 5 +- .../Tests/Functional/Fixtures/pages.xml | 42 +-- .../Rendering/DataSet/LiveDefaultPages.csv | 16 +- .../LocalizedContentRenderingTest.php | 4 +- .../PagesLanguageOverlayVisibleFieldsTest.php | 2 +- typo3/sysext/frontend/ext_tables.php | 2 +- .../TranslationStatusController.php | 28 +- ...gesLanguageOverlayBeGroupsAccessRights.php | 124 ++++++++ .../MigratePagesLanguageOverlayUpdate.php | 296 ++++++++++++++++++ .../Php/MethodCallMatcher.php | 21 ++ .../Php/MethodCallStaticMatcher.php | 7 + typo3/sysext/install/ext_localconf.php | 4 + .../sysext/recordlist/Classes/RecordList.php | 153 ++++++++- .../RecordList/AbstractDatabaseRecordList.php | 4 +- .../Classes/RecordList/DatabaseRecordList.php | 70 +++-- .../Controller/ViewModuleController.php | 4 +- .../Classes/Hook/DataHandlerHook.php | 2 +- .../Classes/Service/StagesService.php | 4 +- .../Classes/Service/WorkspaceService.php | 16 +- .../Regular/Modify/DataSet/localizePage.csv | 16 +- .../Regular/Publish/ActionTest.php | 2 +- .../Regular/Publish/DataSet/localizePage.csv | 14 +- .../PublishAll/DataSet/localizePage.csv | 14 +- .../Service/WorkspaceServiceTest.php | 1 - 86 files changed, 1685 insertions(+), 970 deletions(-) create mode 100644 typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseDefaultLanguagePageRow.php create mode 100644 typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseDefaultLanguagePageRowTest.php create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Breaking-82445-PagesAndPageTranslations.rst create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-82445-PageTranslationRelatedFunctionality.rst create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Important-82445-MigratePagesLanguageOverlayIntoPages.rst delete mode 100644 typo3/sysext/core/Resources/Private/Language/locallang_csh_pageslol.xlf delete mode 100644 typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/TCA/Overrides/pages_language_overlay.php delete mode 100644 typo3/sysext/core/Tests/Functional/Fixtures/pages_language_overlay.xml create mode 100644 typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayBeGroupsAccessRights.php create mode 100644 typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayUpdate.php diff --git a/typo3/sysext/backend/Classes/Clipboard/Clipboard.php b/typo3/sysext/backend/Classes/Clipboard/Clipboard.php index a763d570188e..82c51d746ccc 100644 --- a/typo3/sysext/backend/Classes/Clipboard/Clipboard.php +++ b/typo3/sysext/backend/Classes/Clipboard/Clipboard.php @@ -474,7 +474,7 @@ class Clipboard { $lines = []; $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl']; - if ($table !== 'pages' && BackendUtility::isTableLocalizable($table) && $table !== 'pages_language_overlay') { + if (BackendUtility::isTableLocalizable($table)) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions() ->removeAll() diff --git a/typo3/sysext/backend/Classes/Configuration/TranslationConfigurationProvider.php b/typo3/sysext/backend/Classes/Configuration/TranslationConfigurationProvider.php index fdf659285ef3..972793705ce0 100644 --- a/typo3/sysext/backend/Classes/Configuration/TranslationConfigurationProvider.php +++ b/typo3/sysext/backend/Classes/Configuration/TranslationConfigurationProvider.php @@ -110,37 +110,36 @@ class TranslationConfigurationProvider if (!is_array($row)) { return 'Record "' . $table . '_' . $uid . '" was not found'; } - $translationTable = $this->getTranslationTable($table); - if ($translationTable === '') { + if (!BackendUtility::isTableLocalizable($table)) { return 'Translation is not supported for this table!'; } - if ($translationTable === $table && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) { + if ($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) { return 'Record "' . $table . '_' . $uid . '" seems to be a translation already (has a language value "' . $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] . '", relation to record "' . $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] . '")'; } - if ($translationTable === $table && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0) { + if ($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0) { return 'Record "' . $table . '_' . $uid . '" seems to be a translation already (has a relation to record "' . $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] . '")'; } // Look for translations of this record, index by language field value: if (!$selFieldList) { - $selFieldList = 'uid,' . $GLOBALS['TCA'][$translationTable]['ctrl']['languageField']; + $selFieldList = 'uid,' . $GLOBALS['TCA'][$table]['ctrl']['languageField']; } - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($translationTable); + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $queryBuilder ->select(...GeneralUtility::trimExplode(',', $selFieldList)) - ->from($translationTable) + ->from($table) ->where( $queryBuilder->expr()->eq( - $GLOBALS['TCA'][$translationTable]['ctrl']['transOrigPointerField'], + $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( 'pid', $queryBuilder->createNamedParameter( - ($table === 'pages' ? $row['uid'] : $row['pid']), + $row['pid'], \PDO::PARAM_INT ) ) @@ -148,7 +147,7 @@ class TranslationConfigurationProvider if (!$languageUid) { $queryBuilder->andWhere( $queryBuilder->expr()->gt( - $GLOBALS['TCA'][$translationTable]['ctrl']['languageField'], + $GLOBALS['TCA'][$table]['ctrl']['languageField'], $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) ) ); @@ -156,7 +155,7 @@ class TranslationConfigurationProvider $queryBuilder ->andWhere( $queryBuilder->expr()->eq( - $GLOBALS['TCA'][$translationTable]['ctrl']['languageField'], + $GLOBALS['TCA'][$table]['ctrl']['languageField'], $queryBuilder->createNamedParameter($languageUid, \PDO::PARAM_INT) ) ); @@ -168,10 +167,10 @@ class TranslationConfigurationProvider $translations = []; $translationsErrors = []; foreach ($translationRecords as $translationRecord) { - if (!isset($translations[$translationRecord[$GLOBALS['TCA'][$translationTable]['ctrl']['languageField']]])) { - $translations[$translationRecord[$GLOBALS['TCA'][$translationTable]['ctrl']['languageField']]] = $translationRecord; + if (!isset($translations[$translationRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']]])) { + $translations[$translationRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']]] = $translationRecord; } else { - $translationsErrors[$translationRecord[$GLOBALS['TCA'][$translationTable]['ctrl']['languageField']]][] = $translationRecord; + $translationsErrors[$translationRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']]][] = $translationRecord; } } return [ @@ -179,7 +178,6 @@ class TranslationConfigurationProvider 'uid' => $uid, 'CType' => $row['CType'], 'sys_language_uid' => $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']], - 'translation_table' => $translationTable, 'translations' => $translations, 'excessive_translations' => $translationsErrors ]; @@ -190,10 +188,12 @@ class TranslationConfigurationProvider * * @param string $table The table name * @return string + * @deprecated since TYPO3 v9, will be removed in TYPO3 v10 as foreign translation table is not supported anymore */ public function getTranslationTable($table) { - return $this->isTranslationInOwnTable($table) ? $table : $this->foreignTranslationTable($table); + trigger_error('getTranslationTable() will be removed in TYPO3 v10, as the translation table is always the same as the original table.', E_USER_DEPRECATED); + return BackendUtility::isTableLocalizable($table) ? $table : ''; } /** @@ -201,21 +201,27 @@ class TranslationConfigurationProvider * * @param string $table The table name * @return bool + * @deprecated since TYPO3 v9, will be removed in TYPO3 v10 as foreign translation table is not supported anymore */ public function isTranslationInOwnTable($table) { - return $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] && $table !== 'pages_language_overlay'; + trigger_error('isTranslationInOwnTable() will be removed in TYPO3 v10, as the translation table is always the same as the original table.', E_USER_DEPRECATED); + return $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; } /** - * Returns foreign translation table, if any + * Returns foreign translation table, if any. + * Since TYPO3 v9, even "pages" translations are stored in the same table, having this method return always + * empty, as with other tables as well. * * @param string $table The table name * @return string Translation foreign table + * @deprecated since TYPO3 v9, will be removed in TYPO3 v10 as foreign translation table is not supported anymore */ public function foreignTranslationTable($table) { - return $table === 'pages' ? 'pages_language_overlay' : ''; + trigger_error('foreignTranslationTable() will be removed in TYPO3 v10, as the translation table is always the same as the original table.', E_USER_DEPRECATED); + return ''; } /** diff --git a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php index 07dcc08875ae..c3ea94e0819a 100644 --- a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php +++ b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php @@ -1509,14 +1509,20 @@ class EditDocumentController if ($this->getBackendUser()->check('tables_modify', $table) && $languageField && $transOrigPointerField - && $table !== 'pages_language_overlay' ) { if (is_null($pid)) { $row = BackendUtility::getRecord($table, $uid, 'pid'); $pid = $row['pid']; } // Get all available languages for the page - $langRows = $this->getLanguages($pid); + // If editing a page, the translations of the current UID need to be fetched + if ($table === 'pages') { + $row = BackendUtility::getRecord($table, $uid, 'l10n_parent'); + // Ensure the check is always done against the default language page + $langRows = $this->getLanguages($row['l10n_parent'] ?: $uid); + } else { + $langRows = $this->getLanguages($pid); + } // Page available in other languages than default language? if (is_array($langRows) && count($langRows) > 1) { $rowsByLang = []; @@ -1631,7 +1637,6 @@ class EditDocumentController public function localizationRedirect($justLocalized) { list($table, $origUid, $language) = explode(':', $justLocalized); - $table = $table === 'pages' ? 'pages_language_overlay' : $table; if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] @@ -1674,7 +1679,7 @@ class EditDocumentController * * @param int $id Page id: If zero, the query will select all sys_language records from root level which are NOT * hidden. If set to another value, the query will select all sys_language records that has a - * pages_language_overlay record on that page (and is not hidden, unless you are admin user) + * translation record on that page (and is not hidden, unless you are admin user) * @return array Language records including faked record for default language */ public function getLanguages($id) @@ -1718,11 +1723,11 @@ class EditDocumentController $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(HiddenRestriction::class)); } - // Add join with pages_languages_overlay table to only show active languages - $queryBuilder->from('pages_language_overlay', 'o') + // Add join with pages translations to only show active languages + $queryBuilder->from('pages', 'o') ->where( $queryBuilder->expr()->eq('o.sys_language_uid', $queryBuilder->quoteIdentifier('s.uid')), - $queryBuilder->expr()->eq('o.pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)) + $queryBuilder->expr()->eq('o.l10n_parent', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)) ); } diff --git a/typo3/sysext/backend/Classes/Controller/NewRecordController.php b/typo3/sysext/backend/Classes/Controller/NewRecordController.php index f1925e9fa009..5e15f40e3d30 100644 --- a/typo3/sysext/backend/Classes/Controller/NewRecordController.php +++ b/typo3/sysext/backend/Classes/Controller/NewRecordController.php @@ -557,9 +557,6 @@ class NewRecordController $iconFile[$_EXTKEY] = ''; } } else { - if ($table === 'pages_language_overlay' && !$this->checkIfLanguagesExist()) { - continue; - } $_EXTKEY = 'system'; $thisTitle = $lang->getLL('system_records'); $iconFile['system'] = $this->moduleTemplate->getIconFactory()->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render(); @@ -656,8 +653,8 @@ class NewRecordController if ($table === 'pages' && $addContentTable) { $urlParameters['tt_content']['prev'] = 'new'; $urlParameters['returnNewPageId'] = 1; - } elseif ($table === 'pages_language_overlay') { - $urlParameters['overrideVals']['pages_language_overlay']['doktype'] = (int)$this->pageinfo['doktype']; + } elseif ($table === 'pages') { + $urlParameters['overrideVals']['pages']['doktype'] = (int)$this->pageinfo['doktype']; } $url = BackendUtility::getModuleUrl('record_edit', $urlParameters); return '<a href="' . htmlspecialchars($url) . '">' . $linkText . '</a>'; diff --git a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php index d5d0e272c5bd..7c7b6560c5f3 100644 --- a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php +++ b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php @@ -306,7 +306,7 @@ class PageLayoutController $this->modSharedTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.SHARED'); $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName); - // First, select all pages_language_overlay records on the current page. Each represents a possibility for a language on the page. Add these to language selector. + // First, select all localized page records on the current page. Each represents a possibility for a language on the page. Add these to language selector. $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language'); $queryBuilder->getRestrictions()->removeAll(); if ($this->id) { @@ -314,38 +314,38 @@ class PageLayoutController ->from('sys_language') ->join( 'sys_language', - 'pages_language_overlay', - 'pages_language_overlay', + 'pages', + 'pages', $queryBuilder->expr()->eq( 'sys_language.uid', - $queryBuilder->quoteIdentifier('pages_language_overlay.sys_language_uid') + $queryBuilder->quoteIdentifier('pages.sys_language_uid') ) ) ->where( $queryBuilder->expr()->eq( - 'pages_language_overlay.deleted', + 'pages.deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( - 'pages_language_overlay.pid', + 'pages.l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT) ), $queryBuilder->expr()->orX( $queryBuilder->expr()->gte( - 'pages_language_overlay.t3ver_state', + 'pages.t3ver_state', $queryBuilder->createNamedParameter( (string)new VersionState(VersionState::DEFAULT_STATE), \PDO::PARAM_INT ) ), $queryBuilder->expr()->eq( - 'pages_language_overlay.t3ver_wsid', + 'pages.t3ver_wsid', $queryBuilder->createNamedParameter($this->getBackendUser()->workspace, \PDO::PARAM_INT) ) ) ) ->groupBy( - 'pages_language_overlay.sys_language_uid', + 'pages.sys_language_uid', 'sys_language.uid', 'sys_language.pid', 'sys_language.tstamp', @@ -634,16 +634,19 @@ class PageLayoutController { if ($this->current_sys_language > 0) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); - $overlayRecord = $queryBuilder + $localizedPage = $queryBuilder ->select('*') - ->from('pages_language_overlay') + ->from('pages') ->where( - $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq( + 'l10n_parent', + $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT) + ), $queryBuilder->expr()->eq( 'sys_language_uid', $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT) @@ -652,8 +655,8 @@ class PageLayoutController ->setMaxResults(1) ->execute() ->fetch(); - BackendUtility::workspaceOL('pages_language_overlay', $overlayRecord); - return $overlayRecord['title']; + BackendUtility::workspaceOL('pages', $localizedPage); + return $localizedPage['title']; } return $this->pageinfo['title']; } @@ -998,20 +1001,20 @@ class PageLayoutController if (!$this->modTSconfig['properties']['disableIconToolbar']) { // Edit page properties and page language overlay icons if ($this->pageIsNotLockedForEditors() && $this->getBackendUser()->checkLanguageAccess(0)) { - // Edit localized page_language_overlay only when one specific language is selected + // Edit localized pages only when one specific language is selected if ($this->MOD_SETTINGS['function'] == 1 && $this->current_sys_language > 0) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $overlayRecord = $queryBuilder ->select('uid') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->eq( - 'pid', + 'l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( @@ -1025,7 +1028,7 @@ class PageLayoutController // Edit button $urlParameters = [ 'edit' => [ - 'pages_language_overlay' => [ + 'pages' => [ $overlayRecord['uid'] => 'edit' ] ], diff --git a/typo3/sysext/backend/Classes/Form/FormDataCompiler.php b/typo3/sysext/backend/Classes/Form/FormDataCompiler.php index 7f58166d70f3..e31c41369914 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataCompiler.php +++ b/typo3/sysext/backend/Classes/Form/FormDataCompiler.php @@ -155,6 +155,9 @@ class FormDataCompiler // Parent page record is either the full row of the parent page the record is located at or should // be added to, or it is NULL, if a record is added or edited below the root page node. 'parentPageRow' => null, + // If a translated page is handled, the page row of the default language (the page against all page checks + // are made) is set here + 'defaultLanguagePageRow' => null, // Holds the "neighbor" row if incoming vanillaUid is negative and record creation is relative to a row of the same table. 'neighborRow' => null, // For "new" this is the fully initialized row with defaults diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php index 1a96445b11d5..ad41104ea1be 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php @@ -655,8 +655,7 @@ abstract class AbstractItemProvider $table = $result['tableName']; $backendUser = $this->getBackendUser(); // Guard clause returns if not correct table and field or if user is admin - if ($table !== 'pages' && $table !== 'pages_language_overlay' - || $fieldName !== 'doktype' || $backendUser->isAdmin() + if ($table !== 'pages' || $fieldName !== 'doktype' || $backendUser->isAdmin() ) { return $items; } diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseDefaultLanguagePageRow.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseDefaultLanguagePageRow.php new file mode 100644 index 000000000000..48fd45bebeb6 --- /dev/null +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseDefaultLanguagePageRow.php @@ -0,0 +1,41 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Backend\Form\FormDataProvider; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Backend\Form\FormDataProviderInterface; + +/** + * Fetch page in default language from database if it's a translated pages record + */ +class DatabaseDefaultLanguagePageRow extends AbstractDatabaseRecordProvider implements FormDataProviderInterface +{ + /** + * Add default language page row of existing row to result + * defaultLanguagePageRow will stay NULL in result if a record is added or edited below root node + * + * @param array $result + * @return array + */ + public function addData(array $result) + { + // $defaultLanguagePageRow end up NULL if a record added or edited on root node + $tableName = $result['tableName']; + if ($tableName === 'pages' && $result['databaseRow'][$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0) { + $result['defaultLanguagePageRow'] = $this->getRecordFromDatabase('pages', $result['databaseRow'][$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']]); + } + return $result; + } +} diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php index 34f0ea48c448..31633dc7dcd8 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php @@ -45,15 +45,9 @@ class DatabaseLanguageRows implements FormDataProviderInterface if (isset($result['databaseRow'][$languageField]) && $result['databaseRow'][$languageField] > 0 && isset($result['databaseRow'][$fieldWithUidOfDefaultRecord]) && $result['databaseRow'][$fieldWithUidOfDefaultRecord] > 0 ) { - // Table pages has its overlays in pages_language_overlay, this is accounted here - $tableNameWithDefaultRecords = $result['tableName']; - if ($tableNameWithDefaultRecords === 'pages_language_overlay') { - $tableNameWithDefaultRecords = 'pages'; - } - // Default language record of localized record $defaultLanguageRow = $this->getRecordWorkspaceOverlay( - $tableNameWithDefaultRecords, + $result['tableName'], (int)$result['databaseRow'][$fieldWithUidOfDefaultRecord] ); if (empty($defaultLanguageRow)) { @@ -90,7 +84,7 @@ class DatabaseLanguageRows implements FormDataProviderInterface continue; } $translationInfo = $translationProvider->translationInfo( - $tableNameWithDefaultRecords, + $result['tableName'], (int)$result['databaseRow'][$fieldWithUidOfDefaultRecord], $additionalLanguageUid ); diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabasePageLanguageOverlayRows.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabasePageLanguageOverlayRows.php index 80355249df2d..d2f793c75d07 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabasePageLanguageOverlayRows.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabasePageLanguageOverlayRows.php @@ -52,15 +52,15 @@ class DatabasePageLanguageOverlayRows implements FormDataProviderInterface protected function getDatabaseRows(int $pid): array { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $rows = $queryBuilder->select('*') - ->from('pages_language_overlay') - ->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT))) + ->from('pages') + ->where($queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT))) ->execute() ->fetchAll(); diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseUserPermissionCheck.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseUserPermissionCheck.php index 27d637951d92..467db33c56ac 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseUserPermissionCheck.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseUserPermissionCheck.php @@ -114,7 +114,7 @@ class DatabaseUserPermissionCheck implements FormDataProviderInterface // A page or a record on a page is edited if ($result['tableName'] === 'pages') { // A page record is edited, check edit rights of this record directly - $userPermissionOnPage = $backendUser->calcPerms($result['databaseRow']); + $userPermissionOnPage = $backendUser->calcPerms($result['defaultLanguagePageRow'] ?? $result['databaseRow']); if ((bool)($userPermissionOnPage & Permission::PAGE_EDIT) && $backendUser->check('pagetypes_select', $result['databaseRow'][$result['processedTca']['ctrl']['type']])) { $userHasAccess = true; } else { diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php index cf2b511b2198..18401cfb6885 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php @@ -135,9 +135,6 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid $result['databaseRow'][$fieldName] = implode(',', $connectedUidsOfLocalizedOverlay); if ($result['inlineCompileExistingChildren']) { $tableNameWithDefaultRecords = $result['tableName']; - if ($tableNameWithDefaultRecords === 'pages_language_overlay') { - $tableNameWithDefaultRecords = 'pages'; - } $connectedUidsOfDefaultLanguageRecord = $this->resolveConnectedRecordUids( $result['processedTca']['columns'][$fieldName]['config'], $tableNameWithDefaultRecords, diff --git a/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php b/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php index ef2e157646d1..5bb83cc77379 100644 --- a/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php +++ b/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php @@ -449,17 +449,17 @@ abstract class AbstractRecordList { // Look up page overlays: $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $result = $queryBuilder ->select('*') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->andX( - $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), $queryBuilder->expr()->gt('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)) ) ) diff --git a/typo3/sysext/backend/Classes/Tree/Pagetree/DataProvider.php b/typo3/sysext/backend/Classes/Tree/Pagetree/DataProvider.php index 64d90fa1107c..5618bea16bac 100644 --- a/typo3/sysext/backend/Classes/Tree/Pagetree/DataProvider.php +++ b/typo3/sysext/backend/Classes/Tree/Pagetree/DataProvider.php @@ -444,6 +444,11 @@ class DataProvider extends \TYPO3\CMS\Backend\Tree\AbstractTreeDataProvider ); } + // Only show records in default language + $queryBuilder->andWhere( + $expressionBuilder->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)) + ); + if ($searchFilter !== '') { $searchParts = $expressionBuilder->orX(); if (is_numeric($searchFilter) && $searchFilter > 0) { diff --git a/typo3/sysext/backend/Classes/Tree/View/PageTreeView.php b/typo3/sysext/backend/Classes/Tree/View/PageTreeView.php index 35e4a504b835..1a58a5856693 100644 --- a/typo3/sysext/backend/Classes/Tree/View/PageTreeView.php +++ b/typo3/sysext/backend/Classes/Tree/View/PageTreeView.php @@ -70,7 +70,7 @@ class PageTreeView extends AbstractTreeView */ public function init($clause = '', $orderByFields = '') { - parent::init(' AND deleted=0 ' . $clause, 'sorting'); + parent::init(' AND deleted=0 AND sys_language_uid=0 ' . $clause, 'sorting'); } /** diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php index 1c11d1070f15..3b70932c4c05 100644 --- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php +++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php @@ -302,11 +302,6 @@ class BackendUtility { $recordLocalization = false; - // Pages still stores translations in the pages_language_overlay table, all other tables store in themself - if ($table === 'pages') { - $table = 'pages_language_overlay'; - } - if (self::isTableLocalizable($table)) { $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl']; @@ -546,16 +541,15 @@ class BackendUtility } /** - * Gets the original translation pointer table. - * That is now the same table, apart from pages_language_overlay - * where pages is the original. + * Gets the original translation pointer table, which is always the same table * * @param string $table Name of the table * @return string Pointer table (if any) */ public static function getOriginalTranslationTable($table) { - return $table === 'pages_language_overlay' ? 'pages' : $table; + trigger_error('Starting with TYPO3 v9, the translation table is always the same as the original table, because pages_language_overlay has been migrated into pages table.', E_USER_DEPRECATED); + return $table; } /** @@ -3691,10 +3685,8 @@ class BackendUtility public static function translationCount($table, $ref, $msg = '') { $count = null; - if ($table !== 'pages' - && $GLOBALS['TCA'][$table]['ctrl']['languageField'] + if ($GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] - && $table !== 'pages_language_overlay' ) { $queryBuilder = static::getQueryBuilderForTable($table); $queryBuilder->getRestrictions() diff --git a/typo3/sysext/backend/Classes/View/PageLayoutView.php b/typo3/sysext/backend/Classes/View/PageLayoutView.php index 7df137cb5109..30bd1f711457 100644 --- a/typo3/sysext/backend/Classes/View/PageLayoutView.php +++ b/typo3/sysext/backend/Classes/View/PageLayoutView.php @@ -850,36 +850,15 @@ class PageLayoutView implements LoggerAwareInterface $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/Paste'); $userCanEditPage = $this->ext_CALC_PERMS & Permission::PAGE_EDIT && !empty($this->id) && ($backendUser->isAdmin() || (int)$this->pageinfo['editlock'] === 0); - if ($this->tt_contentConfig['languageColsPointer'] > 0) { - $userCanEditPage = $this->getBackendUser()->check('tables_modify', 'pages_language_overlay'); - } if ($userCanEditPage) { - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); - $queryBuilder->getRestrictions() - ->removeAll() - ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) - ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); - - $queryBuilder->select('uid') - ->from('pages_language_overlay') - ->where( - $queryBuilder->expr()->eq( - 'pid', - $queryBuilder->createNamedParameter((int)$this->id, \PDO::PARAM_INT) - ), - $queryBuilder->expr()->eq( - 'sys_language_uid', - $queryBuilder->createNamedParameter( - $this->tt_contentConfig['sys_language_uid'], - \PDO::PARAM_INT - ) - ) - ) - ->setMaxResults(1); - - $languageOverlayId = (int)$queryBuilder->execute()->fetchColumn(0); - + $languageOverlayId = 0; + $pageLocalizationRecord = BackendUtility::getRecordLocalization('pages', $this->id, (int)$this->tt_contentConfig['sys_language_uid']); + if (is_array($pageLocalizationRecord)) { + $pageLocalizationRecord = reset($pageLocalizationRecord); + } + if (!empty($pageLocalizationRecord['uid'])) { + $languageOverlayId = $pageLocalizationRecord['uid']; + } $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', 'function(PageActions) { PageActions.setPageId(' . (int)$this->id . '); PageActions.setLanguageOverlayId(' . $languageOverlayId . '); @@ -1298,43 +1277,24 @@ class PageLayoutView implements LoggerAwareInterface } // Language overlay page header: if ($lP) { - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); - $queryBuilder->getRestrictions() - ->removeAll() - ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) - ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); - - $lpRecord = $queryBuilder->select('*') - ->from('pages_language_overlay') - ->where( - $queryBuilder->expr()->eq( - 'pid', - $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT) - ), - $queryBuilder->expr()->eq( - 'sys_language_uid', - $queryBuilder->createNamedParameter($lP, \PDO::PARAM_INT) - ) - ) - ->setMaxResults(1) - ->execute() - ->fetch(); - - BackendUtility::workspaceOL('pages_language_overlay', $lpRecord); + $pageLocalizationRecord = BackendUtility::getRecordLocalization('pages', $id, $lP); + if (is_array($pageLocalizationRecord)) { + $pageLocalizationRecord = reset($pageLocalizationRecord); + } + BackendUtility::workspaceOL('pages', $pageLocalizationRecord); $recordIcon = BackendUtility::wrapClickMenuOnIcon( - $this->iconFactory->getIconForRecord('pages_language_overlay', $lpRecord, Icon::SIZE_SMALL)->render(), - 'pages_language_overlay', - $lpRecord['uid'] + $this->iconFactory->getIconForRecord('pages', $pageLocalizationRecord, Icon::SIZE_SMALL)->render(), + 'pages', + $pageLocalizationRecord['uid'] ); $urlParameters = [ 'edit' => [ - 'pages_language_overlay' => [ - $lpRecord['uid'] => 'edit' + 'pages' => [ + $pageLocalizationRecord['uid'] => 'edit' ] ], 'overrideVals' => [ - 'pages_language_overlay' => [ + 'pages' => [ 'sys_language_uid' => $lP ] ], @@ -1342,7 +1302,7 @@ class PageLayoutView implements LoggerAwareInterface ]; $url = BackendUtility::getModuleUrl('record_edit', $urlParameters); $editLink = ( - $this->getBackendUser()->check('tables_modify', 'pages_language_overlay') + $this->getBackendUser()->check('tables_modify', 'pages') ? '<a href="' . htmlspecialchars($url) . '" class="btn btn-default btn-sm"' . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('edit')) . '">' . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '</a>' @@ -1354,7 +1314,7 @@ class PageLayoutView implements LoggerAwareInterface . $viewLink . $editLink . '</div>' - . ' ' . $recordIcon . ' ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($lpRecord['title'], 20)); + . ' ' . $recordIcon . ' ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($pageLocalizationRecord['title'], 20)); } else { $editLink = ''; $recordIcon = ''; @@ -1374,7 +1334,7 @@ class PageLayoutView implements LoggerAwareInterface ]; $url = BackendUtility::getModuleUrl('record_edit', $urlParameters); $editLink = ( - $this->getBackendUser()->check('tables_modify', 'pages_language_overlay') + $this->getBackendUser()->check('tables_modify', 'pages') ? '<a href="' . htmlspecialchars($url) . '" class="btn btn-default btn-sm"' . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('edit')) . '">' . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '</a>' @@ -1693,6 +1653,7 @@ class PageLayoutView implements LoggerAwareInterface ->from('pages') ->where( $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)), $this->getBackendUser()->getPagePermsClause(1) ); @@ -2464,13 +2425,13 @@ class PageLayoutView implements LoggerAwareInterface * Displays only languages which are not yet present for the current page and * that are not disabled with page TS. * - * @param int $id Page id for which to create a new language (pages_language_overlay record) + * @param int $id Page id for which to create a new translation record of pages * @return string <select> HTML element (if there were items for the box anyways...) * @see getTable_tt_content() */ public function languageSelector($id) { - if ($this->getBackendUser()->check('tables_modify', 'pages_language_overlay')) { + if ($this->getBackendUser()->check('tables_modify', 'pages')) { // First, select all $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language'); $queryBuilder->getRestrictions()->removeAll(); @@ -2492,35 +2453,35 @@ class PageLayoutView implements LoggerAwareInterface ->from('sys_language') ->join( 'sys_language', - 'pages_language_overlay', - 'pages_language_overlay', - $queryBuilder->expr()->eq('sys_language.uid', $queryBuilder->quoteIdentifier('pages_language_overlay.sys_language_uid')) + 'pages', + 'pages', + $queryBuilder->expr()->eq('sys_language.uid', $queryBuilder->quoteIdentifier('pages.sys_language_uid')) ) ->where( $queryBuilder->expr()->eq( - 'pages_language_overlay.deleted', + 'pages.deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( - 'pages_language_overlay.pid', + 'pages.l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT) ), $queryBuilder->expr()->orX( $queryBuilder->expr()->gte( - 'pages_language_overlay.t3ver_state', + 'pages.t3ver_state', $queryBuilder->createNamedParameter( (string)new VersionState(VersionState::DEFAULT_STATE), \PDO::PARAM_INT ) ), $queryBuilder->expr()->eq( - 'pages_language_overlay.t3ver_wsid', + 'pages.t3ver_wsid', $queryBuilder->createNamedParameter($this->getBackendUser()->workspace, \PDO::PARAM_INT) ) ) ) ->groupBy( - 'pages_language_overlay.sys_language_uid', + 'pages.sys_language_uid', 'sys_language.uid', 'sys_language.pid', 'sys_language.tstamp', @@ -3399,9 +3360,7 @@ class PageLayoutView implements LoggerAwareInterface } // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set - if ( - $table !== 'pages_language_overlay' - && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) + if (!empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && (GeneralUtility::inList($this->hideTranslations, $table) || $this->hideTranslations === '*') ) { $queryBuilder->andWhere( @@ -4338,17 +4297,17 @@ class PageLayoutView implements LoggerAwareInterface { // Look up page overlays: $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $result = $queryBuilder ->select('*') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->andX( - $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), $queryBuilder->expr()->gt( 'sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/PageActions.js b/typo3/sysext/backend/Resources/Public/JavaScript/PageActions.js index 7e4999a51a58..e0b402896495 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/PageActions.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/PageActions.js @@ -192,20 +192,17 @@ define(['jquery', 'TYPO3/CMS/Backend/Storage/Persistent'], function($, Persisten $field.attr('disabled', 'disabled'); var parameters = {}, - pagesTable, recordUid; if (PageActions.settings.language.pageOverlayId === 0) { - pagesTable = 'pages'; recordUid = PageActions.settings.pageId; } else { - pagesTable = 'pages_language_overlay'; recordUid = PageActions.settings.language.pageOverlayId; } parameters.data = {}; - parameters.data[pagesTable] = {}; - parameters.data[pagesTable][recordUid] = {title: $field.val()}; + parameters.data['pages'] = {}; + parameters.data['pages'][recordUid] = {title: $field.val()}; require(['TYPO3/CMS/Backend/AjaxDataHandler'], function(DataHandler) { DataHandler.process(parameters).done(function() { diff --git a/typo3/sysext/backend/Tests/Functional/Controller/FormInlineAjaxControllerTest.php b/typo3/sysext/backend/Tests/Functional/Controller/FormInlineAjaxControllerTest.php index 5eaa829232a0..0c06968624c0 100644 --- a/typo3/sysext/backend/Tests/Functional/Controller/FormInlineAjaxControllerTest.php +++ b/typo3/sysext/backend/Tests/Functional/Controller/FormInlineAjaxControllerTest.php @@ -47,7 +47,6 @@ class FormInlineAjaxControllerTest extends FunctionalTestCase $this->importDataSet('PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/pages.xml'); $this->importDataSet('PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/sys_language.xml'); - $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/pages_language_overlay.xml'); $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/backend/Tests/Functional/Fixtures/tx_irretutorial_1ncsv_hotel.xml'); $this->setUpBackendUserFromFixture(1); diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseDefaultLanguagePageRowTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseDefaultLanguagePageRowTest.php new file mode 100644 index 000000000000..ec02c4d3e742 --- /dev/null +++ b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseDefaultLanguagePageRowTest.php @@ -0,0 +1,103 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseDefaultLanguagePageRow; + +/** + * Test case + */ +class DatabaseDefaultLanguagePageRowTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase +{ + /** + * @var DatabaseDefaultLanguagePageRow|\PHPUnit_Framework_MockObject_MockObject + */ + protected $subject; + + protected function setUp() + { + $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] = 'l10n_parent'; + $this->subject = $this->getMockBuilder(DatabaseDefaultLanguagePageRow::class) + ->setMethods(['getDatabaseRow']) + ->getMock(); + } + + /** + * @test + */ + public function addDataDoesNotApplyToAnyNonPagesTable() + { + $input = [ + 'tableName' => 'tx_doandroidsdreamofelectricsheep', + 'databaseRow' => [ + 'uid' => 23, + 'l10n_parent' => 13, + 'sys_language_uid' => 23 + ] + ]; + $result = $this->subject->addData($input); + + $this->assertNull($result['defaultLanguagePageRow']); + } + + /** + * @test + */ + public function addDataDoesApplyToAPagesTableButNoChangeForDefaultLanguage() + { + $input = [ + 'tableName' => 'pages', + 'databaseRow' => [ + 'uid' => 23, + 'l10n_parent' => 0, + 'sys_language_uid' => 0 + ] + ]; + $result = $this->subject->addData($input); + $this->assertSame($input, $result); + } + + /** + * @test + */ + public function addDataDoesApplyToATranslatedPagesTable() + { + $input = [ + 'tableName' => 'pages', + 'databaseRow' => [ + 'uid' => 23, + 'pid' => 1, + 'l10n_parent' => 13, + 'sys_language_uid' => 8 + ] + ]; + + $defaultLanguagePageRow = [ + 'uid' => 13, + 'pid' => 1, + 'sys_language_uid' => 0, + 'l10n_parent' => 0 + ]; + + $this->subject->expects($this->once()) + ->method('getDatabaseRow') + ->with($input['tableName'], 13) + ->willReturn($defaultLanguagePageRow); + + $result = $this->subject->addData($input); + $this->assertEquals($defaultLanguagePageRow, $result['defaultLanguagePageRow']); + } +} diff --git a/typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php b/typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php index c6d716a022e6..d1810f02392b 100644 --- a/typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php +++ b/typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php @@ -579,7 +579,8 @@ class BackendUserAuthentication extends AbstractUserAuthentication return Permission::ALL; } // Return 0 if page is not within the allowed web mount - if (!$this->isInWebMount($row['uid'])) { + // Always do this for the default language page record + if (!$this->isInWebMount($row['l10n_parent'] ?: $row['uid'])) { return Permission::NOTHING; } $out = Permission::NOTHING; @@ -731,25 +732,16 @@ class BackendUserAuthentication extends AbstractUserAuthentication public function checkFullLanguagesAccess($table, $record) { $recordLocalizationAccess = $this->checkLanguageAccess(0); - if ($recordLocalizationAccess && (BackendUtility::isTableLocalizable($table) || $table === 'pages')) { - if ($table === 'pages') { - $l10nTable = 'pages_language_overlay'; - $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField']; - $pointerValue = $record['uid']; - } else { - $l10nTable = $table; - $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField']; - $pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid']; - } - - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($l10nTable); + if ($recordLocalizationAccess && BackendUtility::isTableLocalizable($table)) { + $pointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; + $pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid']; + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); - $recordLocalization = $queryBuilder->select('*') - ->from($l10nTable) + ->from($table) ->where( $queryBuilder->expr()->eq( $pointerField, @@ -762,7 +754,7 @@ class BackendUserAuthentication extends AbstractUserAuthentication if (is_array($recordLocalization)) { $languageAccess = $this->checkLanguageAccess( - $recordLocalization[$GLOBALS['TCA'][$l10nTable]['ctrl']['languageField']] + $recordLocalization[$GLOBALS['TCA'][$table]['ctrl']['languageField']] ); $recordLocalizationAccess = $recordLocalizationAccess && $languageAccess; } @@ -807,6 +799,9 @@ class BackendUserAuthentication extends AbstractUserAuthentication } } // Checking languages: + if ($table === 'pages' && $checkFullLanguageAccess && !$this->checkFullLanguagesAccess($table, $idOrRow)) { + return false; + } if ($GLOBALS['TCA'][$table]['ctrl']['languageField']) { // Language field must be found in input row - otherwise it does not make sense. if (isset($idOrRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) { @@ -826,11 +821,6 @@ class BackendUserAuthentication extends AbstractUserAuthentication . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '" was not found in testing record!'; return false; } - } elseif ( - $table === 'pages' && $checkFullLanguageAccess && - !$this->checkFullLanguagesAccess($table, $idOrRow) - ) { - return false; } // Checking authMode fields: if (is_array($GLOBALS['TCA'][$table]['columns'])) { diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php index 3d049826bf01..53c95637e4bf 100644 --- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php +++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php @@ -1043,7 +1043,12 @@ class DataHandler implements LoggerAwareInterface // Now, check if we may insert records on this pid. if ($theRealPid >= 0) { // Checks if records can be inserted on this $pid. - $recordAccess = $this->checkRecordInsertAccess($table, $theRealPid); + // If this is a page translation, the check needs to be done for the l10n_parent record + if ($table === 'pages' && $incomingFieldArray['sys_language_uid'] > 0 && $incomingFieldArray['l10n_parent'] > 0) { + $recordAccess = $this->checkRecordInsertAccess($table, $incomingFieldArray['l10n_parent']); + } else { + $recordAccess = $this->checkRecordInsertAccess($table, $theRealPid); + } if ($recordAccess) { $this->addDefaultPermittedLanguageIfNotSet($table, $incomingFieldArray); $recordAccess = $this->BE_USER->recordEditAccessInternals($table, $incomingFieldArray, true); @@ -1417,19 +1422,26 @@ class DataHandler implements LoggerAwareInterface if (is_array($incomingFieldArray) && is_array($checkValueRecord)) { ArrayUtility::mergeRecursiveWithOverrule($checkValueRecord, $incomingFieldArray); } + $currentRecord = $checkValueRecord; } else { // We must use the current values as basis for this! $currentRecord = ($checkValueRecord = $this->recordInfo($table, $id, '*')); - // This is done to make the pid positive for offline versions; Necessary to have diff-view for pages_language_overlay in workspaces. + // This is done to make the pid positive for offline versions; Necessary to have diff-view for page translations in workspaces. BackendUtility::fixVersioningPid($table, $currentRecord); - // Get original language record if available: - if (is_array($currentRecord) && $GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField'] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $currentRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0 && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] && (int)$currentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] > 0) { - $lookUpTable = $table === 'pages_language_overlay' ? 'pages' : $table; - $originalLanguageRecord = $this->recordInfo($lookUpTable, $currentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']], '*'); - BackendUtility::workspaceOL($lookUpTable, $originalLanguageRecord); - $originalLanguage_diffStorage = unserialize($currentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']]); - } } + + // Get original language record if available: + if (is_array($currentRecord) + && $GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField'] + && $GLOBALS['TCA'][$table]['ctrl']['languageField'] + && $currentRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0 + && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] + && (int)$currentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] > 0) { + $originalLanguageRecord = $this->recordInfo($table, $currentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']], '*'); + BackendUtility::workspaceOL($table, $originalLanguageRecord); + $originalLanguage_diffStorage = unserialize($currentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']]); + } + $this->checkValue_currentRecord = $checkValueRecord; // In the following all incoming value-fields are tested: // - Are the user allowed to change the field? @@ -1464,8 +1476,6 @@ class DataHandler implements LoggerAwareInterface $value = (int)$fieldValue; switch ($field) { case 'perms_userid': - $fieldArray[$field] = $value; - break; case 'perms_groupid': $fieldArray[$field] = $value; break; @@ -1518,6 +1528,17 @@ class DataHandler implements LoggerAwareInterface } } } + + // Dealing with a page translation, setting "sorting", "pid", "perms_*" to the same values as the original record + if ($table === 'pages' && is_array($originalLanguageRecord)) { + $fieldArray['sorting'] = $originalLanguageRecord['sorting']; + $fieldArray['perms_userid'] = $originalLanguageRecord['perms_userid']; + $fieldArray['perms_groupid'] = $originalLanguageRecord['perms_groupid']; + $fieldArray['perms_user'] = $originalLanguageRecord['perms_user']; + $fieldArray['perms_group'] = $originalLanguageRecord['perms_group']; + $fieldArray['perms_everybody'] = $originalLanguageRecord['perms_everybody']; + } + // Add diff-storage information: if ($diffStorageFlag && !isset($fieldArray[$GLOBALS['TCA'][$table]['ctrl']['transOrigDiffSourceField']])) { // If the field is set it would probably be because of an undo-operation - in which case we should not update the field of course... @@ -1552,7 +1573,7 @@ class DataHandler implements LoggerAwareInterface $res = []; // Processing special case of field pages.doktype - if (($table === 'pages' || $table === 'pages_language_overlay') && $field === 'doktype') { + if ($table === 'pages' && $field === 'doktype') { // If the user may not use this specific doktype, we issue a warning if (!($this->admin || GeneralUtility::inList($this->BE_USER->groupData['pagetypes_select'], $value))) { if ($this->enableLogging) { @@ -3381,7 +3402,7 @@ class DataHandler implements LoggerAwareInterface } $fullLanguageCheckNeeded = $table !== 'pages'; - //Used to check language and general editing rights + // Used to check language and general editing rights if (!$ignoreLocalization && ($language <= 0 || !$this->BE_USER->checkLanguageAccess($language)) && !$this->BE_USER->recordEditAccessInternals($table, $uid, false, false, $fullLanguageCheckNeeded)) { $this->log($table, $uid, 1, 0, 1, 'Attempt to copy record "%s:%s" without having permissions to do so. [' . $this->BE_USER->errorMsg . '].', -1, [$table, $uid]); return null; @@ -4174,8 +4195,8 @@ class DataHandler implements LoggerAwareInterface */ public function copyL10nOverlayRecords($table, $uid, $destPid, $first = false, $overrideValues = [], $excludeFields = '') { - // There's no need to perform this for page-records or for tables that are not localizable - if (!BackendUtility::isTableLocalizable($table) || $table === 'pages' || $table === 'pages_language_overlay') { + // There's no need to perform this for tables that are not localizable + if (!BackendUtility::isTableLocalizable($table)) { return; } @@ -4396,6 +4417,20 @@ class DataHandler implements LoggerAwareInterface if ($GLOBALS['TCA'][$table]['ctrl']['tstamp']) { $updateFields[$GLOBALS['TCA'][$table]['ctrl']['tstamp']] = $GLOBALS['EXEC_TIME']; } + + // Check if this is a translation of a page, if so then it just needs to be kept "sorting" in sync + // Usually called from moveL10nOverlayRecords() + $originalTranslationRecord = null; + if ($table === 'pages') { + $fullRecord = $this->recordInfo($table, $uid, 'sys_language_uid, l10n_parent'); + if ($fullRecord['sys_language_uid'] > 0) { + $originalTranslationRecord = $this->recordInfo($table, $fullRecord['l10n_parent'], 'pid,' . $sortRow); + $updateFields[$sortRow] = $originalTranslationRecord[$sortRow]; + // Ensure that the PID is always the same as the original page + $destPid = $originalTranslationRecord['pid']; + } + } + // Insert as first element on page (where uid = $destPid) if ($destPid >= 0) { if ($table !== 'pages' || $this->destNotInsideSelf($destPid, $uid)) { @@ -4405,7 +4440,7 @@ class DataHandler implements LoggerAwareInterface // Setting PID $updateFields['pid'] = $destPid; // Table is sorted by 'sortby' - if ($sortRow) { + if ($sortRow && !isset($updateFields[$sortRow])) { $sortNumber = $this->getSortNumber($table, $uid, $destPid); $updateFields[$sortRow] = $sortNumber; } @@ -4464,9 +4499,11 @@ class DataHandler implements LoggerAwareInterface if ($table !== 'pages' || $this->destNotInsideSelf($destPid, $uid)) { // clear cache before moving $this->registerRecordIdForPageCacheClearing($table, $uid); - // We now update the pid and sortnumber + // We now update the pid and sortnumber (if not set for page translations) $updateFields['pid'] = $destPid; - $updateFields[$sortRow] = $sortInfo['sortNumber']; + if (!isset($updateFields[$sortRow])) { + $updateFields[$sortRow] = $sortInfo['sortNumber']; + } // Check for child records that have also to be moved $this->moveRecord_procFields($table, $uid, $destPid); // Create query for update: @@ -4582,8 +4619,8 @@ class DataHandler implements LoggerAwareInterface */ public function moveL10nOverlayRecords($table, $uid, $destPid, $originalRecordDestinationPid) { - // There's no need to perform this for page-records or not localizable tables - if (!BackendUtility::isTableLocalizable($table) || $table === 'pages' || $table === 'pages_language_overlay') { + // There's no need to perform this for non-localizable tables + if (!BackendUtility::isTableLocalizable($table)) { return; } @@ -4652,10 +4689,7 @@ class DataHandler implements LoggerAwareInterface } $this->registerNestedElementCall($table, $uid, 'localize'); - if ((!$GLOBALS['TCA'][$table]['ctrl']['languageField'] - || !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] - || $table === 'pages_language_overlay') - && $table !== 'pages') { + if (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) { $this->newlog('Localization failed; "languageField" and "transOrigPointerField" must be defined for the table!', 1); return false; } @@ -4680,8 +4714,7 @@ class DataHandler implements LoggerAwareInterface // Make sure that records which are translated from another language than the default language have a correct // localization source set themselves, before translating them to another language. if ((int)$row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] !== 0 - && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0 - && $table !== 'pages') { + && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) { $localizationParentRecord = BackendUtility::getRecord( $table, $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] @@ -4694,41 +4727,12 @@ class DataHandler implements LoggerAwareInterface // Default language records must never have a localization parent as they are the origin of any translation. if ((int)$row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] !== 0 - && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0 - && $table !== 'pages') { + && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) { $this->newlog('Localization failed; Source record contained a reference to an original default record but is a default record itself (which is strange)!', 1); return false; } - if ($table === 'pages') { - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); - $queryBuilder->getRestrictions() - ->removeAll() - ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) - ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); - - $recordCount = $queryBuilder->count('*') - ->from('pages_language_overlay') - ->where( - $queryBuilder->expr()->eq( - 'pid', - $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT) - ), - $queryBuilder->expr()->eq( - $GLOBALS['TCA']['pages_language_overlay']['ctrl']['languageField'], - $queryBuilder->createNamedParameter((int)$langRec['uid'], \PDO::PARAM_INT) - ) - ) - ->execute() - ->fetchColumn(0); - - $pass = !$recordCount; - $Ttable = 'pages_language_overlay'; - } else { - $pass = !BackendUtility::getRecordLocalization($table, $uid, $langRec['uid'], 'AND pid=' . (int)$row['pid']); - $Ttable = $table; - } + $pass = !BackendUtility::getRecordLocalization($table, $uid, $language, 'AND pid=' . (int)$row['pid']); if (!$pass) { $this->newlog('Localization failed; There already was a localization for this language of the record!', 1); @@ -4739,26 +4743,26 @@ class DataHandler implements LoggerAwareInterface $overrideValues = []; $excludeFields = []; // Set override values: - $overrideValues[$GLOBALS['TCA'][$Ttable]['ctrl']['languageField']] = $langRec['uid']; + $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['languageField']] = $langRec['uid']; // If the translated record is a default language record, set it's uid as localization parent of the new record. // If translating from any other language, no override is needed; we just can copy the localization parent of // the original record (which is pointing to the correspondent default language record) to the new record. // In copy / free mode the TransOrigPointer field is always set to 0, as no connection to the localization parent is wanted in that case. - if (($this->useTransOrigPointerField && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) - || $table === 'pages') { - $overrideValues[$GLOBALS['TCA'][$Ttable]['ctrl']['transOrigPointerField']] = $uid; + // For pages, there is no "copy/free mode". + if (($this->useTransOrigPointerField || $table === 'pages') && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) { + $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] = $uid; } elseif (!$this->useTransOrigPointerField) { - $overrideValues[$GLOBALS['TCA'][$Ttable]['ctrl']['transOrigPointerField']] = 0; + $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] = 0; } if (isset($GLOBALS['TCA'][$table]['ctrl']['translationSource'])) { - $overrideValues[$GLOBALS['TCA'][$Ttable]['ctrl']['translationSource']] = $uid; + $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['translationSource']] = $uid; } // Copy the type (if defined in both tables) from the original record so that translation has same type as original record - if (isset($GLOBALS['TCA'][$table]['ctrl']['type']) && isset($GLOBALS['TCA'][$Ttable]['ctrl']['type'])) { - $overrideValues[$GLOBALS['TCA'][$Ttable]['ctrl']['type']] = $row[$GLOBALS['TCA'][$table]['ctrl']['type']]; + if (isset($GLOBALS['TCA'][$table]['ctrl']['type'])) { + $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['type']] = $row[$GLOBALS['TCA'][$table]['ctrl']['type']]; } // Set exclude Fields: - foreach ($GLOBALS['TCA'][$Ttable]['columns'] as $fN => $fCfg) { + foreach ($GLOBALS['TCA'][$table]['columns'] as $fN => $fCfg) { $translateToMsg = ''; // Check if we are just prefixing: if ($fCfg['l10n_mode'] === 'prefixLangTitle') { @@ -4785,15 +4789,16 @@ class DataHandler implements LoggerAwareInterface } } elseif ( ($fCfg['l10n_mode'] === 'exclude') - && $fN != $GLOBALS['TCA'][$Ttable]['ctrl']['languageField'] - && $fN != $GLOBALS['TCA'][$Ttable]['ctrl']['transOrigPointerField'] + && $fN != $GLOBALS['TCA'][$table]['ctrl']['languageField'] + && $fN != $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] ) { // Otherwise, do not copy field (unless it is the language field or // pointer to the original language) $excludeFields[] = $fN; } } - if ($Ttable === $table) { + + if ($table !== 'pages') { // Get the uid of record after which this localized record should be inserted $previousUid = $this->getPreviousLocalizedRecordUid($table, $uid, $row['pid'], $language); // Execute the copy: @@ -4803,16 +4808,17 @@ class DataHandler implements LoggerAwareInterface $this->triggerRemapAction($table, $newId, [$this, 'placeholderShadowing'], [$table, $autoVersionNewId], true); } } else { - // Create new record: + // Create new page which needs to contain the same pid as the original page + $overrideValues['pid'] = $row['pid']; $temporaryId = StringUtility::getUniqueId('NEW'); $copyTCE = $this->getLocalTCE(); - $copyTCE->start([$Ttable => [$temporaryId => $overrideValues]], [], $this->BE_USER); + $copyTCE->start([$table => [$temporaryId => $overrideValues]], [], $this->BE_USER); $copyTCE->process_datamap(); // Getting the new UID as if it had been copied: $theNewSQLID = $copyTCE->substNEWwithIDs[$temporaryId]; if ($theNewSQLID) { - // If is by design that $Ttable is used and not $table! See "l10nmgr" extension. Could be debated, but this is what I chose for this "pseudo case" - $this->copyMappingArray[$Ttable][$uid] = $theNewSQLID; + // If is by design that $table is used and not $table! See "l10nmgr" extension. Could be debated, but this is what I chose for this "pseudo case" + $this->copyMappingArray[$table][$uid] = $theNewSQLID; $newId = $theNewSQLID; } } @@ -4883,7 +4889,6 @@ class DataHandler implements LoggerAwareInterface $foreignTable = $config['foreign_table']; $transOrigPointer = (int)$parentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]; - $transOrigTable = BackendUtility::getOriginalTranslationTable($table); $childTransOrigPointerField = $GLOBALS['TCA'][$foreignTable]['ctrl']['transOrigPointerField']; if (!$parentRecord || !is_array($parentRecord) || $language <= 0 || !$transOrigPointer) { @@ -4895,14 +4900,14 @@ class DataHandler implements LoggerAwareInterface return; } - $transOrigRecord = BackendUtility::getRecordWSOL($transOrigTable, $transOrigPointer); + $transOrigRecord = BackendUtility::getRecordWSOL($table, $transOrigPointer); $removeArray = []; $mmTable = $inlineSubType === 'mm' && isset($config['MM']) && $config['MM'] ? $config['MM'] : ''; // Fetch children from original language parent: /** @var $dbAnalysisOriginal RelationHandler */ $dbAnalysisOriginal = $this->createRelationHandlerInstance(); - $dbAnalysisOriginal->start($transOrigRecord[$field], $foreignTable, $mmTable, $transOrigRecord['uid'], $transOrigTable, $config); + $dbAnalysisOriginal->start($transOrigRecord[$field], $foreignTable, $mmTable, $transOrigRecord['uid'], $table, $config); $elementsOriginal = []; foreach ($dbAnalysisOriginal->itemArray as $item) { $elementsOriginal[$item['id']] = $item; @@ -5090,7 +5095,15 @@ class DataHandler implements LoggerAwareInterface // Checking if there is anything else disallowing deleting the record by checking if editing is allowed $deletedRecord = $forceHardDelete || $undeleteRecord; - $hasEditAccess = $this->BE_USER->recordEditAccessInternals($table, $uid, false, $deletedRecord, true); + $fullLanguageAccessCheck = true; + if ($table === 'pages') { + // If this is a page translation, the full language access check should not be done + $recordInfo = $this->recordInfo($table, $uid, 'l10n_parent'); + if ($recordInfo['l10n_parent'] > 0) { + $fullLanguageAccessCheck = false; + } + } + $hasEditAccess = $this->BE_USER->recordEditAccessInternals($table, $uid, false, $deletedRecord, $fullLanguageAccessCheck); if (!$hasEditAccess) { $this->log($table, $uid, 3, 0, 1, 'Attempt to delete record without delete-permissions'); return; @@ -5403,9 +5416,19 @@ class DataHandler implements LoggerAwareInterface public function canDeletePage($uid) { $uid = (int)$uid; + $isTranslatedPage = null; // If we may at all delete this page - if (!$this->doesRecordExist('pages', $uid, 'delete')) { + // If this is a page translation, do the check against the perms_* of the default page + // Because it is currently only deleting the translation + $fullRecord = $this->recordInfo('pages', $uid, 'l10n_parent'); + if ($fullRecord['l10n_parent'] > 0) { + if ($this->doesRecordExist('pages', (int)$fullRecord['l10n_parent'], 'delete')) { + $isTranslatedPage = $fullRecord['l10n_parent'] > 0; + } else { + return 'Attempt to delete page without permissions'; + } + } elseif (!$this->doesRecordExist('pages', $uid, 'delete')) { return 'Attempt to delete page without permissions'; } @@ -5433,7 +5456,7 @@ class DataHandler implements LoggerAwareInterface } foreach ($pagesInBranch as $pageInBranch) { - if (!$this->BE_USER->recordEditAccessInternals('pages', $pageInBranch, false, false, true)) { + if (!$this->BE_USER->recordEditAccessInternals('pages', $pageInBranch, false, false, $isTranslatedPage ? false : true)) { return 'Attempt to delete page which has prohibited localizations.'; } } @@ -5563,8 +5586,8 @@ class DataHandler implements LoggerAwareInterface */ public function deleteL10nOverlayRecords($table, $uid) { - // Check whether table can be localized or has a different table defined to store localizations: - if (!BackendUtility::isTableLocalizable($table) || $table === 'pages' || $table === 'pages_language_overlay') { + // Check whether table can be localized + if (!BackendUtility::isTableLocalizable($table)) { return; } @@ -6062,8 +6085,14 @@ class DataHandler implements LoggerAwareInterface $thePidToUpdate = $this->registerDBPids[$table][$uid]; $thePidToUpdate = $this->copyMappingArray_merged['pages'][$thePidToUpdate]; } + // Update child records if change to pid is required (only if the current record is not on a workspace): if ($thePidToUpdate) { + // Ensure that only the default language page is used as PID + $localizationParent = $this->recordInfo('pages', $thePidToUpdate, 'l10n_parent'); + if ($localizationParent['l10n_parent'] > 0) { + $thePidToUpdate = $localizationParent['l10n_parent']; + } // ensure, only live page ids are used as 'pid' values $liveId = BackendUtility::getLiveVersionIdOfRecord('pages', $theUidToUpdate); if ($liveId !== null) { @@ -6448,7 +6477,15 @@ class DataHandler implements LoggerAwareInterface if (isset($this->recUpdateAccessCache[$table][$id])) { return $this->recUpdateAccessCache[$table][$id]; } - if ($this->doesRecordExist($table, $id, 'edit')) { + // permissions check for page translations need to be done on the parent page + if ($table === 'pages') { + $defaultLanguagePage = $this->recordInfo($table, $id, 'l10n_parent'); + if ($defaultLanguagePage['l10n_parent'] > 0) { + $res = $this->doesRecordExist($table, $defaultLanguagePage['l10n_parent'], 'edit'); + } else { + $res = $this->doesRecordExist($table, $id, 'edit') ? 1 : 0; + } + } elseif ($this->doesRecordExist($table, $id, 'edit')) { $res = 1; } // Cache the result @@ -8368,9 +8405,11 @@ class DataHandler implements LoggerAwareInterface if (empty($TSConfig['clearCache_disable'])) { // If table is "pages": $pageIdsThatNeedCacheFlush = []; - if ($table === 'pages' || $table === 'pages_language_overlay') { - if ($table === 'pages_language_overlay') { - $pageUid = $this->getPID($table, $uid); + if ($table === 'pages') { + // Find out if the record is a get the original page + $row = $this->recordInfo($table, $uid, 'pid,sys_language_uid,l10n_parent'); + if ((int)$row['l10n_parent'] > 0) { + $pageUid = $row['l10n_parent']; } else { $pageUid = $uid; } diff --git a/typo3/sysext/core/Classes/DataHandling/Localization/DataMapItem.php b/typo3/sysext/core/Classes/DataHandling/Localization/DataMapItem.php index 4cf0e7ab838e..21fb7e7c9986 100644 --- a/typo3/sysext/core/Classes/DataHandling/Localization/DataMapItem.php +++ b/typo3/sysext/core/Classes/DataHandling/Localization/DataMapItem.php @@ -161,32 +161,6 @@ class DataMapItem return $this->tableName; } - /** - * Gets the table name used to resolve the language parent record. - * - * @return string - */ - public function getFromTableName(): string - { - if ($this->tableName === 'pages_language_overlay') { - return 'pages'; - } - return $this->tableName; - } - - /** - * Gets the table name used to resolve any kind of translations. - * - * @return string - */ - public function getForTableName(): string - { - if ($this->tableName === 'pages') { - return 'pages_language_overlay'; - } - return $this->tableName; - } - /** * Gets the id of this data-map item. * diff --git a/typo3/sysext/core/Classes/DataHandling/Localization/DataMapProcessor.php b/typo3/sysext/core/Classes/DataHandling/Localization/DataMapProcessor.php index 4f5daa40f5c1..33784b29b745 100644 --- a/typo3/sysext/core/Classes/DataHandling/Localization/DataMapProcessor.php +++ b/typo3/sysext/core/Classes/DataHandling/Localization/DataMapProcessor.php @@ -141,41 +141,32 @@ class DataMapProcessor */ protected function collectItems(string $tableName, array $idValues) { - $forTableName = $tableName; - if ($forTableName === 'pages') { - $forTableName = 'pages_language_overlay'; - } - - if (!$this->isApplicable($forTableName)) { + if (!$this->isApplicable($tableName)) { return; } $fieldNames = [ 'uid' => 'uid', 'l10n_state' => 'l10n_state', - 'language' => $GLOBALS['TCA'][$forTableName]['ctrl']['languageField'], - 'parent' => $GLOBALS['TCA'][$forTableName]['ctrl']['transOrigPointerField'], + 'language' => $GLOBALS['TCA'][$tableName]['ctrl']['languageField'], + 'parent' => $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'], ]; - if (!empty($GLOBALS['TCA'][$forTableName]['ctrl']['translationSource'])) { - $fieldNames['source'] = $GLOBALS['TCA'][$forTableName]['ctrl']['translationSource']; + if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['translationSource'])) { + $fieldNames['source'] = $GLOBALS['TCA'][$tableName]['ctrl']['translationSource']; } - $translationValues = []; - // Fetching parent/source pointer values does not make sense for pages - if ($tableName !== 'pages') { - $translationValues = $this->fetchTranslationValues( + $translationValues = $this->fetchTranslationValues( + $tableName, + $fieldNames, + $this->filterNewItemIds( $tableName, - $fieldNames, - $this->filterNewItemIds( - $tableName, - $this->filterNumericIds(array_keys($idValues)) - ) - ); - } + $this->filterNumericIds(array_keys($idValues)) + ) + ); $dependencies = $this->fetchDependencies( - $forTableName, - $this->filterNewItemIds($forTableName, array_keys($idValues)) + $tableName, + $this->filterNewItemIds($tableName, array_keys($idValues)) ); foreach ($idValues as $id => $values) { @@ -297,7 +288,7 @@ class DataMapProcessor $fromRecord = ['uid' => $fromId]; if (MathUtility::canBeInterpretedAsInteger($fromId)) { $fromRecord = BackendUtility::getRecordWSOL( - $item->getFromTableName(), + $item->getTableName(), $fromId, $fieldNameList ); @@ -390,8 +381,8 @@ class DataMapProcessor $fromId = $fromRecord['uid']; // retrieve value from in-memory data-map - if ($this->isSetInDataMap($item->getFromTableName(), $fromId, $fieldName)) { - $fromValue = $this->allDataMap[$item->getFromTableName()][$fromId][$fieldName]; + if ($this->isSetInDataMap($item->getTableName(), $fromId, $fieldName)) { + $fromValue = $this->allDataMap[$item->getTableName()][$fromId][$fieldName]; } elseif (array_key_exists($fieldName, $fromRecord)) { // retrieve value from record $fromValue = $fromRecord[$fieldName]; @@ -401,13 +392,13 @@ class DataMapProcessor } // plain values - if (!$this->isRelationField($item->getFromTableName(), $fieldName)) { + if (!$this->isRelationField($item->getTableName(), $fieldName)) { $this->modifyDataMap( $item->getTableName(), $item->getId(), [$fieldName => $fromValue] ); - } elseif (!$this->isInlineRelationField($item->getFromTableName(), $fieldName)) { + } elseif (!$this->isInlineRelationField($item->getTableName(), $fieldName)) { // direct relational values $this->synchronizeDirectRelations($item, $fieldName, $fromRecord); } else { @@ -425,12 +416,12 @@ class DataMapProcessor */ protected function synchronizeDirectRelations(DataMapItem $item, string $fieldName, array $fromRecord) { - $configuration = $GLOBALS['TCA'][$item->getFromTableName()]['columns'][$fieldName]; + $configuration = $GLOBALS['TCA'][$item->getTableName()]['columns'][$fieldName]; $isSpecialLanguageField = ($configuration['config']['special'] ?? null) === 'languages'; $fromId = $fromRecord['uid']; - if ($this->isSetInDataMap($item->getFromTableName(), $fromId, $fieldName)) { - $fromValue = $this->allDataMap[$item->getFromTableName()][$fromId][$fieldName]; + if ($this->isSetInDataMap($item->getTableName(), $fromId, $fieldName)) { + $fromValue = $this->allDataMap[$item->getTableName()][$fromId][$fieldName]; } else { $fromValue = $fromRecord[$fieldName]; } @@ -439,7 +430,7 @@ class DataMapProcessor // if values are available in data-map already, just use them as well if ( empty($configuration['config']['MM']) - || $this->isSetInDataMap($item->getFromTableName(), $fromId, $fieldName) + || $this->isSetInDataMap($item->getTableName(), $fromId, $fieldName) || $isSpecialLanguageField ) { $this->modifyDataMap( @@ -470,7 +461,7 @@ class DataMapProcessor $tableNames, $manyToManyTable, $fromId, - $item->getFromTableName(), + $item->getTableName(), $configuration['config'] ); @@ -494,7 +485,7 @@ class DataMapProcessor */ protected function synchronizeInlineRelations(DataMapItem $item, string $fieldName, array $fromRecord, array $forRecord) { - $configuration = $GLOBALS['TCA'][$item->getFromTableName()]['columns'][$fieldName]; + $configuration = $GLOBALS['TCA'][$item->getTableName()]['columns'][$fieldName]; $isLocalizationModeExclude = ($configuration['l10n_mode'] ?? null) === 'exclude'; $foreignTableName = $configuration['config']['foreign_table']; @@ -652,16 +643,16 @@ class DataMapProcessor { $suggestedAncestorIds = []; $fromId = $fromRecord['uid']; - $configuration = $GLOBALS['TCA'][$item->getFromTableName()]['columns'][$fieldName]; + $configuration = $GLOBALS['TCA'][$item->getTableName()]['columns'][$fieldName]; $foreignTableName = $configuration['config']['foreign_table']; $manyToManyTable = ($configuration['config']['MM'] ?? ''); // determine suggested elements of either translation parent or source record // from data-map, in case the accordant language parent/source record was modified - if ($this->isSetInDataMap($item->getFromTableName(), $fromId, $fieldName)) { + if ($this->isSetInDataMap($item->getTableName(), $fromId, $fieldName)) { $suggestedAncestorIds = GeneralUtility::trimExplode( ',', - $this->allDataMap[$item->getFromTableName()][$fromId][$fieldName], + $this->allDataMap[$item->getTableName()][$fromId][$fieldName], true ); } elseif (MathUtility::canBeInterpretedAsInteger($fromId)) { @@ -672,7 +663,7 @@ class DataMapProcessor $foreignTableName, $manyToManyTable, $fromId, - $item->getFromTableName(), + $item->getTableName(), $configuration['config'] ); $suggestedAncestorIds = $this->mapRelationItemId($relationHandler->itemArray); @@ -692,7 +683,7 @@ class DataMapProcessor private function resolvePersistedInlineRelations(DataMapItem $item, string $fieldName, array $forRecord): array { $persistedIds = []; - $configuration = $GLOBALS['TCA'][$item->getFromTableName()]['columns'][$fieldName]; + $configuration = $GLOBALS['TCA'][$item->getTableName()]['columns'][$fieldName]; $foreignTableName = $configuration['config']['foreign_table']; $manyToManyTable = ($configuration['config']['MM'] ?? ''); @@ -789,8 +780,7 @@ class DataMapProcessor /** * Fetches translation related field values for the items submitted in - * the data-map. That's why further adjustment for the tables pages vs. - * pages_language_overlay is not required. + * the data-map. * * @param string $tableName * @param array $fieldNames @@ -842,10 +832,6 @@ class DataMapProcessor */ protected function fetchDependencies(string $tableName, array $ids) { - if ($tableName === 'pages') { - $tableName = 'pages_language_overlay'; - } - if (!BackendUtility::isTableLocalizable($tableName)) { return []; } @@ -923,10 +909,6 @@ class DataMapProcessor */ protected function fetchDependentIdMap(string $tableName, array $ids, int $desiredLanguage) { - if ($tableName === 'pages') { - $tableName = 'pages_language_overlay'; - } - $ids = $this->filterNumericIds($ids, true); $isTranslatable = BackendUtility::isTableLocalizable($tableName); $originFieldName = ($GLOBALS['TCA'][$tableName]['ctrl']['origUid'] ?? null); @@ -1341,10 +1323,6 @@ class DataMapProcessor */ protected function getPrefixLanguageTitleFieldNames(string $tableName) { - if ($tableName === 'pages') { - $tableName = 'pages_language_overlay'; - } - $prefixLanguageTitleFieldNames = []; if (empty($GLOBALS['TCA'][$tableName]['columns'])) { return $prefixLanguageTitleFieldNames; diff --git a/typo3/sysext/core/Classes/Migrations/TcaMigration.php b/typo3/sysext/core/Classes/Migrations/TcaMigration.php index f54f61bcbdab..2add591b0200 100644 --- a/typo3/sysext/core/Classes/Migrations/TcaMigration.php +++ b/typo3/sysext/core/Classes/Migrations/TcaMigration.php @@ -88,6 +88,7 @@ class TcaMigration $tca = $this->migrateinputDateTimeMax($tca); $tca = $this->migrateInlineOverrideChildTca($tca); $tca = $this->migrateLocalizeChildrenAtParentLocalization($tca); + $tca = $this->migratePagesLanguageOverlayRemoval($tca); return $tca; } @@ -975,70 +976,36 @@ class TcaMigration protected function migratePageLocalizationDefinitions(array $tca) { if ( - empty($tca['pages']['columns']) - || empty($tca['pages_language_overlay']['columns']) + empty($tca['pages_language_overlay']['columns']) ) { return $tca; } // ensure, that localization settings are defined for - // pages_language_overlay and not only for pages - foreach ($tca['pages']['columns'] as $fieldName => &$fieldConfig) { + // pages and not for pages_language_overlay + foreach ($tca['pages_language_overlay']['columns'] as $fieldName => &$fieldConfig) { $l10nMode = $fieldConfig['l10n_mode'] ?? null; $allowLanguageSynchronization = $fieldConfig['config']['behaviour']['allowLanguageSynchronization'] ?? null; - $oppositeFieldConfig = $tca['pages_language_overlay']['columns'][$fieldName] ?? []; + $oppositeFieldConfig = $tca['pages']['columns'][$fieldName] ?? []; $oppositeL10nMode = $oppositeFieldConfig['l10n_mode'] ?? null; $oppositeAllowLanguageSynchronization = $oppositeFieldConfig['config']['behaviour']['allowLanguageSynchronization'] ?? null; if ($l10nMode !== null) { if (!empty($oppositeFieldConfig) && $oppositeL10nMode !== 'exclude') { - $tca['pages_language_overlay']['columns'][$fieldName]['l10n_mode'] = $l10nMode; + $tca['pages']['columns'][$fieldName]['l10n_mode'] = $l10nMode; $this->messages[] = 'The TCA setting \'l10n_mode\' was migrated ' - . 'to TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\'] ' - . 'from TCA pages[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']'; - } - unset($fieldConfig['l10n_mode']); - $this->messages[] = 'The TCA setting \'l10n_mode\' was removed ' - . 'in TCA pages[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']'; - } - - if (!empty($allowLanguageSynchronization)) { - if (!empty($oppositeFieldConfig) && empty($oppositeAllowLanguageSynchronization)) { - $tca['pages_language_overlay']['columns'][$fieldName]['config']['behaviour']['allowLanguageSynchronization'] = (bool)$allowLanguageSynchronization; - $this->messages[] = 'The TCA setting \'allowLanguageSynchronization\' was migrated ' - . 'to TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\']' - . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\'] ' - . 'from TCA pages[\'columns\'][\'' . $fieldName . '\']' - . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\']'; + . 'to TCA pages[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\'] ' + . 'from TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']'; } - unset($fieldConfig['config']['behaviour']['allowLanguageSynchronization']); - $this->messages[] = 'The TCA setting \'allowLanguageSynchronization\' was removed ' - . 'in TCA pages[\'columns\'][\'' . $fieldName . '\']' - . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\']'; - } - } - - // clean up localization settings in pages_language_overlay that cannot - // be used since the fields in pages are just not configured/available - foreach ($tca['pages_language_overlay']['columns'] as $fieldName => &$fieldConfig) { - $l10nMode = $fieldConfig['l10n_mode'] ?? null; - $allowLanguageSynchronization = $fieldConfig['config']['behaviour']['allowLanguageSynchronization'] ?? null; - $oppositeFieldConfig = $tca['pages']['columns'][$fieldName] ?? []; - - if (!empty($oppositeFieldConfig)) { - continue; } - if ($l10nMode !== null) { - unset($fieldConfig['l10n_mode']); - $this->messages[] = 'The TCA setting \'l10n_mode\' was removed ' - . 'in TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\'][\'l10n_mode\']'; - } - if (!empty($allowLanguageSynchronization)) { - unset($fieldConfig['config']['behaviour']['allowLanguageSynchronization']); - $this->messages[] = 'The TCA setting \'allowLanguageSynchronization\' was removed ' - . 'in TCA pages[\'columns\'][\'' . $fieldName . '\']' + if (!empty($allowLanguageSynchronization) && empty($oppositeAllowLanguageSynchronization)) { + $tca['pages']['columns'][$fieldName]['config']['behaviour']['allowLanguageSynchronization'] = (bool)$allowLanguageSynchronization; + $this->messages[] = 'The TCA setting \'allowLanguageSynchronization\' was migrated ' + . 'to TCA pages[\'columns\'][\'' . $fieldName . '\']' + . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\'] ' + . 'from TCA pages_language_overlay[\'columns\'][\'' . $fieldName . '\']' . '[\'config\'][\'behaviour\'][\'allowLanguageSynchronization\']'; } } @@ -2561,4 +2528,21 @@ class TcaMigration } return $tca; } + + /** + * Removes $TCA['pages_language_overlay'] if defined. + * + * @param array $tca + * @return array the modified TCA structure + */ + protected function migratePagesLanguageOverlayRemoval(array $tca) + { + if (isset($tca['pages_language_overlay'])) { + $this->messages[] = 'The TCA table \'pages_language_overlay\' is' + . ' not used anymore and has been removed automatically in' + . ' order to avoid negative side-effects.'; + unset($tca['pages_language_overlay']); + } + return $tca; + } } diff --git a/typo3/sysext/core/Classes/Utility/RootlineUtility.php b/typo3/sysext/core/Classes/Utility/RootlineUtility.php index 5dba704bc54d..a2e1908d8d10 100644 --- a/typo3/sysext/core/Classes/Utility/RootlineUtility.php +++ b/typo3/sysext/core/Classes/Utility/RootlineUtility.php @@ -273,7 +273,7 @@ class RootlineUtility /** * Resolve relations as defined in TCA and add them to the provided $pageRecord array. * - * @param int $uid Either pages.uid or pages_language_overlay.uid if localized + * @param int $uid page ID * @param array $pageRecord Page record (possibly overlaid) to be extended with relations * @throws \RuntimeException * @return array $pageRecord with additional relations @@ -336,7 +336,7 @@ class RootlineUtility $queryBuilder->expr()->eq( trim($configuration['foreign_table_field']), $queryBuilder->createNamedParameter( - (int)$this->languageUid > 0 ? 'pages_language_overlay' : 'pages', + 'pages', \PDO::PARAM_STR ) ) diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php index 76001ce283ee..99aeadf32b1f 100644 --- a/typo3/sysext/core/Configuration/DefaultConfiguration.php +++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php @@ -322,8 +322,14 @@ return [ \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseEditRow::class, ], ], + \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseDefaultLanguagePageRow::class => [ + 'depends' => [ + \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseParentPageRow::class, + ], + ], \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseUserPermissionCheck::class => [ 'depends' => [ + \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseDefaultLanguagePageRow::class, \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseParentPageRow::class, \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class, ], @@ -896,7 +902,6 @@ return [ sys_filemounts.after = be_users sys_file_storage.after = sys_filemounts sys_language.after = sys_file_storage - pages_language_overlay.before = pages fe_users.after = fe_groups fe_users.before = pages sys_template.after = pages diff --git a/typo3/sysext/core/Configuration/TCA/pages.php b/typo3/sysext/core/Configuration/TCA/pages.php index 99fc3a64ad01..900f92e4e8e9 100644 --- a/typo3/sysext/core/Configuration/TCA/pages.php +++ b/typo3/sysext/core/Configuration/TCA/pages.php @@ -15,6 +15,10 @@ return [ 'cruser_id' => 'cruser_id', 'editlock' => 'editlock', 'useColumnsForDefaultValues' => 'doktype,fe_group,hidden', + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'translationSource' => 'l10n_source', 'enablecolumns' => [ 'disabled' => 'hidden', 'starttime' => 'starttime', @@ -128,6 +132,7 @@ return [ ] ], 'title' => [ + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:title', 'config' => [ 'type' => 'input', @@ -138,6 +143,7 @@ return [ ], 'TSconfig' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'TSconfig:', 'config' => [ 'type' => 'text', @@ -149,6 +155,7 @@ return [ ], 'php_tree_stop' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:php_tree_stop', 'config' => [ 'type' => 'check', @@ -169,6 +176,7 @@ return [ ], 'editlock' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:editlock', 'config' => [ 'type' => 'check', @@ -181,6 +189,7 @@ return [ ], 'hidden' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.hidden', 'config' => [ 'type' => 'check', @@ -194,6 +203,7 @@ return [ ], 'starttime' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.starttime', 'config' => [ 'type' => 'input', @@ -204,6 +214,7 @@ return [ ], 'endtime' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.endtime', 'config' => [ 'type' => 'input', @@ -215,8 +226,55 @@ return [ ] ] ], + 'l10n_parent' => [ + 'exclude' => true, + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'items' => [ + [ + '', + 0 + ] + ], + 'foreign_table' => 'pages', + // no sys_language_uid = -1 allowed explicitly! + 'foreign_table_where' => 'AND pages.uid=###CURRENT_PID### AND pages.sys_language_uid = 0', + 'default' => 0 + ] + ], + 'sys_language_uid' => [ + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'sys_language', + 'foreign_table_where' => 'ORDER BY sys_language.sorting', + 'items' => [], // no default language here, as the pages table is always the default language + 'default' => 0, + 'fieldWizard' => [ + 'selectIcons' => [ + 'disabled' => false, + ], + ], + ] + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + 'default' => '' + ] + ], + 'l10n_source' => [ + 'config' => [ + 'type' => 'passthrough' + ] + ], 'layout' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.layout', 'config' => [ 'type' => 'select', @@ -244,6 +302,7 @@ return [ ], 'fe_group' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.fe_group', 'config' => [ 'type' => 'select', @@ -272,6 +331,7 @@ return [ ], 'extendToSubpages' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.extendToSubpages', 'config' => [ 'type' => 'check', @@ -294,6 +354,7 @@ return [ ], 'nav_hide' => [ 'exclude' => true, + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.nav_hide', 'config' => [ 'type' => 'check', @@ -306,6 +367,7 @@ return [ ], 'subtitle' => [ 'exclude' => true, + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.subtitle', 'config' => [ 'type' => 'input', @@ -316,6 +378,7 @@ return [ ], 'target' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.target', 'config' => [ 'type' => 'input', @@ -332,6 +395,7 @@ return [ 'alias' => [ 'exclude' => true, 'displayCond' => 'VERSION:IS:false', + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.alias', 'config' => [ 'type' => 'input', @@ -348,7 +412,10 @@ return [ 'size' => 23, 'max' => 255, 'eval' => 'trim,required', - 'softref' => 'url' + 'softref' => 'url', + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'lastUpdated' => [ @@ -358,7 +425,10 @@ return [ 'type' => 'input', 'renderType' => 'inputDateTime', 'eval' => 'datetime', - 'default' => 0 + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'newUntil' => [ @@ -368,11 +438,15 @@ return [ 'type' => 'input', 'renderType' => 'inputDateTime', 'eval' => 'date', - 'default' => 0 + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'cache_timeout' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.cache_timeout', 'config' => [ 'type' => 'select', @@ -428,6 +502,7 @@ return [ ], 'cache_tags' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.cache_tags', 'config' => [ 'type' => 'input', @@ -445,6 +520,9 @@ return [ '1' => [ '0' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.no_search_checkbox_1_formlabel' ] + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true ] ] ], @@ -462,7 +540,10 @@ return [ 'additionalSearchFields' => 'nav_title, alias, url' ] ], - 'default' => 0 + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'shortcut_mode' => [ @@ -489,11 +570,15 @@ return [ \TYPO3\CMS\Frontend\Page\PageRepository::SHORTCUT_MODE_PARENT_PAGE ] ], - 'default' => 0 + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'content_from_pid' => [ 'exclude' => true, + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.content_from_pid', 'config' => [ 'type' => 'group', @@ -506,6 +591,7 @@ return [ ] ], 'mount_pid' => [ + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.mount_pid', 'config' => [ 'type' => 'group', @@ -519,6 +605,7 @@ return [ ], 'keywords' => [ 'exclude' => true, + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.keywords', 'config' => [ 'type' => 'text', @@ -528,6 +615,7 @@ return [ ], 'description' => [ 'exclude' => true, + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.description', 'config' => [ 'type' => 'text', @@ -537,6 +625,7 @@ return [ ], 'abstract' => [ 'exclude' => true, + 'l10n_mode' => 'prefixLangTitle', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.abstract', 'config' => [ 'type' => 'text', @@ -551,7 +640,10 @@ return [ 'type' => 'input', 'size' => 23, 'eval' => 'trim', - 'max' => 80 + 'max' => 80, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'author_email' => [ @@ -562,7 +654,10 @@ return [ 'size' => 23, 'eval' => 'trim', 'max' => 80, - 'softref' => 'email[subst]' + 'softref' => 'email[subst]', + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ], 'media' => [ @@ -606,11 +701,15 @@ return [ ] ], ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] ] ) ], 'is_siteroot' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.is_siteroot', 'config' => [ 'type' => 'check', @@ -623,6 +722,7 @@ return [ ], 'mount_pid_ol' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.mount_pid_ol', 'config' => [ 'type' => 'radio', @@ -640,6 +740,7 @@ return [ ], 'module' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.module', 'config' => [ 'type' => 'select', @@ -661,6 +762,7 @@ return [ ], 'fe_login_mode' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.fe_login_mode', 'config' => [ 'type' => 'select', @@ -687,6 +789,7 @@ return [ ], 'l18n_cfg' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.l18n_cfg', 'config' => [ 'type' => 'check', @@ -704,6 +807,7 @@ return [ ], 'backend_layout' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.backend_layout_formlabel', 'config' => [ 'type' => 'select', @@ -719,11 +823,12 @@ return [ ], ], 'size' => 1, - 'maxitems' => 1, + 'maxitems' => 1 ] ], 'backend_layout_next_level' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.backend_layout_next_level_formlabel', 'config' => [ 'type' => 'select', @@ -739,11 +844,12 @@ return [ ], ], 'size' => 1, - 'maxitems' => 1, + 'maxitems' => 1 ] ], 'tsconfig_includes' => [ 'exclude' => true, + 'l10n_mode' => 'exclude', 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tsconfig_includes', 'config' => [ 'type' => 'select', diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-82445-PagesAndPageTranslations.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-82445-PagesAndPageTranslations.rst new file mode 100644 index 000000000000..7eb88300a6a9 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Breaking-82445-PagesAndPageTranslations.rst @@ -0,0 +1,61 @@ +.. include:: ../../Includes.txt + +============================================== +Breaking: #82445 - Pages and page translations +============================================== + +See :issue:`82445` + +Description +=========== + +The database table "pages_language_overlay" has been obsoleted in the core and is +not used and updated anymore. Page translation records are now handled in the "pages" +table directly. + + +Impact +====== + +This change has a huge impact on page and page translation handling, especially +on database record level: + +* Table "pages_language_overlay" is no longer read by core code +* Records in "pages_language_overlay" are no longer updated by core code +* Records in "pages_language_overlay" are no longer shown in the backend +* Table and TCA definition for "pages_language_overlay" will be dropped in v10 +* Queries to table "pages" should now observe the "sys_language_uid" field to + fetch default language records only. A casual case for this are tree traversal + queries for children or rootline fetching. If additional restrictions are not + added, the query result may return page translations along the default language row. +* Existing inline relations with "foreign_table" and "foreign_field" and "foreign_table_field" + on a "pages_language_overlay" TCA are migrated to "pages". This works well for + typical FAL relations like the default "media" field. +* Complex TCA relations with "inline" "group" that use an "MM" table in TCA + not automatically get their relation record rows migrated. Configurations + like these are seldom and need manual migration steps depending on their + TCA configuration when upgrading. + + +Affected installations +====================== + +Single language instances are not affected. For sites with translations and +non-empty "pages_language_overlay" table, the main data merging is done with +upgrade wizards, but it may happen that TypoScript and extensions may need +adaptions, for instance if they write and read data from "pages" or +"pages_language_overlay" directly. + + +Migration +========= + +The following backwards-compatibility are met until TYPO3 v10.0: + +* The TCA definition for "pages_language_overlay" is kept as part of handling extensions supporting v8 and v9 +* The database table "pages_language_overlay" is kept as is, but not updated anymore by core +* A database field within "pages" is keeping the old pages_language_overlay record UID +* An upgrade wizard merges records from "pages_language_overlay" into "pages" +* An upgrade wizard adapts "be_groups" access restrictions for "pages_language_overlay" towards "pages" + +.. index:: Backend, Database, PHP-API, TCA, NotScanned diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82445-PageTranslationRelatedFunctionality.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82445-PageTranslationRelatedFunctionality.rst new file mode 100644 index 000000000000..bcfbb64dc895 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82445-PageTranslationRelatedFunctionality.rst @@ -0,0 +1,47 @@ +.. include:: ../../Includes.txt + +============================================================ +Deprecation: #82445 - Page translation related functionality +============================================================ + +See :issue:`82445` + +Description +=========== + +With the merge of row content from table "pages_language_overlay" into "pages" +various core functionality has been deprecated. + +Methods: +* :php:`TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider->getTranslationTable()` +* :php:`TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider->isTranslationInOwnTable()` +* :php:`TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider->foreignTranslationTable()` +* :php:`TYPO3\CMS\Backend\Utility\BackendUtility::getOriginalTranslationTable()` + +Additionally, the automatic TCA migration performed by the TYPO3 bootstrap now merges flags of type +:php:`['columns']['someField']['config']['behaviour']['allowLanguageSynchronization'] from +table "pages_language_overlay" into "pages". + + +Impact +====== + +A deprecation warning is thrown calling one of the above methods and if the TCA migration +changes the 'allowLanguageSynchronization' flag. + + +Affected Installations +====================== + +Instances using the above methods or TCA configuration. The install tool extension scanner will +find affected extensions and the TCA migrations check of the install tool shows applied TCA migrations. + + +Migration +========= + +The functionality to have language overlays records in a different table than the table the default language +records are in has been removed. It is safe to no longer check for this and use 'pages' for page language +overlay records directly. + +.. index:: Backend, PHP-API, TCA, FullyScanned diff --git a/typo3/sysext/core/Documentation/Changelog/master/Important-82445-MigratePagesLanguageOverlayIntoPages.rst b/typo3/sysext/core/Documentation/Changelog/master/Important-82445-MigratePagesLanguageOverlayIntoPages.rst new file mode 100644 index 000000000000..20eb5928ca73 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Important-82445-MigratePagesLanguageOverlayIntoPages.rst @@ -0,0 +1,53 @@ +.. include:: ../../Includes.txt + +============================================================= +Important: #82445 - Migrate pages_language_overlay into pages +============================================================= + +See :issue:`82445` + +Description +=========== + +The functionality of "pages_language_overlay" has been migrated into "pages". + +An upgrade wizard is in place to migrate all existing data into the "pages" database table. + +All relations directly to "pages_language_overlay" are migrated to the newly created "pages" records +as well. + +Some rules for future development need to be clarified: + +Definitions: + +**Default Language Page** + +- previously exclusively available in "pages" +- Holds the PID of the parent page +- MUST be in place in order to create a translated page (not possible to create a translated page without having a default page in place) +- Has always "l10n_parent" and "sys_language_uid" fields set to "0" +- The "uid" of this record is automatically the PID for all records of this page + +**Translated Page** (previously known as "pages_language_overlay") + +- Is identified as *Translated Page* by having a "sys_language_uid" field greater 0 and "l10n_parent" field containing the "uid" of the *Default Language Page*. +- The value of the "pid" field is the same "pid" as of the *Default Language Page* - effectively putting the *Translated Page* and the *Default Language Page* on the same root-level. +- The value of "sorting" is the same for all translated pages +- The "uid" field is not used by anything currently within the TYPO3 Core. +- The "hidden" field is set as "allowLanguageSynchronization" + + +**The following details apply** + +- Any TCA-based records (= subpages, content elements) still ALWAYS contain the pid to the *Original Language Page*, a DataHandler restriction ensures this constraint. +- Backend: All UI elements like Element Browser, Page Browser etc. are restricted to only show the *Default Translation Pages* to be selected (one can not link to a specific Translated Page). +- Permissions are always fetched from the "Original Language Page" +- DataHandler: Moving or deleting of a *Default Language Page* always moves/deletes the associated *Translated Page* records as well. +- DataHandler: "sorting" and "pid" parameters of translations are always kept in sync one-to-one for translated pages. Translated pages cannot be moved themselves. +- Permissions: Restricting a Backend User/Group to a language limits the access to "pages" to a specific language in page module. +- Permissions: All existing "pages_language_overlay" permissions are merged into "pages" options for all records - when a Backend User/Group is limited to only certain languages (and not the default language) this , the . If a Backend User/Group does have permission on "pages_language_overlay" but not "pages", the Backend User/Group has automatically assigned all translations (sys_language_uid) as language limitations. +- Frontend: Requesting a page can be done with ?id=originalpage&L=1 or ?id=translatedpage where "?id=translatedpage" internally resolves the "id" parameter to the uid of the Original Language Page and the "L" parameter resolved to the "sys_language_uid" corresponding in the TypoScript options. +- Frontend: All "pid" checks are always done against the Original Language Page, as all records still sit on that page. +- Frontend: Generating a link to a *Default Translation Page* with a current Translated Page generated, will exchange the target on link creation to the targeted Translated Page automatically. + +.. index:: Database, PHP-API diff --git a/typo3/sysext/core/Resources/Private/Language/locallang_csh_pageslol.xlf b/typo3/sysext/core/Resources/Private/Language/locallang_csh_pageslol.xlf deleted file mode 100644 index 1129ccdf585d..000000000000 --- a/typo3/sysext/core/Resources/Private/Language/locallang_csh_pageslol.xlf +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff"> - <file t3:id="1415814798" source-language="en" datatype="plaintext" original="messages" date="2011-10-17T20:22:32Z" product-name="context_help"> - <header/> - <body> - <trans-unit id=".description"> - <source>Represents an alternative language for the page.</source> - </trans-unit> - <trans-unit id=".details" xml:space="preserve"> - <source>These records contains fields very similar to the Page records, exactly those fields which should be translated to another language in case you want a localized version of the page. -Create only ONE Alternative Page Language record of a specific language in each page. Having more than one record will leave it uncertain which of them is used when the page is displayed. - -Before you can create Alternative Page Language records you should create a 'master' language to be available in the root of the website ("Website Language") -The TypoScript template must be configured to allow other languages as well. - -Technically when an alternative language is being viewed, the content of the Alternative Page Language record is simply overlaid on the actual page records thus substituting the content of the fields in the default language.</source> - </trans-unit> - <trans-unit id="_.seeAlso" xml:space="preserve"> - <source>sys_language, -_MOD_web_layout:language_list</source> - </trans-unit> - <trans-unit id="hidden.description"> - <source>Use this to temporarily disable the alternative language overlay for this page.</source> - </trans-unit> - <trans-unit id="hidden.details"> - <source>Setting this option is practical in the phase of adding the extra language. When it is set, the alternative content will not be displayed unless you - as an logged in backend user - enables the Admin Panel>Preview>Show hidden records option.</source> - </trans-unit> - <trans-unit id="_hidden.seeAlso" xml:space="preserve"> - <source>pages_language_overlay:starttime, -pages_language_overlay:endtime</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="starttime.description"> - <source>The 'Start' time determines the date from which the alternative language will be available online.</source> - </trans-unit> - <trans-unit id="_starttime.seeAlso" xml:space="preserve"> - <source>pages_language_overlay:endtime, -pages_language_overlay:hidden, -pages:starttime</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="endtime.description"> - <source>The 'End' time determines the date from which the alternative language will be available online.</source> - </trans-unit> - <trans-unit id="_endtime.seeAlso" xml:space="preserve"> - <source>pages_language_overlay:starttime, -pages_language_overlay:hidden, -pages:endtime</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="title.description"> - <source>Enter the title of the alternative language.</source> - </trans-unit> - <trans-unit id="_title.seeAlso"> - <source>pages:title</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="subtitle.description"> - <source>Enter the subtitle of the alternative language.</source> - </trans-unit> - <trans-unit id="_subtitle.seeAlso"> - <source>pages:subtitle</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="keywords.description"> - <source>Enter the keywords of the alternative language.</source> - </trans-unit> - <trans-unit id="_keywords.seeAlso"> - <source>pages:keywords</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="description.description"> - <source>Enter the description of the alternative language.</source> - </trans-unit> - <trans-unit id="_description.seeAlso"> - <source>pages:description</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="abstract.description"> - <source>Enter the abstract of the alternative language.</source> - </trans-unit> - <trans-unit id="_abstract.seeAlso"> - <source>pages:abstract</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="author.description"> - <source>Enter the author of the alternative language.</source> - </trans-unit> - <trans-unit id="_author.seeAlso"> - <source>pages:author</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="author_email.description"> - <source>Enter the author email address of the alternative language.</source> - </trans-unit> - <trans-unit id="_author_email.seeAlso"> - <source>pages:author_email</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="media.description"> - <source>Enter the media files of the alternative language.</source> - </trans-unit> - <trans-unit id="_media.seeAlso"> - <source>pages:media</source> - <note from="developer">This string contains an internal text, which must not be changed. Just copy the original text into the translation field. For more information have a look at the Tutorial.</note> - </trans-unit> - <trans-unit id="sys_language_uid.description"> - <source>Select the Alternative Language represented by this record.</source> - </trans-unit> - <trans-unit id="_sys_language_uid.seeAlso" xml:space="preserve"> - <source>sys_language, -sys_language:title</source> - </trans-unit> - <trans-unit id="nav_title.description"> - <source>Enter optional navigation title of the alternative language.</source> - </trans-unit> - </body> - </file> -</xliff> diff --git a/typo3/sysext/core/Resources/Private/Language/locallang_csh_syslang.xlf b/typo3/sysext/core/Resources/Private/Language/locallang_csh_syslang.xlf index bf69873230c0..460830ea1ad4 100644 --- a/typo3/sysext/core/Resources/Private/Language/locallang_csh_syslang.xlf +++ b/typo3/sysext/core/Resources/Private/Language/locallang_csh_syslang.xlf @@ -13,11 +13,7 @@ <source>Defines which languages are alternatively available on each webpage.</source> </trans-unit> <trans-unit id=".details" xml:space="preserve"> - <source>The Web>Page module has a feature which allows users to edit page content divided into not only columns but also languages. The languages available for translation are determined by the number of Website Language record created. -For a webpage to be available in another language an "Alternative Page Language" record must be created on the page.</source> - </trans-unit> - <trans-unit id="_.seeAlso"> - <source>pages_language_overlay</source> + <source>The Web>Page module has a feature which allows users to edit page content divided into not only columns but also languages. The languages available for translation are determined by the number of Website Language record created.</source> </trans-unit> </body> </file> 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 fae8dcfdcb9a..caf26096f77d 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php @@ -33,7 +33,6 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D const VALUE_LanguageIdSecond = 2; const TABLE_Page = 'pages'; - const TABLE_PageOverlay = 'pages_language_overlay'; const TABLE_Content = 'tt_content'; const TABLE_Hotel = 'tx_irretutorial_1nff_hotel'; const TABLE_Offer = 'tx_irretutorial_1nff_offer'; @@ -413,19 +412,21 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D public function localizePageWithLocalizationExclude() { $GLOBALS['TCA'][self::TABLE_Page]['columns'][self::FIELD_PageHotel]['l10n_mode'] = 'exclude'; - $GLOBALS['TCA'][self::TABLE_PageOverlay]['columns'][self::FIELD_PageHotel]['l10n_mode'] = 'exclude'; + // 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; $localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_LanguageId); $this->recordIds['localizedPageId'] = $localizedTableIds[self::TABLE_Page][self::VALUE_PageId]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; } public function localizePageAndAddHotelChildWithLocalizationExclude() { $GLOBALS['TCA'][self::TABLE_Page]['columns'][self::FIELD_PageHotel]['l10n_mode'] = 'exclude'; - $GLOBALS['TCA'][self::TABLE_PageOverlay]['columns'][self::FIELD_PageHotel]['l10n_mode'] = 'exclude'; + // 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; $localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_LanguageId); $this->recordIds['localizedPageId'] = $localizedTableIds[self::TABLE_Page][self::VALUE_PageId]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; $this->actionService->modifyRecords( self::VALUE_PageId, [ @@ -437,18 +438,22 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D public function localizePageWithLanguageSynchronization() { - $GLOBALS['TCA'][self::TABLE_PageOverlay]['columns'][self::FIELD_PageHotel]['config']['behaviour']['allowLanguageSynchronization'] = true; + // 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]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; } public function localizePageAndAddHotelChildWithLanguageSynchronization() { - $GLOBALS['TCA'][self::TABLE_PageOverlay]['columns'][self::FIELD_PageHotel]['config']['behaviour']['allowLanguageSynchronization'] = true; + // 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]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; $this->actionService->modifyRecords( self::VALUE_PageId, [ @@ -460,12 +465,14 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D public function localizePageAndAddMonoglotHotelChildWithLanguageSynchronization() { + // 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; unset($GLOBALS['TCA'][self::TABLE_Hotel]['ctrl']['languageField']); unset($GLOBALS['TCA'][self::TABLE_Hotel]['ctrl']['transOrigPointerField']); - $GLOBALS['TCA'][self::TABLE_PageOverlay]['columns'][self::FIELD_PageHotel]['config']['behaviour']['allowLanguageSynchronization'] = true; + $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]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; $this->actionService->modifyRecords( self::VALUE_PageId, [ @@ -477,10 +484,12 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D public function localizeAndCopyPageWithLanguageSynchronization() { - $GLOBALS['TCA'][self::TABLE_PageOverlay]['columns'][self::FIELD_PageHotel]['config']['behaviour']['allowLanguageSynchronization'] = true; + // 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]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; $newTableIds = $this->actionService->copyRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_PageIdTarget); $this->recordIds['newPageId'] = $newTableIds[self::TABLE_Page][self::VALUE_PageId]; } diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizeNCopyPageWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizeNCopyPageWSynchronization.csv index f14a18824ad0..569284d74991 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizeNCopyPageWSynchronization.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizeNCopyPageWSynchronization.csv @@ -1,42 +1,40 @@ 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,1 -,90,88,512,0,0,0,0,0,0,0,Target,0 -,91,90,256,0,89,0,0,0,0,0,Relations,1 -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",1,"{""tx_irretutorial_hotels"":""parent""}" -,2,91,0,1,0,0,0,0,"[Translate to Dansk:] Relations",1,"{""tx_irretutorial_hotels"":""parent""}" +,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",1,"{""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""}" +,92,90,256,0,0,0,89,0,0,0,0,0,Relations,1, +,93,90,256,0,1,92,91,0,0,0,0,0,"[Translate to Dansk:] Relations",1,"{""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""}" 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 +,299,92,256,0,0,0,298,0,0,0,0,0,"Regular Element #2",1 +,300,92,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,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",1,pages_language_overlay,,0 -,7,91,1,0,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,0 -,8,91,1,0,1,7,6,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",2,pages_language_overlay,,0 -,9,91,1,0,0,0,5,0,0,0,0,0,"Hotel #1",299,tt_content,,1 -,10,91,1,0,0,0,3,0,0,0,0,0,"Hotel #1",300,tt_content,,2 -,11,91,2,0,0,0,4,0,0,0,0,0,"Hotel #2",300,tt_content,,1 +,6,89,1,0,1,2,2,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",91,pages,,0 +,7,92,1,0,0,0,2,0,0,0,0,0,"Hotel #0",92,pages,,0 +,8,92,1,0,1,7,6,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",93,pages,,0 +,9,92,1,0,0,0,5,0,0,0,0,0,"Hotel #1",299,tt_content,,1 +,10,92,1,0,0,0,3,0,0,0,0,0,"Hotel #1",300,tt_content,,2 +,11,92,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",9,tx_irretutorial_1nff_hotel,,1 -,10,91,1,0,0,0,5,0,0,0,0,0,"Offer #1.1",10,tx_irretutorial_1nff_hotel,,3 -,11,91,2,0,0,0,6,0,0,0,0,0,"Offer #1.2",10,tx_irretutorial_1nff_hotel,,2 -,12,91,1,0,0,0,7,0,0,0,0,0,"Offer #2.1",11,tx_irretutorial_1nff_hotel,,1 +,9,92,1,0,0,0,8,0,0,0,0,0,"Offer #1.1",9,tx_irretutorial_1nff_hotel,,1 +,10,92,1,0,0,0,5,0,0,0,0,0,"Offer #1.1",10,tx_irretutorial_1nff_hotel,,3 +,11,92,2,0,0,0,6,0,0,0,0,0,"Offer #1.2",10,tx_irretutorial_1nff_hotel,,2 +,12,92,1,0,0,0,7,0,0,0,0,0,"Offer #2.1",11,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, @@ -46,10 +44,10 @@ tx_irretutorial_1nff_price ,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, +,14,92,1,0,0,0,13,0,0,0,0,0,"Price #1.1.1",9,tx_irretutorial_1nff_offer, +,15,92,1,0,0,0,7,0,0,0,0,0,"Price #1.1.1",10,tx_irretutorial_1nff_offer, +,16,92,2,0,0,0,8,0,0,0,0,0,"Price #1.1.2",10,tx_irretutorial_1nff_offer, +,17,92,3,0,0,0,9,0,0,0,0,0,"Price #1.1.3",10,tx_irretutorial_1nff_offer, +,18,92,1,0,0,0,10,0,0,0,0,0,"Price #1.2.1",11,tx_irretutorial_1nff_offer, +,19,92,2,0,0,0,11,0,0,0,0,0,"Price #1.2.2",11,tx_irretutorial_1nff_offer, +,20,92,1,0,0,0,12,0,0,0,0,0,"Price #2.1.1",12,tx_irretutorial_1nff_offer, 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 index 12f915614868..be2da9bd0ce7 100644 --- 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 @@ -1,46 +1,44 @@ 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""}" +,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,2, +,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""}" +,92,90,256,0,0,0,89,0,0,0,0,0,Relations,2, +,93,90,256,0,1,92,91,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""}" 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 +,299,92,256,0,0,0,298,0,0,0,0,0,"Regular Element #2",1 +,300,92,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 +,6,89,1,0,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,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 +,8,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",91,pages,,0 +,9,92,1,0,0,0,2,0,0,0,0,0,"Hotel #0",92,pages,,0 +,10,92,2,0,0,0,7,0,0,0,0,0,"Hotel #007",92,pages,,0 +,11,92,1,0,0,0,6,0,0,0,0,0,"Hotel #0",93,pages,,0 +,12,92,2,0,0,0,8,0,0,0,0,0,"Hotel #007",93,pages,,0 +,13,92,1,0,0,0,5,0,0,0,0,0,"Hotel #1",299,tt_content,,1 +,14,92,1,0,0,0,3,0,0,0,0,0,"Hotel #1",300,tt_content,,2 +,15,92,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 +,9,92,1,0,0,0,8,0,0,0,0,0,"Offer #1.1",13,tx_irretutorial_1nff_hotel,,1 +,10,92,1,0,0,0,5,0,0,0,0,0,"Offer #1.1",14,tx_irretutorial_1nff_hotel,,3 +,11,92,2,0,0,0,6,0,0,0,0,0,"Offer #1.2",14,tx_irretutorial_1nff_hotel,,2 +,12,92,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, @@ -50,10 +48,10 @@ tx_irretutorial_1nff_price ,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, +,14,92,1,0,0,0,13,0,0,0,0,0,"Price #1.1.1",9,tx_irretutorial_1nff_offer, +,15,92,1,0,0,0,7,0,0,0,0,0,"Price #1.1.1",10,tx_irretutorial_1nff_offer, +,16,92,2,0,0,0,8,0,0,0,0,0,"Price #1.1.2",10,tx_irretutorial_1nff_offer, +,17,92,3,0,0,0,9,0,0,0,0,0,"Price #1.1.3",10,tx_irretutorial_1nff_offer, +,18,92,1,0,0,0,10,0,0,0,0,0,"Price #1.2.1",11,tx_irretutorial_1nff_offer, +,19,92,2,0,0,0,11,0,0,0,0,0,"Price #1.2.2",11,tx_irretutorial_1nff_offer, +,20,92,1,0,0,0,12,0,0,0,0,0,"Price #2.1.1",12,tx_irretutorial_1nff_offer, diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWExclude.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWExclude.csv index 30244615be74..015a731455f4 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWExclude.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWExclude.csv @@ -1,12 +1,10 @@ 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 -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, +,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,2, +,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""}" 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 @@ -17,10 +15,10 @@ tx_irretutorial_1nff_hotel ,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,1000000000,1,0,0,2,0,0,0,0,0,"Hotel #0",1,pages_language_overlay,,0 -,7,89,1,0,0,0,2,0,0,0,0,0,"Hotel #0",1,pages_language_overlay,,0 +,6,89,1000000000,1,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,0 +,7,89,1,0,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,0 ,8,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",89,pages,,0 -,9,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",1,pages_language_overlay,,0 +,9,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",91,pages,,0 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 diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWSynchronization.csv index 065db2892ad4..db421d57a6d2 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWSynchronization.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWSynchronization.csv @@ -1,12 +1,10 @@ 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 -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""}" +,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,2, +,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""}" 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 @@ -17,9 +15,9 @@ tx_irretutorial_1nff_hotel ,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,1,2,2,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",1,pages_language_overlay,,0 +,6,89,1,0,1,2,2,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",91,pages,,0 ,7,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",89,pages,,0 -,8,89,2,0,1,7,0,0,0,0,0,0,"[Translate to Dansk:] Hotel #007",1,pages_language_overlay,,0 +,8,89,2,0,1,7,0,0,0,0,0,0,"[Translate to Dansk:] Hotel #007",91,pages,,0 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 diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddMonoglotHotelChildWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddMonoglotHotelChildWSynchronization.csv index 7c07fb3126ec..8bc243932a14 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddMonoglotHotelChildWSynchronization.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddMonoglotHotelChildWSynchronization.csv @@ -1,12 +1,10 @@ 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 -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""}" +,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,2, +,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""}" 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 @@ -17,9 +15,9 @@ tx_irretutorial_1nff_hotel ,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 +,6,89,1,0,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,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 +,8,89,2,0,0,0,0,0,0,0,0,0,"Hotel #007",91,pages,,0 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 diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWExclude.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWExclude.csv index 0fee9b8cdfcb..4415b18be91e 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWExclude.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWExclude.csv @@ -1,12 +1,10 @@ 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,1 -,90,88,512,0,0,0,0,0,0,0,Target,0 -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",1, +,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 +,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",1 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 @@ -17,7 +15,7 @@ tx_irretutorial_1nff_hotel ,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,0,0,2,0,0,0,0,0,"Hotel #0",1,pages_language_overlay,,0 +,6,89,1,0,0,0,2,0,0,0,0,0,"Hotel #0",91,pages,,0 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 diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWSynchronization.csv index 3ab8e50f4cc8..e4af05dfa80f 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWSynchronization.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWSynchronization.csv @@ -1,12 +1,10 @@ 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,1 -,90,88,512,0,0,0,0,0,0,0,Target,0 -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",1,"{""tx_irretutorial_hotels"":""parent""}" +,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",1,"{""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""}" 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 @@ -17,7 +15,7 @@ tx_irretutorial_1nff_hotel ,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",1,pages_language_overlay,,0 +,6,89,1,0,1,2,2,0,0,0,0,0,"[Translate to Dansk:] Hotel #0",91,pages,,0 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 diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/AbstractActionTestCase.php b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/AbstractActionTestCase.php index cdabe46de66e..613086af702f 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/AbstractActionTestCase.php +++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/AbstractActionTestCase.php @@ -32,7 +32,6 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D const VALUE_LanguageIdSecond = 2; const TABLE_Page = 'pages'; - const TABLE_PageOverlay = 'pages_language_overlay'; const TABLE_Content = 'tt_content'; /** @@ -305,17 +304,22 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D */ public function localizePage() { + // 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; $localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_LanguageId); $this->recordIds['localizedPageId'] = $localizedTableIds[self::TABLE_Page][self::VALUE_PageId]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; } public function localizePageWithLanguageSynchronization() { - $GLOBALS['TCA']['pages_language_overlay']['columns']['title']['config']['behaviour']['allowLanguageSynchronization'] = true; + unset($GLOBALS['TCA'][self::TABLE_Page]['columns']['title']['l10n_mode']); + $GLOBALS['TCA'][self::TABLE_Page]['columns']['title']['config']['behaviour']['allowLanguageSynchronization'] = true; + // 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; $localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Page, self::VALUE_PageId, self::VALUE_LanguageId); $this->recordIds['localizedPageId'] = $localizedTableIds[self::TABLE_Page][self::VALUE_PageId]; - $this->recordIds['localizedPageOverlayId'] = $localizedTableIds[self::TABLE_PageOverlay][self::VALUE_PageId]; $this->actionService->modifyRecord(self::TABLE_Page, self::VALUE_PageId, ['title' => 'Testing #1']); } diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/DataSet/LiveDefaultPages.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/DataSet/LiveDefaultPages.csv index 335d96c76764..2e47970e493b 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/DataSet/LiveDefaultPages.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/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" -,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" +,"uid","pid","sorting","deleted","sys_language_uid","l10n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title" +,1,0,256,0,0,0,0,0,0,0,0,0,"FunctionalTest" +,88,1,256,0,0,0,0,0,0,0,0,0,"DataHandlerTest" +,89,88,256,0,0,0,0,0,0,0,0,0,"Relations" +,90,88,512,0,0,0,0,0,0,0,0,0,"Target" 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 index 8a03b53e27df..0d823f1bac03 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPage.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPage.csv @@ -1,14 +1,12 @@ 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" +,uid,pid,sorting,deleted,sys_language_uid,l10n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title +,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest +,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest +,89,88,256,0,0,0,0,0,0,0,0,0,Relations +,90,88,512,0,0,0,0,0,0,0,0,0,Target +,91,88,256,0,1,89,0,0,0,0,0,0,"[Translate to Dansk:] Relations" +,92,90,256,0,0,0,89,0,0,0,0,0,Relations +,93,90,256,0,1,92,91,0,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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" @@ -18,9 +16,9 @@ tt_content ,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" +,303,92,256,0,0,0,0,299,0,0,0,0,0,"Regular Element #3" +,304,92,128,0,1,303,303,300,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3" +,305,92,64,0,0,0,0,298,0,0,0,0,0,"Regular Element #2" +,306,92,32,0,0,0,0,297,0,0,0,0,0,"Regular Element #1" +,307,92,16,0,1,306,306,301,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1" +,308,92,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 index fb115f6bde7b..c259294fe49a 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPageWSynchronization.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPageWSynchronization.csv @@ -1,14 +1,12 @@ 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""}" +,uid,pid,sorting,sys_language_uid,l10n_parent,deleted,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,l10n_state +,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest, +,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest, +,89,88,256,0,0,0,0,0,0,0,0,0,"Testing #1", +,90,88,512,0,0,0,0,0,0,0,0,0,Target, +,91,88,256,1,89,0,0,0,0,0,0,0,"Testing #1","{""title"":""parent"",""url"":""parent"",""lastUpdated"":""parent"",""newUntil"":""parent"",""no_search"":""parent"",""shortcut"":""parent"",""shortcut_mode"":""parent"",""author"":""parent"",""author_email"":""parent"",""media"":""parent""}" +,92,90,256,0,0,0,89,0,0,0,0,0,"Testing #1", +,93,90,256,1,92,0,91,0,0,0,0,0,"Testing #1","{""title"":""parent"",""url"":""parent"",""lastUpdated"":""parent"",""newUntil"":""parent"",""no_search"":""parent"",""shortcut"":""parent"",""shortcut_mode"":""parent"",""author"":""parent"",""author_email"":""parent"",""media"":""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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" @@ -18,9 +16,9 @@ tt_content ,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" +,303,92,256,0,0,0,0,299,0,0,0,0,0,"Regular Element #3" +,304,92,128,0,1,303,303,300,0,0,0,0,0,"[Translate to Dansk:] Regular Element #3" +,305,92,64,0,0,0,0,298,0,0,0,0,0,"Regular Element #2" +,306,92,32,0,0,0,0,297,0,0,0,0,0,"Regular Element #1" +,307,92,16,0,1,306,306,301,0,0,0,0,0,"[Translate to Dansk:] Regular Element #1" +,308,92,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/localizePage.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv index f78fb3a65eb9..a4e9444fc118 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv @@ -1,12 +1,10 @@ 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 -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" +,uid,pid,sorting,sys_language_uid,l10n_parent,deleted,hidden,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title +,1,0,256,0,0,0,0,0,0,0,0,0,0,FunctionalTest +,88,1,256,0,0,0,0,0,0,0,0,0,0,DataHandlerTest +,89,88,256,0,0,0,0,0,0,0,0,0,0,Relations +,90,88,512,0,0,0,0,0,0,0,0,0,0,Target +,91,88,256,1,89,0,0,0,0,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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePageWSynchronization.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePageWSynchronization.csv index aca0204998d8..80d56cb42317 100644 --- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePageWSynchronization.csv +++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePageWSynchronization.csv @@ -1,12 +1,10 @@ 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 -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,"Testing #1" +,uid,pid,sorting,deleted,l10n_parent,sys_language_uid,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title +,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest +,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest +,89,88,256,0,0,0,0,0,0,0,0,0,"Testing #1" +,90,88,512,0,0,0,0,0,0,0,0,0,Target +,91,88,256,0,89,1,0,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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/TCA/Overrides/pages_language_overlay.php b/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/TCA/Overrides/pages_language_overlay.php deleted file mode 100644 index 96284dbc3236..000000000000 --- a/typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/TCA/Overrides/pages_language_overlay.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns( - 'pages_language_overlay', - [ - 'tx_irretutorial_hotels' => [ - 'exclude' => true, - 'label' => 'LLL:EXT:irre_tutorial/Resources/Private/Language/locallang_db.xml:pages.tx_irretutorial_hotels', - 'config' => [ - 'type' => 'inline', - 'foreign_table' => 'tx_irretutorial_1nff_hotel', - 'foreign_field' => 'parentid', - 'foreign_table_field' => 'parenttable', - 'maxitems' => 10, - 'appearance' => [ - 'showSynchronizationLink' => 1, - 'showAllLocalizationLink' => 1, - 'showPossibleLocalizationRecords' => 1, - 'showRemovedLocalizationRecords' => 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' -); 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 index b2fb61d06f73..763c88e36725 100644 --- 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 @@ -9,15 +9,6 @@ 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' # diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/pages_language_overlay.xml b/typo3/sysext/core/Tests/Functional/Fixtures/pages_language_overlay.xml deleted file mode 100644 index a85fc9a1f5af..000000000000 --- a/typo3/sysext/core/Tests/Functional/Fixtures/pages_language_overlay.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<dataset> - <pages_language_overlay> - <uid>1</uid> - <pid>1</pid> - <title>Root [Dansk]</title> - <deleted>0</deleted> - <hidden>0</hidden> - <sys_language_uid>1</sys_language_uid> - </pages_language_overlay> - <pages_language_overlay> - <uid>2</uid> - <pid>1</pid> - <title>Root [Deutsch]</title> - <deleted>0</deleted> - <hidden>0</hidden> - <sys_language_uid>2</sys_language_uid> - </pages_language_overlay> -</dataset> \ No newline at end of file diff --git a/typo3/sysext/core/Tests/Unit/Database/Schema/Fixtures/tablebuilder.sql b/typo3/sysext/core/Tests/Unit/Database/Schema/Fixtures/tablebuilder.sql index d542c72b8bba..558465bc939b 100644 --- a/typo3/sysext/core/Tests/Unit/Database/Schema/Fixtures/tablebuilder.sql +++ b/typo3/sysext/core/Tests/Unit/Database/Schema/Fixtures/tablebuilder.sql @@ -17,5 +17,5 @@ CREATE TABLE aTestTable ( UNIQUE `parent` (pid,`deleted`,sorting), KEY noCache (`no_cache`), KEY substring (TSconfig(80)), - FOREIGN KEY fk_overlay (uid) REFERENCES pages_language_overlay(pid) + FOREIGN KEY fk_overlay (uid) REFERENCES any_foreign_table(pid) ) ENGINE = MyISAM DEFAULT CHARACTER SET latin1 COLLATE latin1_german_cs ROW_FORMAT DYNAMIC AUTO_INCREMENT=1; diff --git a/typo3/sysext/core/Tests/Unit/Database/Schema/Parser/TableBuilderTest.php b/typo3/sysext/core/Tests/Unit/Database/Schema/Parser/TableBuilderTest.php index 825feb319530..f2e2996c956e 100644 --- a/typo3/sysext/core/Tests/Unit/Database/Schema/Parser/TableBuilderTest.php +++ b/typo3/sysext/core/Tests/Unit/Database/Schema/Parser/TableBuilderTest.php @@ -242,7 +242,7 @@ class TableBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase $this->assertSame(['`pid`'], $subject->getForeignColumns()); $this->assertSame(['`uid`'], $subject->getLocalColumns()); $this->assertSame('aTestTable', $subject->getLocalTableName()); - $this->assertSame('pages_language_overlay', $subject->getForeignTableName()); + $this->assertSame('any_foreign_table', $subject->getForeignTableName()); } /** diff --git a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php index 0b989724529a..4879e426171c 100644 --- a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php +++ b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php @@ -2160,7 +2160,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'config' => [ 'type' => 'input', ], - 'l10n_mode' => 'any-possible-value', ], ], ], @@ -2170,21 +2169,13 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'config' => [ 'type' => 'input', ], + 'l10n_mode' => 'any-possible-value', ], ], ], ], [ 'pages' => [ - 'columns' => [ - 'aColumn' => [ - 'config' => [ - 'type' => 'input', - ], - ], - ], - ], - 'pages_language_overlay' => [ 'columns' => [ 'aColumn' => [ 'config' => [ @@ -2203,9 +2194,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'aColumn' => [ 'config' => [ 'type' => 'input', - 'behaviour' => [ - 'allowLanguageSynchronization' => true, - ] ], ], ], @@ -2215,6 +2203,9 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'aColumn' => [ 'config' => [ 'type' => 'input', + 'behaviour' => [ + 'allowLanguageSynchronization' => true, + ] ], ], ], @@ -2222,16 +2213,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase ], [ 'pages' => [ - 'columns' => [ - 'aColumn' => [ - 'config' => [ - 'type' => 'input', - 'behaviour' => [] - ], - ], - ], - ], - 'pages_language_overlay' => [ 'columns' => [ 'aColumn' => [ 'config' => [ @@ -2269,15 +2250,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'aColumn' => [], ], ], - 'pages_language_overlay' => [ - 'columns' => [ - 'aColumn' => [ - 'config' => [ - 'type' => 'input', - ], - ], - ], - ], ] ], 'superfluous allowLanguageSynchronization' => [ @@ -2302,16 +2274,12 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase ], [ 'pages' => [ - 'columns' => [ - 'aColumn' => [], - ], - ], - 'pages_language_overlay' => [ 'columns' => [ 'aColumn' => [ 'config' => [ - 'type' => 'input', - 'behaviour' => [] + 'behaviour' => [ + 'allowLanguageSynchronization' => true, + ] ], ], ], diff --git a/typo3/sysext/core/ext_tables.php b/typo3/sysext/core/ext_tables.php index aecd9b88265f..ece80f7b72a3 100644 --- a/typo3/sysext/core/ext_tables.php +++ b/typo3/sysext/core/ext_tables.php @@ -95,7 +95,6 @@ $GLOBALS['TBE_STYLES'] = []; * documentation found in "Inside TYPO3" */ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('pages', 'EXT:core/Resources/Private/Language/locallang_csh_pages.xlf'); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('pages_language_overlay', 'EXT:core/Resources/Private/Language/locallang_csh_pageslol.xlf'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('be_users', 'EXT:core/Resources/Private/Language/locallang_csh_be_users.xlf'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('be_groups', 'EXT:core/Resources/Private/Language/locallang_csh_be_groups.xlf'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('sys_filemounts', 'EXT:core/Resources/Private/Language/locallang_csh_sysfilem.xlf'); diff --git a/typo3/sysext/core/ext_tables.sql b/typo3/sysext/core/ext_tables.sql index 45373b0c2107..8b3e06402717 100644 --- a/typo3/sysext/core/ext_tables.sql +++ b/typo3/sysext/core/ext_tables.sql @@ -116,6 +116,10 @@ CREATE TABLE pages ( editlock tinyint(4) unsigned DEFAULT '0' NOT NULL, crdate int(11) unsigned DEFAULT '0' NOT NULL, cruser_id int(11) unsigned DEFAULT '0' NOT NULL, + sys_language_uid int(11) unsigned DEFAULT '0' NOT NULL, + l10n_parent int(11) DEFAULT '0' NOT NULL, + l10n_source int(11) DEFAULT '0' NOT NULL, + l10n_diffsource mediumblob, hidden tinyint(4) unsigned DEFAULT '0' NOT NULL, title varchar(255) DEFAULT '' NOT NULL, doktype int(11) unsigned DEFAULT '0' NOT NULL, @@ -156,6 +160,7 @@ CREATE TABLE pages ( backend_layout varchar(64) DEFAULT '' NOT NULL, backend_layout_next_level varchar(64) DEFAULT '' NOT NULL, tsconfig_includes text, + legacy_overlay_uid int(11) unsigned DEFAULT '0' NOT NULL, PRIMARY KEY (uid), KEY t3ver_oid (t3ver_oid,t3ver_wsid), KEY parent (pid,deleted,sorting), diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php index d43a3bd3bcc8..857a9271d9f9 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php @@ -591,7 +591,6 @@ class Typo3DbBackend implements BackendInterface, SingletonInterface if (isset($tableName) && isset($GLOBALS['TCA'][$tableName]) && isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField']) && isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']) - && $tableName !== 'pages_language_overlay' ) { if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']]) && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0 @@ -623,7 +622,6 @@ class Typo3DbBackend implements BackendInterface, SingletonInterface $row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid()); } elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField']) && $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== '' - && $tableName !== 'pages_language_overlay' ) { if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], [-1, 0])) { $overlayMode = $querySettings->getLanguageMode() === 'strict' ? 'hideNonTranslated' : ''; diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php index 43d568956aa0..6c7e341e0028 100644 --- a/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php +++ b/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php @@ -210,7 +210,7 @@ class TranslatedContentTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandlin } /** - * Dutch language has pages_language_overlay record and some content elements are translated + * Dutch language has pages record and some content elements are translated * * @return array */ diff --git a/typo3/sysext/filelist/Classes/FileList.php b/typo3/sysext/filelist/Classes/FileList.php index 35ec4b8f9183..0ccac54c493f 100644 --- a/typo3/sysext/filelist/Classes/FileList.php +++ b/typo3/sysext/filelist/Classes/FileList.php @@ -752,17 +752,17 @@ class FileList { // Look up page overlays: $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $result = $queryBuilder ->select('*') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->andX( - $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), $queryBuilder->expr()->gt( 'sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) diff --git a/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php b/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php index 000f9190eab6..0f78ecbb5b2f 100644 --- a/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php +++ b/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php @@ -1286,7 +1286,7 @@ abstract class AbstractMenuContentObject if ($languageUid && ($this->conf['protectLvar'] === 'all' || GeneralUtility::hideIfNotTranslated($data['l18n_cfg']))) { $olRec = $tsfe->sys_page->getPageOverlay($data['uid'], $languageUid); if (empty($olRec)) { - // If no pages_language_overlay record then page can NOT be accessed in + // If no page translation record then page can NOT be accessed in // the language pointed to by "&L" and therefore we protect the link by setting "&L=0" $data['_ADD_GETVARS'] .= '&L=0'; } diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php index f580b40d7876..a24ab68586e2 100644 --- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php +++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php @@ -263,7 +263,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface /** * Flag indicating that hidden records should be shown. This includes - * sys_template, pages_language_overlay and even fe_groups in addition to all + * sys_template and even fe_groups in addition to all * other regular content. So in effect, this includes everything except pages. * @var bool */ diff --git a/typo3/sysext/frontend/Classes/Page/PageRepository.php b/typo3/sysext/frontend/Classes/Page/PageRepository.php index 78ebcc84f196..abaa43274305 100644 --- a/typo3/sysext/frontend/Classes/Page/PageRepository.php +++ b/typo3/sysext/frontend/Classes/Page/PageRepository.php @@ -460,19 +460,19 @@ class PageRepository implements LoggerAwareInterface } // NOTE regarding the query restrictions // Currently the showHiddenRecords of TSFE set will allow - // pages_language_overlay records to be selected as they are + // page translation records to be selected as they are // child-records of a page. // However you may argue that the showHiddenField flag should // determine this. But that's not how it's done right now. // Selecting overlay record: $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class)); $result = $queryBuilder->select('*') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->in( - 'pid', + 'l10n_parent', $queryBuilder->createNamedParameter($page_ids, Connection::PARAM_INT_ARRAY) ), $queryBuilder->expr()->eq( @@ -484,12 +484,12 @@ class PageRepository implements LoggerAwareInterface $overlays = []; while ($row = $result->fetch()) { - $this->versionOL('pages_language_overlay', $row); + $this->versionOL('pages', $row); if (is_array($row)) { $row['_PAGES_OVERLAY'] = true; $row['_PAGES_OVERLAY_UID'] = $row['uid']; $row['_PAGES_OVERLAY_LANGUAGE'] = $lUid; - $origUid = $row['pid']; + $origUid = $row['l10n_parent']; // Unset vital fields that are NOT allowed to be overlaid: unset($row['uid']); unset($row['pid']); @@ -545,7 +545,7 @@ class PageRepository implements LoggerAwareInterface if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) { // Return record for ALL languages untouched // TODO: Fix call stack to prevent this situation in the first place - if ($table !== 'pages_language_overlay' && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] !== -1) { + if ((int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] !== -1) { // Will not be able to work with other tables (Just didn't implement it yet; // Requires a scan over all tables [ctrl] part for first FIND the table that // carries localization information for this table (which could even be more @@ -703,6 +703,10 @@ class PageRepository implements LoggerAwareInterface $relationField, $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY) ), + $queryBuilder->expr()->eq( + 'sys_language_uid', + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ), QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del), QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess), QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause) @@ -1301,7 +1305,7 @@ class PageRepository implements LoggerAwareInterface if ($show_hidden === -1 && is_object($this->getTypoScriptFrontendController())) { // If show_hidden was not set from outside and if TSFE is an object, set it // based on showHiddenPage and showHiddenRecords from TSFE - $show_hidden = $table === 'pages' || $table === 'pages_language_overlay' + $show_hidden = $table === 'pages' ? $this->getTypoScriptFrontendController()->showHiddenPage : $this->getTypoScriptFrontendController()->showHiddenRecords; } @@ -1849,18 +1853,9 @@ class PageRepository implements LoggerAwareInterface $localizedId = $element['_PAGES_OVERLAY_UID']; } - if ($tableName === 'pages') { - $tableName = 'pages_language_overlay'; - } - $isTableLocalizable = ( !empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField']) && !empty($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']) - // Only fetch references if the field is defined in TCA. This is a special use-case - // for pages_language_overlay because it may be possible that a field is defined in TCA - // of "pages" but not in "pages_language_overlay". Once pages_language_overlay is removed - // this check can be removed as well - && isset($GLOBALS['TCA'][$tableName]['columns'][$fieldName]) ); if ($isTableLocalizable && $localizedId !== null) { $localizedReferences = $fileRepository->findByRelation($tableName, $fieldName, $localizedId); diff --git a/typo3/sysext/frontend/Classes/View/AdminPanelView.php b/typo3/sysext/frontend/Classes/View/AdminPanelView.php index d5e768390eea..eafc752a260c 100644 --- a/typo3/sysext/frontend/Classes/View/AdminPanelView.php +++ b/typo3/sysext/frontend/Classes/View/AdminPanelView.php @@ -963,14 +963,14 @@ class AdminPanelView // Edit Page Overlay if ($perms & Permission::PAGE_EDIT && $tsfe->sys_language_uid && $langAllowed) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class)); $row = $queryBuilder ->select('uid', 'pid', 't3ver_state') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->eq( - 'pid', + 'l10n_parent', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( @@ -981,12 +981,12 @@ class AdminPanelView ->setMaxResults(1) ->execute() ->fetch(); - $tsfe->sys_page->versionOL('pages_language_overlay', $row); + $tsfe->sys_page->versionOL('pages', $row); if (is_array($row)) { $link = BackendUtility::getModuleUrl( 'record_edit', [ - 'edit[pages_language_overlay][' . $row['uid'] . ']' => 'edit', + 'edit[pages][' . $row['uid'] . ']' => 'edit', 'noView' => 1, 'returnUrl' => $returnUrl ] diff --git a/typo3/sysext/frontend/Configuration/TCA/pages_language_overlay.php b/typo3/sysext/frontend/Configuration/TCA/pages_language_overlay.php index e8fbe58adc77..a5a8870c61d4 100644 --- a/typo3/sysext/frontend/Configuration/TCA/pages_language_overlay.php +++ b/typo3/sysext/frontend/Configuration/TCA/pages_language_overlay.php @@ -24,6 +24,10 @@ return [ 'typeicon_classes' => [ 'default' => 'mimetypes-x-content-page-language-overlay' ], + // disabled until all migration has been done + 'hideTable' => true, + // This option needs to be set to the record is not shown in the be_groups ACLs + 'adminOnly' => true, 'searchFields' => 'title,subtitle,nav_title,keywords,description,abstract,author,author_email,url' ], 'interface' => [ @@ -68,7 +72,6 @@ return [ ] ], 'title' => [ - 'l10n_mode' => 'prefixLangTitle', 'label' => $GLOBALS['TCA']['pages']['columns']['title']['label'], 'config' => [ 'type' => 'input', diff --git a/typo3/sysext/frontend/Tests/Functional/Fixtures/pages.xml b/typo3/sysext/frontend/Tests/Functional/Fixtures/pages.xml index ff8cb0c32f37..abb60ee80448 100644 --- a/typo3/sysext/frontend/Tests/Functional/Fixtures/pages.xml +++ b/typo3/sysext/frontend/Tests/Functional/Fixtures/pages.xml @@ -95,47 +95,53 @@ <perms_everybody>15</perms_everybody> </pages> - <pages_language_overlay> + <pages> <uid>901</uid> - <pid>1</pid> + <pid>0</pid> + <l10n_parent>1</l10n_parent> <sys_language_uid>1</sys_language_uid> <title>Wurzel 1</title> <deleted>0</deleted> - </pages_language_overlay> - <pages_language_overlay> + </pages> + <pages> <uid>902</uid> - <pid>2</pid> + <pid>1</pid> + <l10n_parent>2</l10n_parent> <sys_language_uid>1</sys_language_uid> <title>Attrappe 1-2</title> <deleted>0</deleted> - </pages_language_overlay> - <pages_language_overlay> + </pages> + <pages> <uid>903</uid> - <pid>3</pid> + <pid>1</pid> + <l10n_parent>3</l10n_parent> <sys_language_uid>1</sys_language_uid> <title>Attrappe 1-3</title> <deleted>0</deleted> - </pages_language_overlay> - <pages_language_overlay> + </pages> + <pages> <uid>904</uid> - <pid>5</pid> + <pid>2</pid> + <l10n_parent>5</l10n_parent> <sys_language_uid>1</sys_language_uid> <title>Attrappe 1-2-5</title> <deleted>0</deleted> - </pages_language_overlay> - <pages_language_overlay> + </pages> + <pages> <uid>905</uid> - <pid>6</pid> + <pid>2</pid> + <l10n_parent>6</l10n_parent> <sys_language_uid>1</sys_language_uid> <title>Attrappe 1-2-6</title> <deleted>0</deleted> - </pages_language_overlay> - <pages_language_overlay> + </pages> + <pages> <uid>906</uid> - <pid>9</pid> + <pid>3</pid> + <l10n_parent>9</l10n_parent> <sys_language_uid>1</sys_language_uid> <title>Attrappe 1-3-9</title> <deleted>0</deleted> - </pages_language_overlay> + </pages> </dataset> diff --git a/typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/LiveDefaultPages.csv b/typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/LiveDefaultPages.csv index 68c32a7fe68e..b7383af8cd6a 100644 --- a/typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/LiveDefaultPages.csv +++ b/typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/LiveDefaultPages.csv @@ -1,9 +1,7 @@ -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,Root page -,88,1,256,0,0,0,0,0,0,0,Subpage -,89,88,256,0,0,0,0,0,0,0,Default language Page -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,[DK]Page,"{""title"":""parent""}", -,2,89,0,3,0,0,0,0,[PL]Page,"{""title"":""parent""}", +pages,,,,,,,,,,,,,, +,uid,pid,sorting,deleted,sys_language_uid,l10n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,l10n_state +,1,0,256,0,0,0,0,0,0,0,0,0,Root page,"{}" +,88,1,256,0,0,0,0,0,0,0,0,0,Subpage,"{}" +,89,88,256,0,0,0,0,0,0,0,0,0,Default language Page,"{}" +,90,88,256,0,1,89,0,0,0,0,0,0,[DK]Page,"{""title"":""parent""}" +,91,88,256,0,3,89,0,0,0,0,0,0,[PL]Page,"{""title"":""parent""}" diff --git a/typo3/sysext/frontend/Tests/Functional/Rendering/LocalizedContentRenderingTest.php b/typo3/sysext/frontend/Tests/Functional/Rendering/LocalizedContentRenderingTest.php index fa171f645824..c58ba1662146 100644 --- a/typo3/sysext/frontend/Tests/Functional/Rendering/LocalizedContentRenderingTest.php +++ b/typo3/sysext/frontend/Tests/Functional/Rendering/LocalizedContentRenderingTest.php @@ -36,7 +36,7 @@ use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Response; * to that value) or "ignore" (just render the page and the content as this translation would exist). * When set to "0" or not set "", this means that the page request is using the default language for content * and page properties. - * Content fallback is evaluated on page level, not on the CE level. So it only makes a difference when the pages_language_overlay + * Content fallback is evaluated on page level, not on the CE level. So it only makes a difference when the page translation * for the requested language does not exist. * * config.sys_language_overlay = [0, 1, hideNonTranslated] @@ -272,7 +272,7 @@ class LocalizedContentRenderingTest extends \TYPO3\CMS\Core\Tests\Functional\Dat } /** - * Dutch language has pages_language_overlay record and some content elements are translated + * Dutch language has page translation record and some content elements are translated * * @return array */ diff --git a/typo3/sysext/frontend/Tests/Functional/Tca/PagesLanguageOverlayVisibleFieldsTest.php b/typo3/sysext/frontend/Tests/Functional/Tca/PagesLanguageOverlayVisibleFieldsTest.php index d5a84fe9cad9..7c570fad82ff 100644 --- a/typo3/sysext/frontend/Tests/Functional/Tca/PagesLanguageOverlayVisibleFieldsTest.php +++ b/typo3/sysext/frontend/Tests/Functional/Tca/PagesLanguageOverlayVisibleFieldsTest.php @@ -166,7 +166,7 @@ class PagesLanguageOverlayVisibleFieldsTest extends \TYPO3\TestingFramework\Core $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageService::class); $formEngineTestService = GeneralUtility::makeInstance(FormTestService::class); - $formResult = $formEngineTestService->createNewRecordForm('pages_language_overlay', ['doktype' => $doktype]); + $formResult = $formEngineTestService->createNewRecordForm('pages', ['doktype' => $doktype]); foreach ($expectedFields as $expectedField) { $this->assertNotFalse( diff --git a/typo3/sysext/frontend/ext_tables.php b/typo3/sysext/frontend/ext_tables.php index e8a4cdca6cc0..63a983fc1713 100644 --- a/typo3/sysext/frontend/ext_tables.php +++ b/typo3/sysext/frontend/ext_tables.php @@ -2,7 +2,7 @@ defined('TYPO3_MODE') or die(); // Add allowed records to pages -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('pages_language_overlay,tt_content,sys_template,sys_domain,backend_layout'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tt_content,sys_template,sys_domain,backend_layout'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('_MOD_web_layout', 'EXT:frontend/Resources/Private/Language/locallang_csh_weblayout.xlf'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('fe_groups', 'EXT:frontend/Resources/Private/Language/locallang_csh_fe_groups.xlf'); diff --git a/typo3/sysext/info/Classes/Controller/TranslationStatusController.php b/typo3/sysext/info/Classes/Controller/TranslationStatusController.php index 7ab573527b43..84fef815a37a 100644 --- a/typo3/sysext/info/Classes/Controller/TranslationStatusController.php +++ b/typo3/sysext/info/Classes/Controller/TranslationStatusController.php @@ -34,12 +34,6 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc */ protected $iconFactory; - /** - * @var string - * static table for pages_language_overlay - */ - protected static $pageLanguageOverlayTable = 'pages_language_overlay'; - /** * Construct for initialize class variables */ @@ -206,7 +200,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc if (is_array($row)) { $langRecUids[$langRow['uid']][] = $row['uid']; $status = $row['_HIDDEN'] ? (GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : '') : 'success'; - $icon = $this->iconFactory->getIconForRecord('pages_language_overlay', $row, Icon::SIZE_SMALL)->render(); + $icon = $this->iconFactory->getIconForRecord('pages', $row, Icon::SIZE_SMALL)->render(); $info = $icon . htmlspecialchars( GeneralUtility::fixed_lgd_cs($row['title'], $titleLen) ) . ((string)$row['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars( @@ -224,7 +218,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc // Create links: $editUrl = BackendUtility::getModuleUrl('record_edit', [ 'edit' => [ - 'pages_language_overlay' => [ + 'pages' => [ $row['uid'] => 'edit' ] ], @@ -253,7 +247,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc +(document.webinfoForm[' . GeneralUtility::quoteJSvalue('newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']') . '].checked ? ' - . GeneralUtility::quoteJSvalue('&edit[pages_language_overlay][' . $data['row']['uid'] . ']=new') + . GeneralUtility::quoteJSvalue('&edit[pages][' . $data['row']['uid'] . ']=new') . ' : \'\') '; } @@ -300,7 +294,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc if (is_array($langRecUids[$langRow['uid']])) { $editUrl = BackendUtility::getModuleUrl('record_edit', [ 'edit' => [ - 'pages_language_overlay' => [ + 'pages' => [ implode(',', $langRecUids[$langRow['uid']]) => 'edit' ] ], @@ -315,7 +309,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc $editButton = ''; } // Create new overlay records: - $params = '&columnsOnly=title,hidden,sys_language_uid&overrideVals[pages_language_overlay][sys_language_uid]=' . $langRow['uid']; + $params = '&columnsOnly=title,hidden,sys_language_uid&overrideVals[pages][sys_language_uid]=' . $langRow['uid']; $onClick = BackendUtility::editOnClick($params); if (!empty($newOL_js[$langRow['uid']])) { $onClickArray = explode('?', $onClick, 2); @@ -387,12 +381,12 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc * * @param int $pageId Page ID to look up for. * @param int $langId Language UID to select for. - * @return array pages_languages_overlay record + * @return array translated pages record */ public function getLangStatus($pageId, $langId) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable(static::$pageLanguageOverlayTable); + ->getQueryBuilderForTable('pages'); $queryBuilder ->getRestrictions() ->removeAll() @@ -400,10 +394,10 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc ->add(GeneralUtility::makeInstance(DeletedRestriction::class)); $result = $queryBuilder ->select('*') - ->from(static::$pageLanguageOverlayTable) + ->from('pages') ->where( $queryBuilder->expr()->eq( - 'pid', + 'l10n_parent', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT) ) ) @@ -416,7 +410,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc ->execute(); $row = $result->fetch(); - BackendUtility::workspaceOL(static::$pageLanguageOverlayTable, $row); + BackendUtility::workspaceOL('pages', $row); if (is_array($row)) { $row['_COUNT'] = $result->rowCount(); $row['_HIDDEN'] = $row['hidden'] || (int)$row['endtime'] > 0 && (int)$row['endtime'] < $GLOBALS['EXEC_TIME'] || $GLOBALS['EXEC_TIME'] < (int)$row['starttime']; @@ -435,7 +429,7 @@ class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunc public function getContentElementCount($pageId, $sysLang) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable(static::$pageLanguageOverlayTable); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) diff --git a/typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayBeGroupsAccessRights.php b/typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayBeGroupsAccessRights.php new file mode 100644 index 000000000000..ba2587e8df1c --- /dev/null +++ b/typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayBeGroupsAccessRights.php @@ -0,0 +1,124 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Install\Updates; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +/** + * Merge access rights from be_groups concerning pages_language_overlay + * into pages + */ +class MigratePagesLanguageOverlayBeGroupsAccessRights extends AbstractUpdate +{ + /** + * The human-readable title of the upgrade wizard + * + * @var string + */ + protected $title = 'Merge be_groups access rights from pages_language_overlay to pages'; + + /** + * Checks whether updates are required. + * + * @param string &$description The description for the update + * @return bool Whether an update is required (TRUE) or not (FALSE) + */ + public function checkForUpdate(&$description) + { + $description = 'The table pages_language_overlay will be removed to align the translation ' . + 'handling for pages with the rest of the core. This wizard transfers all be_groups with ' . + 'access restrictions to pages_language_overlay into pages.'; + + $updateNeeded = false; + + if (!$this->isWizardDone()) { + $updateNeeded = true; + } + + return $updateNeeded; + } + + /** + * Performs the accordant updates. + * + * @param array &$dbQueries Queries done in this update + * @param string &$customMessage Custom message + * @return bool Whether everything went smoothly or not + * @throws \InvalidArgumentException + */ + public function performUpdate(array &$dbQueries, &$customMessage) + { + $beGroupsQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_groups'); + $beGroupsQueryBuilder->getRestrictions()->removeAll(); + $beGroupsRows = $beGroupsQueryBuilder + ->select('uid', 'non_exclude_fields', 'tables_modify') + ->from('be_groups') + ->execute(); + while ($beGroupsRow = $beGroupsRows->fetch()) { + $updateNeeded = false; + if (!empty($beGroupsRow['tables_modify'])) { + // If 'pages_language_overlay' is allowed as table-modify, remove it and add + // 'pages' if it is not in there, yet. + $tablesArray = GeneralUtility::trimExplode(',', $beGroupsRow['tables_modify'], true); + $newTablesArray = $tablesArray; + if (in_array('pages_language_overlay', $tablesArray, true)) { + $updateNeeded = true; + $newTablesArray = array_diff($tablesArray, ['pages_language_overlay']); + if (!in_array('pages', $newTablesArray, true)) { + $newTablesArray[] = 'pages'; + } + } + } else { + $newTablesArray = []; + } + if (!empty($beGroupsRow['non_exclude_fields'])) { + // Exclude fields on 'pages_language_overlay' are removed and added as + // exclude fields on 'pages' + $excludeFields = GeneralUtility::trimExplode(',', $beGroupsRow['non_exclude_fields'], true); + $newExcludeFields = []; + foreach ($excludeFields as $tableFieldCombo) { + if (strpos($tableFieldCombo, 'pages_language_overlay:') === 0) { + $updateNeeded = true; + $field = substr($tableFieldCombo, strlen('pages_language_overlay:')); + $newExcludeFields[] = 'pages:' . $field; + } else { + $newExcludeFields[] = $tableFieldCombo; + } + } + array_unique($newExcludeFields); + } else { + $newExcludeFields = []; + } + if ($updateNeeded) { + $updateBeGroupsQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_groups'); + $updateBeGroupsQueryBuilder + ->update('be_groups') + ->set('tables_modify', implode(',', $newTablesArray)) + ->set('non_exclude_fields', implode(',', $newExcludeFields)) + ->where( + $updateBeGroupsQueryBuilder->expr()->eq( + 'uid', + $updateBeGroupsQueryBuilder->createNamedParameter($beGroupsRow['uid'], \PDO::PARAM_INT) + ) + ) + ->execute(); + } + } + $this->markWizardAsDone(); + return true; + } +} diff --git a/typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayUpdate.php b/typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayUpdate.php new file mode 100644 index 000000000000..d208c557d1ca --- /dev/null +++ b/typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayUpdate.php @@ -0,0 +1,296 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Install\Updates; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Install\Service\LoadTcaService; + +/** + * Class MigratePagesLanguageOverlayUpdate + */ +class MigratePagesLanguageOverlayUpdate extends AbstractUpdate +{ + /** + * The human-readable title of the upgrade wizard + * + * @var string + */ + protected $title = 'Migrate content from pages_language_overlay to pages'; + + /** + * Checks whether updates are required. + * + * @param string &$description The description for the update + * @return bool Whether an update is required (TRUE) or not (FALSE) + */ + public function checkForUpdate(&$description) + { + $description = 'The table pages_language_overlay will be removed to align the translation ' . + 'handling for pages with the rest of the core. This wizard transfers all data to the pages ' . + 'table by creating new entries and linking them to the l10n parent. This might take a while, ' . + 'because max. (amount of pages) x (active languages) new entries need be created.'; + + $updateNeeded = false; + + if (!$this->isWizardDone()) { + $updateNeeded = true; + } + + return $updateNeeded; + } + + /** + * Shows information on the next step of the page + * + * @param string $formFieldNamePrefix + * @return string + */ + public function getUserInput($formFieldNamePrefix) + { + $message = ''; + // Warn for TCA relation configurations which are not migrated. + if (isset($GLOBALS['TCA']['pages_language_overlay']['columns']) && is_array($GLOBALS['TCA']['pages_language_overlay']['columns'])) { + foreach ($GLOBALS['TCA']['pages_language_overlay']['columns'] as $fieldName => $fieldConfiguration) { + if (isset($fieldConfiguration['config']['MM'])) { + $message .= '<p>The pages_language_overlay field ' . $fieldName + . ' with its MM relation configuration can not be migrated' + . ' automatically. Existing data relations to this field have' + . ' to be migrated manually.</p>'; + } + } + } + return $message; + } + + /** + * Performs the accordant updates. + * + * @param array &$dbQueries Queries done in this update + * @param string &$customMessage Custom message + * @return bool Whether everything went smoothly or not + * @throws \InvalidArgumentException + */ + public function performUpdate(array &$dbQueries, &$customMessage) + { + // Ensure pages_language_overlay is still available in TCA + GeneralUtility::makeInstance(LoadTcaService::class)->loadExtensionTablesWithoutMigration(); + $this->mergePagesLanguageOverlayIntoPages(); + $this->updateInlineRelations(); + $this->updateSysHistoryRelations(); + $this->markWizardAsDone(); + return true; + } + + /** + * 1. Fetches ALL pages_language_overlay (= translations) records + * 2. Fetches the given page record (= original language) for each translation + * 3. Populates the values from the original language IF the field in the translation record is NOT SET (empty is fine) + * 4. Adds proper fields for the translations which is + * - l10n_parent = UID of the original-language-record + * - pid = PID of the original-language-record (please note: THIS IS DIFFERENT THAN IN pages_language_overlay) + * - l10n_source = UID of the original-language-record (only this is supported currently) + */ + protected function mergePagesLanguageOverlayIntoPages() + { + $overlayQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages_language_overlay'); + $overlayQueryBuilder->getRestrictions()->removeAll(); + $overlayRecords = $overlayQueryBuilder + ->select('*') + ->from('pages_language_overlay') + ->execute(); + $pagesConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages'); + $pagesColumns = $pagesConnection->getSchemaManager()->listTableDetails('pages')->getColumns(); + $pagesColumnTypes = []; + foreach ($pagesColumns as $pageColumn) { + $pagesColumnTypes[$pageColumn->getName()] = $pageColumn->getType()->getBindingType(); + } + while ($overlayRecord = $overlayRecords->fetch()) { + // Early continue if record has been migrated before + if ($this->isOverlayRecordMigratedAlready((int)$overlayRecord['uid'])) { + continue; + } + + $values = []; + $originalPageId = (int)$overlayRecord['pid']; + $page = $this->fetchDefaultLanguagePageRecord($originalPageId); + if (!empty($page)) { + foreach ($pagesColumns as $pageColumn) { + $name = $pageColumn->getName(); + if (isset($overlayRecord[$name])) { + $values[$name] = $overlayRecord[$name]; + } elseif (isset($page[$name])) { + $values[$name] = $page[$name]; + } + } + + $values['pid'] = $page['pid']; + $values['l10n_parent'] = $originalPageId; + $values['l10n_source'] = $originalPageId; + $values['legacy_overlay_uid'] = $overlayRecord['uid']; + unset($values['uid']); + $pagesConnection->insert( + 'pages', + $values, + $pagesColumnTypes + ); + } + } + } + + /** + * Inline relations with foreign_field, foreign_table, foreign_table_field on + * pages_language_overlay TCA get their existing relations updated to new + * uid and pages table. + */ + protected function updateInlineRelations() + { + if (isset($GLOBALS['TCA']['pages_language_overlay']['columns']) && is_array($GLOBALS['TCA']['pages_language_overlay']['columns'])) { + foreach ($GLOBALS['TCA']['pages_language_overlay']['columns'] as $fieldName => $fieldConfiguration) { + // Migrate any 1:n relations + if ($fieldConfiguration['config']['type'] === 'inline' + && !empty($fieldConfiguration['config']['foreign_field']) + && !empty($fieldConfiguration['config']['foreign_table']) + && !empty($fieldConfiguration['config']['foreign_table_field']) + ) { + $foreignTable = trim($fieldConfiguration['config']['foreign_table']); + $foreignField = trim($fieldConfiguration['config']['foreign_field']); + $foreignTableField = trim($fieldConfiguration['config']['foreign_table_field']); + $translatedPagesQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $translatedPagesQueryBuilder->getRestrictions()->removeAll(); + $translatedPagesRows = $translatedPagesQueryBuilder + ->select('uid', 'legacy_overlay_uid') + ->from('pages') + ->where( + $translatedPagesQueryBuilder->expr()->gt( + 'l10n_parent', + $translatedPagesQueryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ) + ->execute(); + while ($translatedPageRow = $translatedPagesRows->fetch()) { + $foreignTableQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($foreignTable); + $foreignTableQueryBuilder->getRestrictions()->removeAll(); + $foreignTableQueryBuilder + ->update($foreignTable) + ->set($foreignField, $translatedPageRow['uid']) + ->set($foreignTableField, 'pages') + ->where( + $foreignTableQueryBuilder->expr()->eq( + $foreignField, + $foreignTableQueryBuilder->createNamedParameter($translatedPageRow['legacy_overlay_uid'], \PDO::PARAM_INT) + ), + $foreignTableQueryBuilder->expr()->eq( + $foreignTableField, + $foreignTableQueryBuilder->createNamedParameter('pages_language_overlay', \PDO::PARAM_STR) + ) + ) + ->execute(); + } + } + } + } + } + + /** + * Update recuid and tablename of sys_history table to pages and new uid + * for all pages_language_overlay rows + */ + protected function updateSysHistoryRelations() + { + $translatedPagesQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $translatedPagesQueryBuilder->getRestrictions()->removeAll(); + $translatedPagesRows = $translatedPagesQueryBuilder + ->select('uid', 'legacy_overlay_uid') + ->from('pages') + ->where( + $translatedPagesQueryBuilder->expr()->gt( + 'l10n_parent', + $translatedPagesQueryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ) + ->execute(); + while ($translatedPageRow = $translatedPagesRows->fetch()) { + $historyTableQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_history'); + $historyTableQueryBuilder->getRestrictions()->removeAll(); + $historyTableQueryBuilder + ->update('sys_history') + ->set('tablename', 'pages') + ->set('recuid', $translatedPageRow['uid']) + ->where( + $historyTableQueryBuilder->expr()->eq( + 'recuid', + $historyTableQueryBuilder->createNamedParameter($translatedPageRow['legacy_overlay_uid'], \PDO::PARAM_INT) + ), + $historyTableQueryBuilder->expr()->eq( + 'tablename', + $historyTableQueryBuilder->createNamedParameter('pages_language_overlay', \PDO::PARAM_STR) + ) + ) + ->execute(); + } + } + + /** + * Fetches a certain page + * + * @param int $pageId + * @return array + * @throws \InvalidArgumentException + */ + protected function fetchDefaultLanguagePageRecord(int $pageId): array + { + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $queryBuilder->getRestrictions()->removeAll(); + $page = $queryBuilder + ->select('*') + ->from('pages') + ->where( + $queryBuilder->expr()->eq( + 'uid', + $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetch(); + return $page ?: []; + } + + /** + * Verify if a single overlay record has been migrated to pages already + * by checking the db field legacy_overlay_uid for the orig uid + * + * @param int $overlayUid + * @return bool + */ + protected function isOverlayRecordMigratedAlready(int $overlayUid): bool + { + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $queryBuilder->getRestrictions()->removeAll(); + $migratedRecord = $queryBuilder + ->select('uid') + ->from('pages') + ->where( + $queryBuilder->expr()->eq( + 'legacy_overlay_uid', + $queryBuilder->createNamedParameter($overlayUid, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetch(); + return !empty($migratedRecord); + } +} diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php index e720b6cb43a8..1780c888f3a8 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php @@ -1381,4 +1381,25 @@ return [ 'Deprecation-82926-DomainRelatedApiMethodInTSFE.rst', ], ], + 'TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider->getTranslationTable' => [ + 'numberOfMandatoryArguments' => 1, + 'maximumNumberOfArguments' => 1, + 'restFiles' => [ + 'Deprecation-82445-PageTranslationRelatedFunctionality.rst', + ], + ], + 'TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider->isTranslationInOwnTable' => [ + 'numberOfMandatoryArguments' => 1, + 'maximumNumberOfArguments' => 1, + 'restFiles' => [ + 'Deprecation-82445-PageTranslationRelatedFunctionality.rst', + ], + ], + 'TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider->foreignTranslationTable' => [ + 'numberOfMandatoryArguments' => 1, + 'maximumNumberOfArguments' => 1, + 'restFiles' => [ + 'Deprecation-82445-PageTranslationRelatedFunctionality.rst', + ], + ], ]; diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php index ac5210ae926f..3edd1528ac48 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php @@ -498,4 +498,11 @@ return [ 'Deprecation-82902-CustomBackendModuleRegistrationMethods.rst', ], ], + 'TYPO3\CMS\Backend\Utility\BackendUtility::getOriginalTranslationTable' => [ + 'numberOfMandatoryArguments' => 1, + 'maximumNumberOfArguments' => 1, + 'restFiles' => [ + 'Deprecation-82445-PageTranslationRelatedFunctionality.rst', + ], + ], ]; diff --git a/typo3/sysext/install/ext_localconf.php b/typo3/sysext/install/ext_localconf.php index c0843db3145e..765af3045832 100644 --- a/typo3/sysext/install/ext_localconf.php +++ b/typo3/sysext/install/ext_localconf.php @@ -50,6 +50,10 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['rdctExtensio = \TYPO3\CMS\Install\Updates\RedirectExtractionUpdate::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['cshmanualBackendUsers'] = \TYPO3\CMS\Install\Updates\BackendUserStartModuleUpdate::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['pagesLanguageOverlay'] + = \TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['pagesLanguageOverlayBeGroupsAccessRights'] + = \TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayBeGroupsAccessRights::class; $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); $icons = [ diff --git a/typo3/sysext/recordlist/Classes/RecordList.php b/typo3/sysext/recordlist/Classes/RecordList.php index f9f4b1f72abe..85b77ff316cd 100644 --- a/typo3/sysext/recordlist/Classes/RecordList.php +++ b/typo3/sysext/recordlist/Classes/RecordList.php @@ -22,6 +22,8 @@ use TYPO3\CMS\Backend\Template\DocumentTemplate; use TYPO3\CMS\Backend\Template\ModuleTemplate; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; @@ -32,6 +34,7 @@ use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\TypoScript\TypoScriptService; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Versioning\VersionState; /** * Script Class for the Web > List module; rendering the listing of records on a page @@ -465,10 +468,16 @@ class RecordList $this->body = $this->moduleTemplate->header($title); $this->moduleTemplate->setTitle($title); + $output = ''; + // Show the selector for new translations of the current page + // but only when in "default" mode + if ($this->id && !$dblist->csvOutput && !$this->search_field && !$this->cmd && !$this->table) { + $output .= $this->languageSelector($this->id); + } + if (!empty($dblist->HTMLcode)) { - $output = $dblist->HTMLcode; + $output .= $dblist->HTMLcode; } else { - $output = ''; $flashMessage = GeneralUtility::makeInstance( FlashMessage::class, $lang->getLL('noRecordsOnThisPage'), @@ -596,6 +605,146 @@ class RecordList return $response; } + /** + * Make selector box for creating new translation in a language + * Displays only languages which are not yet present for the current page and + * that are not disabled with page TS. + * + * @param int $id Page id for which to create a new translation record of pages + * @return string <select> HTML element (if there were items for the box anyways...) + */ + protected function languageSelector(int $id): string + { + if ($this->getBackendUserAuthentication()->check('tables_modify', 'pages')) { + // First, select all + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language'); + $queryBuilder->getRestrictions()->removeAll(); + $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(HiddenRestriction::class)); + $statement = $queryBuilder->select('uid', 'title') + ->from('sys_language') + ->orderBy('sorting') + ->execute(); + $availableTranslations = []; + while ($row = $statement->fetch()) { + if ($this->getBackendUserAuthentication()->checkLanguageAccess($row['uid'])) { + $availableTranslations[(int)$row['uid']] = $row['title']; + } + } + // Then, subtract the languages which are already on the page: + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language'); + $queryBuilder->getRestrictions()->removeAll(); + $queryBuilder->select('sys_language.uid AS uid', 'sys_language.title AS title') + ->from('sys_language') + ->join( + 'sys_language', + 'pages', + 'pages', + $queryBuilder->expr()->eq('sys_language.uid', $queryBuilder->quoteIdentifier('pages.sys_language_uid')) + ) + ->where( + $queryBuilder->expr()->eq( + 'pages.deleted', + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ), + $queryBuilder->expr()->eq( + 'pages.l10n_parent', + $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT) + ), + $queryBuilder->expr()->orX( + $queryBuilder->expr()->gte( + 'pages.t3ver_state', + $queryBuilder->createNamedParameter( + (string)new VersionState(VersionState::DEFAULT_STATE), + \PDO::PARAM_INT + ) + ), + $queryBuilder->expr()->eq( + 'pages.t3ver_wsid', + $queryBuilder->createNamedParameter($this->getBackendUserAuthentication()->workspace, \PDO::PARAM_INT) + ) + ) + ) + ->groupBy( + 'pages.sys_language_uid', + 'sys_language.uid', + 'sys_language.pid', + 'sys_language.tstamp', + 'sys_language.hidden', + 'sys_language.title', + 'sys_language.language_isocode', + 'sys_language.static_lang_isocode', + 'sys_language.flag', + 'sys_language.sorting' + ) + ->orderBy('sys_language.sorting'); + if (!$this->getBackendUserAuthentication()->isAdmin()) { + $queryBuilder->andWhere( + $queryBuilder->expr()->eq( + 'sys_language.hidden', + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ); + } + $statement = $queryBuilder->execute(); + while ($row = $statement->fetch()) { + unset($availableTranslations[(int)$row['uid']]); + } + // Remove disallowed languages + if (!empty($availableTranslations) + && !$this->getBackendUserAuthentication()->isAdmin() + && $this->getBackendUserAuthentication()->groupData['allowed_languages'] !== '' + ) { + $allowed_languages = array_flip(explode(',', $this->getBackendUserAuthentication()->groupData['allowed_languages'])); + if (!empty($allowed_languages)) { + foreach ($availableTranslations as $key => $value) { + if (!isset($allowed_languages[$key]) && $key != 0) { + unset($availableTranslations[$key]); + } + } + } + } + // Remove disabled languages + $modSharedTSconfig = BackendUtility::getModTSconfig($id, 'mod.SHARED'); + $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages']) + ? GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], true) + : []; + if (!empty($availableTranslations) && !empty($disableLanguages)) { + foreach ($disableLanguages as $language) { + if ($language != 0 && isset($availableTranslations[$language])) { + unset($availableTranslations[$language]); + } + } + } + // If any languages are left, make selector: + if (!empty($availableTranslations)) { + $output = '<option value="">' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:new_language')) . '</option>'; + foreach ($availableTranslations as $languageUid => $languageTitle) { + // Build localize command URL to DataHandler (tce_db) + // which redirects to FormEngine (record_edit) + // which, when finished editing should return back to the current page (returnUrl) + $parameters = [ + 'justLocalized' => 'pages:' . $id . ':' . $languageUid, + 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') + ]; + $redirectUrl = BackendUtility::getModuleUrl('record_edit', $parameters); + $targetUrl = BackendUtility::getLinkToDataHandlerAction( + '&cmd[pages][' . $id . '][localize]=' . $languageUid, + $redirectUrl + ); + + $output .= '<option value="' . htmlspecialchars($targetUrl) . '">' . htmlspecialchars($languageTitle) . '</option>'; + } + + return '<div class="form-inline form-inline-spaced">' + . '<div class="form-group">' + . '<select class="form-control input-sm" name="createNewLanguage" onchange="window.location.href=this.options[this.selectedIndex].value">' + . $output + . '</select></div></div>'; + } + } + return ''; + } + /** * @return ModuleTemplate */ diff --git a/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php b/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php index e3c79fec27d0..7d249d093625 100644 --- a/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php +++ b/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php @@ -804,9 +804,7 @@ class AbstractDatabaseRecordList extends AbstractRecordList } // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set - if ( - $table !== 'pages_language_overlay' - && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) + if (!empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && (GeneralUtility::inList($this->hideTranslations, $table) || $this->hideTranslations === '*') ) { $queryBuilder->andWhere($queryBuilder->expr()->eq( diff --git a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php index 9465d4c29017..f77fa8c2db2d 100644 --- a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php +++ b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php @@ -917,8 +917,7 @@ class DatabaseRecordList $titleCol = $GLOBALS['TCA'][$table]['ctrl']['label']; $thumbsCol = $GLOBALS['TCA'][$table]['ctrl']['thumbnail']; $l10nEnabled = $GLOBALS['TCA'][$table]['ctrl']['languageField'] - && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] - && $table !== 'pages_language_overlay'; + && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; $tableCollapsed = (bool)$this->tablesCollapsed[$table]; // prepare space icon $this->spaceIcon = '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>'; @@ -1435,7 +1434,6 @@ class DatabaseRecordList $theData['uid'] = $row['uid']; if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) && isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) - && $table !== 'pages_language_overlay' ) { $theData['_l10nparent_'] = $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]; } @@ -1619,8 +1617,8 @@ class DatabaseRecordList . $spriteIcon->render() . '</a>'; } else { $params = '&edit[' . $table . '][' . $this->id . ']=new'; - if ($table === 'pages_language_overlay') { - $params .= '&overrideVals[pages_language_overlay][doktype]=' . (int)$this->pageRow['doktype']; + if ($table === 'pages') { + $params .= '&overrideVals[pages][doktype]=' . (int)$this->pageRow['doktype']; } $icon = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1)) . '" title="' . htmlspecialchars($lang->getLL('new')) . '">' . $spriteIcon->render() . '</a>'; @@ -1850,6 +1848,9 @@ class DatabaseRecordList 'primary' => [], 'secondary' => [] ]; + // Enables to hide the move elements for localized records - doesn't make much sense to perform these options for them + // For page translations these icons should never be shown + $isL10nOverlay = ($this->localizationView || $table === 'pages') && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; // If the listed table is 'pages' we have to request the permission settings for each page: $localCalcPerms = 0; if ($table === 'pages') { @@ -1902,10 +1903,14 @@ class DatabaseRecordList $this->addActionToCellGroup($cells, $viewBigAction, 'viewBig'); // "Move" wizard link for pages/tt_content elements: if ($permsEdit && ($table === 'tt_content' || $table === 'pages')) { - $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $row['uid']) . ');'; - $linkTitleLL = htmlspecialchars($this->getLanguageService()->getLL('move_' . ($table === 'tt_content' ? 'record' : 'page'))); - $icon = ($table === 'pages' ? $this->iconFactory->getIcon('actions-page-move', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)); - $moveAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $linkTitleLL . '">' . $icon->render() . '</a>'; + if ($isL10nOverlay) { + $moveAction = $this->spaceIcon; + } else { + $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $row['uid']) . ');'; + $linkTitleLL = htmlspecialchars($this->getLanguageService()->getLL('move_' . ($table === 'tt_content' ? 'record' : 'page'))); + $icon = ($table === 'pages' ? $this->iconFactory->getIcon('actions-page-move', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)); + $moveAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $linkTitleLL . '">' . $icon->render() . '</a>'; + } $this->addActionToCellGroup($cells, $moveAction, 'move'); } // If the table is NOT a read-only table, then show these links: @@ -1919,17 +1924,23 @@ class DatabaseRecordList $this->addActionToCellGroup($cells, $historyAction, 'history'); // "Edit Perms" link: if ($table === 'pages' && $this->getBackendUserAuthentication()->check('modules', 'system_BeuserTxPermission') && ExtensionManagementUtility::isLoaded('beuser')) { - $href = BackendUtility::getModuleUrl('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&tx_beuser_system_beusertxpermission[action]=edit' . $this->makeReturnUrl(); - $permsAction = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="' - . htmlspecialchars($this->getLanguageService()->getLL('permissions')) . '">' - . $this->iconFactory->getIcon('actions-lock', Icon::SIZE_SMALL)->render() . '</a>'; + if ($isL10nOverlay) { + $permsAction = $this->spaceIcon; + } else { + $href = BackendUtility::getModuleUrl('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&tx_beuser_system_beusertxpermission[action]=edit' . $this->makeReturnUrl(); + $permsAction = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="' + . htmlspecialchars($this->getLanguageService()->getLL('permissions')) . '">' + . $this->iconFactory->getIcon('actions-lock', Icon::SIZE_SMALL)->render() . '</a>'; + } $this->addActionToCellGroup($cells, $permsAction, 'perms'); } // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row // or if default values can depend on previous record): if (($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) && $permsEdit) { if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT || $table === 'pages' && $this->calcPerms & Permission::PAGE_NEW) { - if ($this->showNewRecLink($table)) { + if ($table === 'pages' && $isL10nOverlay) { + $this->addActionToCellGroup($cells, $this->spaceIcon, 'new'); + } elseif ($this->showNewRecLink($table)) { $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new'; $icon = ($table === 'pages' ? $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)); $titleLabel = 'new'; @@ -1945,7 +1956,7 @@ class DatabaseRecordList } // "Up/Down" links if ($permsEdit && $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) { - if (isset($this->currentTable['prev'][$row['uid']])) { + if (!$isL10nOverlay && isset($this->currentTable['prev'][$row['uid']])) { // Up $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']]; $moveUpAction = '<a class="btn btn-default" href="#" onclick="' @@ -1957,7 +1968,7 @@ class DatabaseRecordList } $this->addActionToCellGroup($cells, $moveUpAction, 'moveUp'); - if ($this->currentTable['next'][$row['uid']]) { + if (!$isL10nOverlay && $this->currentTable['next'][$row['uid']]) { // Down $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']]; $moveDownAction = '<a class="btn btn-default" href="#" onclick="' @@ -2050,10 +2061,10 @@ class DatabaseRecordList . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');') . '" title="' . htmlspecialchars($this->getLanguageService()->getLL('prevLevel')) . '">' . $this->iconFactory->getIcon('actions-move-left', Icon::SIZE_SMALL)->render() . '</a>'; - $this->addActionToCellGroup($cells, $moveLeftAction, 'moveLeft'); + $this->addActionToCellGroup($cells, $isL10nOverlay ? $this->spaceIcon : $moveLeftAction, 'moveLeft'); } // Down (Paste as subpage to the page right above) - if ($this->currentTable['prevUid'][$row['uid']]) { + if (!$isL10nOverlay && $this->currentTable['prevUid'][$row['uid']]) { $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $this->currentTable['prevUid'][$row['uid']])); if ($localCalcPerms & Permission::PAGE_NEW) { $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']]; @@ -2148,8 +2159,9 @@ class DatabaseRecordList } $cells = []; $cells['pasteAfter'] = ($cells['pasteInto'] = $this->spaceIcon); - //enables to hide the copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them - $isL10nOverlay = $this->localizationView && $table !== 'pages_language_overlay' && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; + // Enables to hide the copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them + // For page translations these icons should never be shown + $isL10nOverlay = ($this->localizationView || $table === 'pages') && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; // Return blank, if disabled: // Whether a numeric clipboard pad is active or the normal pad we will see different content of the panel: // For the "Normal" pad: @@ -2194,7 +2206,7 @@ class DatabaseRecordList $cells['cut'] = $this->spaceIcon; } } else { - if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT) { + if ($this->calcPerms & Permission::CONTENT_EDIT) { $cells['cut'] = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars('return jumpSelf(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB($table, $row['uid'], 0, ($isSel === 'cut'), ['returnUrl' => ''])) . ');') . '" title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.cut')) . '">' @@ -2241,7 +2253,7 @@ class DatabaseRecordList } // Now, looking for elements in general: $elFromTable = $this->clipObj->elFromTable(''); - if ($table === 'pages' && !empty($elFromTable)) { + if ($table === 'pages' && !$isL10nOverlay && !empty($elFromTable)) { $cells['pasteInto'] = '<a class="btn btn-default t3js-modal-trigger"' . ' href="' . htmlspecialchars($this->clipObj->pasteUrl('', $row['uid'])) . '"' . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_pasteInto')) . '"' @@ -2266,9 +2278,7 @@ class DatabaseRecordList $cells = $hookObject->makeClip($table, $row, $cells, $this); } } - // Compile items into a DIV-element: - return '<!-- CLIPBOARD PANEL: ' . $table . ':' . $row['uid'] . ' --> - <div class="btn-group" role="group">' . implode('', $cells) . '</div>'; + return '<div class="btn-group" role="group">' . implode('', $cells) . '</div>'; } /** @@ -3181,9 +3191,7 @@ class DatabaseRecordList } // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set - if ( - $table !== 'pages_language_overlay' - && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) + if (!empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && (GeneralUtility::inList($this->hideTranslations, $table) || $this->hideTranslations === '*') ) { $queryBuilder->andWhere( @@ -4088,17 +4096,17 @@ class DatabaseRecordList { // Look up page overlays: $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $result = $queryBuilder ->select('*') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->andX( - $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)), $queryBuilder->expr()->gt( 'sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) diff --git a/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php b/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php index de87dd2f468c..f3fcd4710cc3 100644 --- a/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php +++ b/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php @@ -329,13 +329,13 @@ class ViewModuleController extends ActionController ->from('sys_language') ->join( 'sys_language', - 'pages_language_overlay', + 'pages', 'o', $queryBuilder->expr()->eq('o.sys_language_uid', $queryBuilder->quoteIdentifier('sys_language.uid')) ) ->where( $queryBuilder->expr()->eq( - 'o.pid', + 'o.l10n_parent', $queryBuilder->createNamedParameter($pageIdToShow, \PDO::PARAM_INT) ) ) diff --git a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php index 2819d812f437..4e751a8eccc4 100644 --- a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php +++ b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php @@ -838,7 +838,7 @@ class DataHandlerHook } // l10n-fields must be kept otherwise the localization // will be lost during the publishing - if ($table !== 'pages_language_overlay' && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) { + if ($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) { $keepFields[] = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; } // Swap "keepfields" diff --git a/typo3/sysext/workspaces/Classes/Service/StagesService.php b/typo3/sysext/workspaces/Classes/Service/StagesService.php index 4d41cf87c8d1..6d7855d300f8 100644 --- a/typo3/sysext/workspaces/Classes/Service/StagesService.php +++ b/typo3/sysext/workspaces/Classes/Service/StagesService.php @@ -90,7 +90,7 @@ class StagesService implements \TYPO3\CMS\Core\SingletonInterface */ public function getPreviousStageForElementCollection( $workspaceItems, - array $byTableName = ['tt_content', 'pages', 'pages_language_overlay'] + array $byTableName = ['tt_content', 'pages'] ) { $currentStage = []; $previousStage = []; @@ -138,7 +138,7 @@ class StagesService implements \TYPO3\CMS\Core\SingletonInterface */ public function getNextStageForElementCollection( $workspaceItems, - array $byTableName = ['tt_content', 'pages', 'pages_language_overlay'] + array $byTableName = ['tt_content', 'pages'] ) { $currentStage = []; $usedStages = []; diff --git a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php index 414e0acbbc9c..4824a5fcbb85 100644 --- a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php +++ b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php @@ -693,19 +693,19 @@ class WorkspaceService implements SingletonInterface // If the language is not default, check state of overlay if ($language > 0) { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)); $row = $queryBuilder->select('t3ver_state') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->eq( - 'pid', + 'l10n_parent', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( - $GLOBALS['TCA']['pages_language_overlay']['ctrl']['languageField'], + $GLOBALS['TCA']['pages']['ctrl']['languageField'], $queryBuilder->createNamedParameter($language, \PDO::PARAM_INT) ), $queryBuilder->expr()->eq( @@ -769,7 +769,7 @@ class WorkspaceService implements SingletonInterface $viewUrl = ''; // Directly use determined direct page id - if ($table === 'pages_language_overlay' || $table === 'tt_content') { + if ($table === 'tt_content') { $viewUrl = BackendUtility::viewOnClick($previewPageId, '', null, '', '', $additionalParameters); } elseif (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table]) || !empty($pageTsConfig['options.']['workspaces.']['previewPageId'])) { // Analyze Page TSconfig options.workspaces.previewPageId @@ -1137,17 +1137,17 @@ class WorkspaceService implements SingletonInterface } $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) - ->getQueryBuilderForTable('pages_language_overlay'); + ->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $result = $queryBuilder->select('sys_language_uid') - ->from('pages_language_overlay') + ->from('pages') ->where( $queryBuilder->expr()->eq( - 'pid', + 'l10n_parent', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT) ) ) diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv index 611e170ec6ed..0bff9873fe37 100644 --- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv +++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv @@ -1,13 +1,11 @@ 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 -pages_language_overlay -,uid,pid,deleted,sys_language_uid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,title -,1,89,0,1,1,1,0,0,"[Translate to Dansk:] Relations" -,2,-1,0,1,1,-1,0,1,"[Translate to Dansk:] Relations" +,uid,pid,sorting,deleted,sys_language_uid,l10n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title +,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest +,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest +,89,88,256,0,0,0,0,0,0,0,0,0,Relations +,90,88,512,0,0,0,0,0,0,0,0,0,Target +,91,88,256,0,1,89,0,1,1,0,0,0,"[Translate to Dansk:] Relations" +,92,-1,256,0,1,89,0,1,-1,0,91,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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/ActionTest.php index b90b41eda147..103c7216de4b 100644 --- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/ActionTest.php +++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/ActionTest.php @@ -379,7 +379,7 @@ class ActionTest extends \TYPO3\CMS\Workspaces\Tests\Functional\DataHandling\Reg public function localizePage() { parent::localizePage(); - $this->actionService->publishRecord(self::TABLE_PageOverlay, $this->recordIds['localizedPageOverlayId']); + $this->actionService->publishRecord(self::TABLE_Page, $this->recordIds['localizedPageId']); $this->assertAssertionDataSet('localizePage'); $responseSections = $this->getFrontendResponse(self::VALUE_PageId, self::VALUE_LanguageId)->getResponseSections(); diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/DataSet/localizePage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/DataSet/localizePage.csv index 8c923a881837..31fe6bfc4cac 100644 --- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/DataSet/localizePage.csv +++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/DataSet/localizePage.csv @@ -1,12 +1,10 @@ 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 -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" +,uid,pid,sorting,deleted,sys_language_uid,l10n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title +,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest +,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest +,89,88,256,0,0,0,0,0,0,0,0,0,Relations +,90,88,512,0,0,0,0,0,0,0,0,0,Target +,91,88,256,0,1,89,0,0,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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/PublishAll/DataSet/localizePage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/PublishAll/DataSet/localizePage.csv index 8c923a881837..31fe6bfc4cac 100644 --- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/PublishAll/DataSet/localizePage.csv +++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/PublishAll/DataSet/localizePage.csv @@ -1,12 +1,10 @@ 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 -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" +,uid,pid,sorting,deleted,sys_language_uid,l10n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title +,1,0,256,0,0,0,0,0,0,0,0,0,FunctionalTest +,88,1,256,0,0,0,0,0,0,0,0,0,DataHandlerTest +,89,88,256,0,0,0,0,0,0,0,0,0,Relations +,90,88,512,0,0,0,0,0,0,0,0,0,Target +,91,88,256,0,1,89,0,0,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 ,296,88,256,0,0,0,0,0,0,0,0,0,0,"Regular Element #0" diff --git a/typo3/sysext/workspaces/Tests/Functional/Service/WorkspaceServiceTest.php b/typo3/sysext/workspaces/Tests/Functional/Service/WorkspaceServiceTest.php index c8ecf179ec0d..93d5b6b50dad 100644 --- a/typo3/sysext/workspaces/Tests/Functional/Service/WorkspaceServiceTest.php +++ b/typo3/sysext/workspaces/Tests/Functional/Service/WorkspaceServiceTest.php @@ -239,7 +239,6 @@ class WorkspaceServiceTest extends FunctionalTestCase 'sys_file_metadata' => [], 'sys_file_reference' => [], 'backend_layout' => [], - 'pages_language_overlay' => [], 'sys_template' => [], 'tt_content' => [ 1 => true, -- GitLab