From cb1d82f7235f3f0bb690d855348e8edee3379c4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Buchmann?= <a.buchmann@zeroseven.de>
Date: Thu, 12 May 2022 16:08:46 +0200
Subject: [PATCH] [BUGFIX] Apply empty values in language-overlay
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Some default fields (e.g. tt_content.bodytext) can contain null values.
TYPO3 first fetches the data in the default language and then overlays
the rows data with the translation values. The overlay method inspects
each array item with the php isset() function. This validates not only
the existence of the array key, but also the values. null and
false values evaluated as false. Empty strings evaluate as true.
This leads to inconsistent output in the frontend.

The overlay now valides only the array key existence and applies also
empty values.

Resolves: #97616
Releases: main, 11.5, 10.4
Change-Id: I4b01c52e9ac7adde786b3395bce870bc0a354b58
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/74837
Tested-by: André Buchmann <andy.schliesser@gmail.com>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: André Buchmann <andy.schliesser@gmail.com>
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../Domain/Repository/PageRepository.php      |  2 +-
 .../Domain/Repository/PageRepositoryTest.php  | 21 +++++++++++++
 .../core/Tests/Functional/Fixtures/pages.xml  | 31 +++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php b/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php
index 4b2fbc6f7735..53288e59741f 100644
--- a/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php
+++ b/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php
@@ -661,7 +661,7 @@ class PageRepository implements LoggerAwareInterface
                             $row['_ORIG_pid'] = $olrow['_ORIG_pid'];
                         }
                         foreach ($row as $fN => $fV) {
-                            if ($fN !== 'uid' && $fN !== 'pid' && isset($olrow[$fN])) {
+                            if ($fN !== 'uid' && $fN !== 'pid' && array_key_exists($fN, $olrow)) {
                                 $row[$fN] = $olrow[$fN];
                             } elseif ($fN === 'uid') {
                                 $row['_LOCALIZED_UID'] = $olrow['uid'];
diff --git a/typo3/sysext/core/Tests/Functional/Domain/Repository/PageRepositoryTest.php b/typo3/sysext/core/Tests/Functional/Domain/Repository/PageRepositoryTest.php
index 1ebe86ed5e44..ee99f71c08b4 100644
--- a/typo3/sysext/core/Tests/Functional/Domain/Repository/PageRepositoryTest.php
+++ b/typo3/sysext/core/Tests/Functional/Domain/Repository/PageRepositoryTest.php
@@ -611,4 +611,25 @@ class PageRepositoryTest extends FunctionalTestCase
         self::assertFalse(isset($row['_PAGES_OVERLAY_UID']));
         self::assertFalse(isset($row['_PAGES_OVERLAY_LANGUAGE']));
     }
+
+    /**
+     * @test
+     */
+    public function getLanguageOverlayResolvesContentWithNullInValues(): void
+    {
+        $context = new Context();
+        $context->setAspect('language', new LanguageAspect(1, 1, LanguageAspect::OVERLAYS_ON_WITH_FLOATING, [0]));
+        $subject = new PageRepository($context);
+        $record = $subject->getRawRecord('tt_content', 1);
+        self::assertSame('Default Content #1', $record['header']);
+        $overlaidRecord = $subject->getLanguageOverlay('tt_content', $record);
+        self::assertSame(2, (int)$overlaidRecord['_LOCALIZED_UID']);
+        self::assertSame('Translated Content #1', $overlaidRecord['header']);
+
+        // Check if "bodytext" is actually overlaid with a NULL value
+        $record = $subject->getRawRecord('tt_content', 3);
+        $overlaidRecord = $subject->getLanguageOverlay('tt_content', $record);
+        self::assertSame('Translated #2', $overlaidRecord['header']);
+        self::assertNull($overlaidRecord['bodytext']);
+    }
 }
diff --git a/typo3/sysext/core/Tests/Functional/Fixtures/pages.xml b/typo3/sysext/core/Tests/Functional/Fixtures/pages.xml
index 126169973cac..b0e7bdcedbda 100644
--- a/typo3/sysext/core/Tests/Functional/Fixtures/pages.xml
+++ b/typo3/sysext/core/Tests/Functional/Fixtures/pages.xml
@@ -184,4 +184,35 @@
         <sys_language_uid>1</sys_language_uid>
         <title>Mount translation</title>
     </pages>
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <header>Default Content #1</header>
+        <bodytext><p>Say thanks for HTML in the DB</p></bodytext>
+        <sys_language_uid>0</sys_language_uid>
+        <l18n_parent>0</l18n_parent>
+    </tt_content>
+    <tt_content>
+        <uid>2</uid>
+        <pid>1</pid>
+        <header>Translated Content #1</header>
+        <bodytext><p>Grazie por HTML en la database</p></bodytext>
+        <sys_language_uid>1</sys_language_uid>
+        <l18n_parent>1</l18n_parent>
+    </tt_content>
+    <tt_content>
+        <uid>3</uid>
+        <pid>1</pid>
+        <header>Default Content #2</header>
+        <bodytext><p>Could be anything</p></bodytext>
+        <sys_language_uid>0</sys_language_uid>
+        <l18n_parent>0</l18n_parent>
+    </tt_content>
+    <tt_content>
+        <uid>4</uid>
+        <pid>1</pid>
+        <header>Translated #2</header>
+        <sys_language_uid>1</sys_language_uid>
+        <l18n_parent>3</l18n_parent>
+    </tt_content>
 </dataset>
-- 
GitLab