[!!!][TASK] Migrate pages_language_overlay into pages 72/51272/88
authorBenni Mack <benni@typo3.org>
Thu, 2 Nov 2017 11:29:51 +0000 (12:29 +0100)
committerBenni Mack <benni@typo3.org>
Wed, 8 Nov 2017 10:55:20 +0000 (11:55 +0100)
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>
86 files changed:
typo3/sysext/backend/Classes/Clipboard/Clipboard.php
typo3/sysext/backend/Classes/Configuration/TranslationConfigurationProvider.php
typo3/sysext/backend/Classes/Controller/EditDocumentController.php
typo3/sysext/backend/Classes/Controller/NewRecordController.php
typo3/sysext/backend/Classes/Controller/PageLayoutController.php
typo3/sysext/backend/Classes/Form/FormDataCompiler.php
typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseDefaultLanguagePageRow.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php
typo3/sysext/backend/Classes/Form/FormDataProvider/DatabasePageLanguageOverlayRows.php
typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseUserPermissionCheck.php
typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php
typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php
typo3/sysext/backend/Classes/Tree/Pagetree/DataProvider.php
typo3/sysext/backend/Classes/Tree/View/PageTreeView.php
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/backend/Classes/View/PageLayoutView.php
typo3/sysext/backend/Resources/Public/JavaScript/PageActions.js
typo3/sysext/backend/Tests/Functional/Controller/FormInlineAjaxControllerTest.php
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseDefaultLanguagePageRowTest.php [new file with mode: 0644]
typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php
typo3/sysext/core/Classes/DataHandling/DataHandler.php
typo3/sysext/core/Classes/DataHandling/Localization/DataMapItem.php
typo3/sysext/core/Classes/DataHandling/Localization/DataMapProcessor.php
typo3/sysext/core/Classes/Migrations/TcaMigration.php
typo3/sysext/core/Classes/Utility/RootlineUtility.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Configuration/TCA/pages.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-82445-PagesAndPageTranslations.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Deprecation-82445-PageTranslationRelatedFunctionality.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Important-82445-MigratePagesLanguageOverlayIntoPages.rst [new file with mode: 0644]
typo3/sysext/core/Resources/Private/Language/locallang_csh_pageslol.xlf [deleted file]
typo3/sysext/core/Resources/Private/Language/locallang_csh_syslang.xlf
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/AbstractActionTestCase.php
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizeNCopyPageWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageAddMonoglotHotelChildNCopyPageWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWExclude.csv
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddHotelChildWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageNAddMonoglotHotelChildWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWExclude.csv
typo3/sysext/core/Tests/Functional/DataHandling/IRRE/ForeignField/Modify/DataSet/localizePageWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/Regular/AbstractActionTestCase.php
typo3/sysext/core/Tests/Functional/DataHandling/Regular/DataSet/LiveDefaultPages.csv
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPage.csv
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizeNCopyPageWSynchronization.csv
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv
typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePageWSynchronization.csv
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/Configuration/TCA/Overrides/pages_language_overlay.php [deleted file]
typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial/ext_tables.sql
typo3/sysext/core/Tests/Functional/Fixtures/pages_language_overlay.xml [deleted file]
typo3/sysext/core/Tests/Unit/Database/Schema/Fixtures/tablebuilder.sql
typo3/sysext/core/Tests/Unit/Database/Schema/Parser/TableBuilderTest.php
typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php
typo3/sysext/core/ext_tables.php
typo3/sysext/core/ext_tables.sql
typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php
typo3/sysext/filelist/Classes/FileList.php
typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
typo3/sysext/frontend/Classes/Page/PageRepository.php
typo3/sysext/frontend/Classes/View/AdminPanelView.php
typo3/sysext/frontend/Configuration/TCA/pages_language_overlay.php
typo3/sysext/frontend/Tests/Functional/Fixtures/pages.xml
typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/LiveDefaultPages.csv
typo3/sysext/frontend/Tests/Functional/Rendering/LocalizedContentRenderingTest.php
typo3/sysext/frontend/Tests/Functional/Tca/PagesLanguageOverlayVisibleFieldsTest.php
typo3/sysext/frontend/ext_tables.php
typo3/sysext/info/Classes/Controller/TranslationStatusController.php
typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayBeGroupsAccessRights.php [new file with mode: 0644]
typo3/sysext/install/Classes/Updates/MigratePagesLanguageOverlayUpdate.php [new file with mode: 0644]
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
typo3/sysext/install/ext_localconf.php
typo3/sysext/recordlist/Classes/RecordList.php
typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php
typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php
typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php
typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php
typo3/sysext/workspaces/Classes/Service/StagesService.php
typo3/sysext/workspaces/Classes/Service/WorkspaceService.php
typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Modify/DataSet/localizePage.csv
typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/ActionTest.php
typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/Publish/DataSet/localizePage.csv
typo3/sysext/workspaces/Tests/Functional/DataHandling/Regular/PublishAll/DataSet/localizePage.csv
typo3/sysext/workspaces/Tests/Functional/Service/WorkspaceServiceTest.php

index a763d57..82c51d7 100644 (file)
@@ -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()
index fdf6592..9727937 100644 (file)
@@ -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 '';
     }
 
     /**
index 07dcc08..c3ea94e 100644 (file)
@@ -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))
                 );
         }
 
index f1925e9..5e15f40 100644 (file)
@@ -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>';
index d5d0e27..7c7b656 100644 (file)
@@ -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'
                             ]
                         ],
index 7f58166..e31c413 100644 (file)
@@ -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
index 1a96445..ad41104 100644 (file)
@@ -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 (file)
index 0000000..48fd45b
--- /dev/null
@@ -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;
+    }
+}
index 34f0ea4..31633dc 100644 (file)
@@ -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
                         );
index 8035524..d2f793c 100644 (file)
@@ -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();
 
index 27d6379..467db33 100644 (file)
@@ -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 {
index cf2b511..18401cf 100644 (file)
@@ -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,
index ef2e157..5bb83cc 100644 (file)
@@ -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))
                 )
             )
index 64d90fa..5618bea 100644 (file)
@@ -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) {
index 35e4a50..1a58a58 100644 (file)
@@ -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');
     }
 
     /**
index 1c11d10..3b70932 100644 (file)
@@ -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()
index 7df137c..30bd1f7 100644 (file)
@@ -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)
index 7e4999a..e0b4028 100644 (file)
@@ -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() {
index 5eaa829..0c06968 100644 (file)
@@ -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 (file)
index 0000000..ec02c4d
--- /dev/null
@@ -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']);
+    }
+}
index c6d716a..d1810f0 100644 (file)
@@ -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'])) {
index 3d04982..53c9563 100644 (file)
@@ -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;
                 }
index 4cf0e7a..21fb7e7 100644 (file)
@@ -162,32 +162,6 @@ class DataMapItem
     }
 
     /**
-     * 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.
      *
      * @return mixed
index 4f5daa4..33784b2 100644 (file)
@@ -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;
index f54f61b..2add591 100644 (file)
@@ -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;
+    }
 }
index 5dba704..a2e1908 100644 (file)
@@ -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
                                 )
                             )
index 76001ce..99aeadf 100644 (file)
@@ -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
index 99fc3a6..900f92e 100644 (file)
@@ -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 (file)
index 0000000..7eb8830
--- /dev/null
@@ -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 (file)
index 0000000..bcfbb64
--- /dev/null
@@ -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 (file)
index 0000000..20eb592
--- /dev/null
@@ -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 (file)
index 1129ccd..0000000
+++ /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&gt;Preview&gt;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>
index bf69873..460830e 100644 (file)
                                <source>Defines which languages are alternatively available on each webpage.</source>
                        </trans-unit>
                        <trans-unit id=".details" xml:space="preserve">
-                               <source>The Web&gt;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&gt;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>
index fae8dcf..caf2609 100644 (file)
@@ -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];
     }
index f14a188..569284d 100644 (file)
@@ -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,
index 12f9156..be2da9b 100644 (file)
@@ -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,
index 3024461..015a731 100644 (file)
@@ -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
index 065db28..db421d5 100644 (file)
@@ -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
index 7c07fb3..8bc2439 100644 (file)
@@ -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
index 0fee9b8..4415b18 100644 (file)
@@ -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
index 3ab8e50..e4af05d 100644 (file)
@@ -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
index cdabe46..613086a 100644 (file)
@@ -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']);
     }
 
index 335d96c..2e47970 100644 (file)
@@ -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"
index 8a03b53..0d823f1 100644 (file)
@@ -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"
index fb115f6..c259294 100644 (file)
@@ -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"
index f78fb3a..a4e9444 100644 (file)
@@ -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"
index aca0204..80d56cb 100644 (file)
@@ -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 (file)
index 96284db..0000000
+++ /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'
-);
index b2fb61d..763c88e 100644 (file)
@@ -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 (file)
index a85fc9a..0000000
+++ /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
index d542c72..558465b 100644 (file)
@@ -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;
index 825feb3..f2e2996 100644 (file)
@@ -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());
     }
 
     /**
index 0b98972..4879e42 100644 (file)
@@ -2160,7 +2160,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                                 'config' => [
                                     'type' => 'input',
                                 ],
-                                'l10n_mode' => 'any-possible-value',
                             ],
                         ],
                     ],
@@ -2170,6 +2169,7 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                                 'config' => [
                                     'type' => 'input',
                                 ],
+                                'l10n_mode' => 'any-possible-value',
                             ],
                         ],
                     ],
@@ -2181,15 +2181,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                                 'config' => [
                                     'type' => 'input',
                                 ],
-                            ],
-                        ],
-                    ],
-                    'pages_language_overlay' => [
-                        'columns' => [
-                            'aColumn' => [
-                                'config' => [
-                                    'type' => 'input',
-                                ],
                                 'l10n_mode' => 'any-possible-value',
                             ],
                         ],
@@ -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,
+                                    ]
                                 ],
                             ],
                         ],
@@ -2226,16 +2217,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                             'aColumn' => [
                                 'config' => [
                                     'type' => 'input',
-                                    'behaviour' => []
-                                ],
-                            ],
-                        ],
-                    ],
-                    'pages_language_overlay' => [
-                        'columns' => [
-                            'aColumn' => [
-                                'config' => [
-                                    'type' => 'input',
                                     'behaviour' => [
                                         'allowLanguageSynchronization' => true,
                                     ]
@@ -2269,15 +2250,6 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                             'aColumn' => [],
                         ],
                     ],
-                    'pages_language_overlay' => [
-                        'columns' => [
-                            'aColumn' => [
-                                'config' => [
-                                    'type' => 'input',
-                                ],
-                            ],
-                        ],
-                    ],
                 ]
             ],
             'superfluous allowLanguageSynchronization' => [
@@ -2303,15 +2275,11 @@ class TcaMigrationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
                 [
                     'pages' => [
                         'columns' => [
-                            'aColumn' => [],
-                        ],
-                    ],
-                    'pages_language_overlay' => [
-                        'columns' => [
                             'aColumn' => [
                                 'config' => [
-                                    'type' => 'input',
-                                    'behaviour' => []
+                                    'behaviour' => [
+                                        'allowLanguageSynchronization' => true,
+                                    ]
                                 ],
                             ],
                         ],
index aecd9b8..ece80f7 100644 (file)
@@ -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');
index 45373b0..8b3e064 100644 (file)
@@ -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),
index d43a3bd..857a927 100644 (file)
@@ -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' : '';
index 43d5689..6c7e341 100644 (file)
@@ -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
      */
index 35ec4b8..0ccac54 100644 (file)
@@ -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)
index 000f919..0f78ecb 100644 (file)
@@ -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';
                             }
index f580b40..a24ab68 100644 (file)
@@ -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
      */
index 78ebcc8..abaa432 100644 (file)
@@ -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);
index d5e7683..eafc752 100644 (file)
@@ -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
                     ]
index e8fbe58..a5a8870 100644 (file)
@@ -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',
index ff8cb0c..abb60ee 100644 (file)
         <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>
 
index 68c32a7..b7383af 100644 (file)
@@ -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""}"
index fa171f6..c58ba16 100644 (file)
@@ -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
      */
index d5a84fe..7c570fa 100644 (file)
@@ -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(
index e8a4cdc..63a983f 100644 (file)
@@ -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');
index 7ab5735..84fef81 100644 (file)
@@ -35,12 +35,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
      */
     public function __construct()
@@ -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 (file)
index 0000000..ba2587e
--- /dev/null
@@ -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 (file)
index 0000000..d208c55
--- /dev/null
@@ -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);
+    }
+}
index e720b6c..1780c88 100644 (file)
@@ -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',
+        ],
+    ],
 ];
index ac5210a..3edd152 100644 (file)
@@ -498,4 +498,11 @@ return [
             'Deprecation-82902-CustomBackendModuleRegistrationMethods.rst',
         ],
     ],
+    'TYPO3\CMS\Backend\Utility\BackendUtility::getOriginalTranslationTable' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 1,
+        'restFiles' => [
+            'Deprecation-82445-PageTranslationRelatedFunctionality.rst',
+        ],
+    ],
 ];
index c0843db..765af30 100644 (file)
@@ -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 = [
index f9f4b1f..85b77ff 100644 (file)
@@ -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'),
@@ -597,6 +606,146 @@ class RecordList
     }
 
     /**
+     * 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
      */
     public function getModuleTemplate()
index e3c79fe..7d249d0 100644 (file)
@@ -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(
index 9465d4c..f77fa8c 100644 (file)
@@ -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)
index de87dd2..f3fcd47 100644 (file)
@@ -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)
                 )
             )
index 2819d81..4e751a8 100644 (file)
@@ -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"
index 4d41cf8..6d7855d 100644 (file)
@@ -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 = [];
index 414e0ac..4824a5f 100644 (file)
@@ -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)
                 )
             )
index 611e170..0bff987 100644 (file)
@@ -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"
index b90b41e..103c721 100644 (file)
@@ -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();
index 8c923a8..31fe6bf 100644 (file)
@@ -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"
index 8c923a8..31fe6bf 100644 (file)
@@ -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"
index c8ecf17..93d5b6b 100644 (file)
@@ -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,