From b61e71170ff80a83fcbb6e87a9fcc751fa9ca393 Mon Sep 17 00:00:00 2001
From: Gernot Leitgab <typo3@webentwickler.at>
Date: Fri, 2 Sep 2016 20:59:26 +0200
Subject: [PATCH] [BUGFIX] Return null value instead of string 'NULL'

Add local getPlainValue method in persistence backend, so a
null value instead of string 'NULL' is written to database.

Resolves: #68994
Related: #57255
Releases: master, 8.7
Change-Id: Idb61caabf5115da4bb818d2ed8bb4faa16f5df2c
Reviewed-on: https://review.typo3.org/43627
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
---
 .../Classes/Persistence/Generic/Backend.php   | 26 ++++++++++---
 .../Classes/Domain/Model/Blog.php             | 23 ++++++++++++
 .../TCA/tx_blogexample_domain_model_blog.php  |  9 +++++
 .../Private/Language/locallang_db.xml         |  1 +
 .../Extensions/blog_example/ext_tables.sql    |  1 +
 .../Tests/Functional/Persistence/AddTest.php  | 37 +++++++++++++++++++
 6 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php
index 02d0657b5c2a..e78954e00116 100644
--- a/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php
+++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php
@@ -398,14 +398,11 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
                     if ($propertyValue->_isNew()) {
                         $this->insertObject($propertyValue, $object, $propertyName);
                     }
-                    // Check explicitly for NULL, as getPlainValue would convert this to 'NULL'
-                    $row[$columnMap->getColumnName()] = $propertyValue !== null
-                        ? $this->dataMapper->getPlainValue($propertyValue)
-                        : null;
+                    $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
                 }
                 $queue[] = $propertyValue;
             } elseif ($object->_isNew() || $object->_isDirty($propertyName)) {
-                $row[$columnMap->getColumnName()] = $this->dataMapper->getPlainValue($propertyValue, $columnMap);
+                $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue, $columnMap);
             }
         }
         if (!empty($row)) {
@@ -677,7 +674,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
                     $row[$columnMap->getColumnName()] = 0;
                 }
             } elseif ($propertyValue !== null) {
-                $row[$columnMap->getColumnName()] = $this->dataMapper->getPlainValue($propertyValue, $columnMap);
+                $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue, $columnMap);
             }
         }
         $this->addCommonFieldsToRow($object, $row);
@@ -1123,4 +1120,21 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
         $storagePidList = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $frameworkConfiguration['persistence']['storagePid']);
         return (int)$storagePidList[0];
     }
+
+    /**
+     * Returns a plain value
+     *
+     * i.e. objects are flattened out if possible.
+     * Checks explicitly for null values as DataMapper's getPlainValue would convert this to 'NULL'
+     *
+     * @param mixed $input The value that will be converted
+     * @param ColumnMap $columnMap Optional column map for retrieving the date storage format
+     * @return int|string|null
+     */
+    protected function getPlainValue($input, ColumnMap $columnMap = null)
+    {
+        return $input !== null
+            ? $this->dataMapper->getPlainValue($input, $columnMap)
+            : null;
+    }
 }
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php
index 7a96e03ec68d..69c02e93640e 100644
--- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php
@@ -27,6 +27,13 @@ class Blog extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
      */
     protected $title = '';
 
+    /**
+     * The blog's subtitle
+     *
+     * @var string
+     */
+    protected $subtitle;
+
     /**
      * A short description of the blog
      *
@@ -72,6 +79,14 @@ class Blog extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
         $this->posts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
     }
 
+    /**
+     * @return string
+     */
+    public function getSubtitle()
+    {
+        return $this->subtitle;
+    }
+
     /**
      * Sets this blog's title
      *
@@ -225,4 +240,12 @@ class Blog extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
     {
         return $this->administrator;
     }
+
+    /**
+     * @param ?string $subtitle
+     */
+    public function setSubtitle($subtitle)
+    {
+        $this->subtitle = $subtitle;
+    }
 }
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/tx_blogexample_domain_model_blog.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/tx_blogexample_domain_model_blog.php
index c0611eae7cd7..716f43ad7bcb 100644
--- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/tx_blogexample_domain_model_blog.php
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/tx_blogexample_domain_model_blog.php
@@ -107,6 +107,15 @@ return [
                 'max' => 256
             ]
         ],
+        'subtitle' => [
+            'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.subtitle',
+            'config' => [
+                'type' => 'input',
+                'size' => 20,
+                'eval' => 'trim',
+                'max' => 256
+            ]
+        ],
         'description' => [
             'exclude' => true,
             'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.description',
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml
index feeef2e08c96..50a05731ee4e 100644
--- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml
@@ -15,6 +15,7 @@
 			<label index="tx_blogexample_domain_model_post">Post</label>
 			<label index="tx_blogexample_domain_model_post.blog">Related to</label>
 			<label index="tx_blogexample_domain_model_post.title">Title</label>
+			<label index="tx_blogexample_domain_model_post.subtitle">Title</label>
 			<label index="tx_blogexample_domain_model_post.date">Date</label>
 			<label index="tx_blogexample_domain_model_post.author">Author</label>
 			<label index="tx_blogexample_domain_model_post.content">Content</label>
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql
index e04333ad3141..7794b40693b9 100644
--- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql
@@ -6,6 +6,7 @@ CREATE TABLE tx_blogexample_domain_model_blog (
 	pid int(11) DEFAULT '0' NOT NULL,
 
 	title varchar(255) DEFAULT '' NOT NULL,
+	subtitle varchar(255) DEFAULT '',
 	description text NOT NULL,
 	logo tinyblob NOT NULL,
 	administrator int(11) DEFAULT '0' NOT NULL,
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/AddTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/AddTest.php
index 1c91cc99c83d..eafa12c83532 100644
--- a/typo3/sysext/extbase/Tests/Functional/Persistence/AddTest.php
+++ b/typo3/sysext/extbase/Tests/Functional/Persistence/AddTest.php
@@ -146,4 +146,41 @@ class AddTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
             ->fetch();
         $this->assertEquals(-1, $newBlogRecord['sys_language_uid']);
     }
+
+    /**
+    * @test
+    */
+    public function addObjectSetsNullAsNullForSimpleTypes()
+    {
+        $newBlogTitle = 'aDi1oogh';
+        $newBlog = $this->objectManager->get(\ExtbaseTeam\BlogExample\Domain\Model\Blog::class);
+        $newBlog->setTitle($newBlogTitle);
+        $newBlog->setSubtitle('subtitle');
+
+        /** @var \ExtbaseTeam\BlogExample\Domain\Repository\BlogRepository $blogRepository */
+        $this->blogRepository->add($newBlog);
+        $this->persistentManager->persistAll();
+
+        // make sure null can be set explicitly
+        $insertedBlog = $this->blogRepository->findByUid(1);
+        $insertedBlog->setSubtitle(null);
+        $this->blogRepository->update($insertedBlog);
+        $this->persistentManager->persistAll();
+
+        $queryBuilder = (new ConnectionPool())->getQueryBuilderForTable('tx_blogexample_domain_model_blog');
+        $queryBuilder->getRestrictions()
+            ->removeAll();
+        $newBlogRecord = $queryBuilder
+            ->select('*')
+            ->from('tx_blogexample_domain_model_blog')
+            ->where(
+                $queryBuilder->expr()->eq(
+                    'subtitle',
+                    $queryBuilder->createNamedParameter($newBlogTitle, \PDO::PARAM_STR)
+                )
+            )
+            ->execute()
+            ->fetch();
+        $this->assertNull($newBlogRecord['subtitle']);
+    }
 }
-- 
GitLab