From 691545ddd1806ad730ffda4c6b0ff97dcec66773 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Mon, 25 Apr 2016 17:37:12 +0200
Subject: [PATCH] [BUGFIX] Respect page TSConfig pid overrides for new inline
 children

TCAdefaults.<table>.pid = <page id> in page TSConfig can be used for
new inline children to define a pid new records should be located at,
even if the parent record is on a different page. This can be useful
when having special storage folders on a per-table-basis.

The patch fixes this feature that broke during FormEngine refactoring.

Change-Id: I8e60155612397e72f1b11a068617f88e3793384b
Resolves: #70780
Releases: master, 7.6
Reviewed-on: https://review.typo3.org/47903
Reviewed-by: Susanne Moog <typo3@susannemoog.de>
Tested-by: Susanne Moog <typo3@susannemoog.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../DatabaseRowInitializeNew.php              | 39 ++++++--
 .../DatabaseRowInitializeNewTest.php          | 90 +++++++++++++++++--
 2 files changed, 117 insertions(+), 12 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseRowInitializeNew.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseRowInitializeNew.php
index 348629f863cb..6e8c7e2ccffa 100644
--- a/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseRowInitializeNew.php
+++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseRowInitializeNew.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Form\FormDataProvider;
 
 use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
 
 /**
  * On "new" command, initialize new database row with default data
@@ -47,11 +48,7 @@ class DatabaseRowInitializeNew implements FormDataProviderInterface
         $result = $this->setDefaultsFromNeighborRow($result);
         $result = $this->setDefaultsFromDevVals($result);
         $result = $this->setDefaultsFromInlineRelations($result);
-
-        // Set pid to vanillaUid. This means, it *can* be negative, if the record is added relative to another record
-        // @todo: For inline records it should be possible to set the pid here via TCAdefaults, but
-        // @todo: those values would be overwritten by this 'pid' setter
-        $result['databaseRow']['pid'] = $result['vanillaUid'];
+        $result = $this->setPid($result);
 
         return $result;
     }
@@ -194,4 +191,36 @@ class DatabaseRowInitializeNew implements FormDataProviderInterface
 
         return $result;
     }
+
+    /**
+     * Set the pid. This is either the vanillaUid (see description in FormDataCompiler),
+     * or a pid given by pageTsConfig for inline children.
+     *
+     * @param array $result Result array
+     * @return array Modified result array
+     * @throws \UnexpectedValueException
+     */
+    protected function setPid(array $result)
+    {
+        // Set pid to vanillaUid. This can be a negative value
+        // if the record is added relative to another record.
+        $result['databaseRow']['pid'] = $result['vanillaUid'];
+
+        // In case a new inline record is created, the pid can be set to a different value
+        // by pageTsConfig, but not by userTsConfig. This overrides the above pid selection
+        // and forces the pid of new inline children.
+        $tableNameWithDot = $result['tableName'] . '.';
+        if ($result['isInlineChild'] && isset($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'])) {
+            if (!MathUtility::canBeInterpretedAsInteger($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'])) {
+                throw new \UnexpectedValueException(
+                    'page TSConfig setting TCAdefaults.' . $tableNameWithDot . 'pid must be a number, but given string '
+                    . $result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'] . ' can not be interpreted as integer',
+                    1461598332
+                );
+            }
+            $result['databaseRow']['pid'] = (int)$result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'];
+        }
+
+        return $result;
+    }
 }
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseRowInitializeNewTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseRowInitializeNewTest.php
index cf7f347d9155..5af0e0919af7 100644
--- a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseRowInitializeNewTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseRowInitializeNewTest.php
@@ -64,7 +64,8 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
             'command' => 'new',
             'databaseRow' => 'not-an-array',
         ];
-        $this->setExpectedException(\UnexpectedValueException::class, '', 1444431128);
+        $this->expectException(\UnexpectedValueException::class);
+        $this->expectExceptionCode(1444431128);
         $this->subject->addData($input);
     }
 
@@ -89,7 +90,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFormUserTsIfColumnIsDenfinedInTca()
+    public function addDataSetsDefaultDataFormUserTsIfColumnIsDefinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -148,7 +149,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFormPageTsIfColumnIsDenfinedInTca()
+    public function addDataSetsDefaultDataFormPageTsIfColumnIsDefinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -350,7 +351,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFormPostIfColumnIsDenfinedInTca()
+    public function addDataSetsDefaultDataFromPostIfColumnIsDenfinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -519,7 +520,8 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
             'databaseRow' => [],
             'inlineChildChildUid' => 42,
         ];
-        $this->setExpectedException(\UnexpectedValueException::class, '', 1444434102);
+        $this->expectException(\UnexpectedValueException::class);
+        $this->expectExceptionCode(1444434102);
         $this->subject->addData($input);
     }
 
@@ -533,7 +535,8 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
             'databaseRow' => [],
             'inlineChildChildUid' => '42',
         ];
-        $this->setExpectedException(\UnexpectedValueException::class, '', 1444434103);
+        $this->expectException(\UnexpectedValueException::class);
+        $this->expectExceptionCode(1444434103);
         $this->subject->addData($input);
     }
 
@@ -589,7 +592,8 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
                 ],
             ],
         ];
-        $this->setExpectedException(\UnexpectedValueException::class, '', 1444434104);
+        $this->expectException(\UnexpectedValueException::class);
+        $this->expectExceptionCode(1444434104);
         $this->subject->addData($input);
     }
 
@@ -608,4 +612,76 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
         $result = $this->subject->addData($input);
         $this->assertSame($expected, $result['databaseRow']);
     }
+
+    /**
+     * @test
+     */
+    public function addDataDoesNotUsePageTsValueForPidIfRecordIsNotInlineChild()
+    {
+        $input = [
+            'command' => 'new',
+            'tableName' => 'aTable',
+            'vanillaUid' => 23,
+            'databaseRow' => [],
+            'pageTsConfig' => [
+                'TCAdefaults.' => [
+                    'aTable.' => [
+                        'pid' => '42',
+                    ],
+                ],
+            ],
+            'isInlineChild' => false,
+        ];
+        $expected = $input;
+        $expected['databaseRow']['pid'] = 23;
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
+
+    /**
+     * @test
+     */
+    public function addDataThrowsExceptionIfPageTsConfigPidValueCanNotBeInterpretedAsInteger()
+    {
+        $input = [
+            'command' => 'new',
+            'tableName' => 'aTable',
+            'vanillaUid' => 23,
+            'databaseRow' => [],
+            'pageTsConfig' => [
+                'TCAdefaults.' => [
+                    'aTable.' => [
+                        'pid' => 'notAnInteger',
+                    ],
+                ],
+            ],
+            'isInlineChild' => true,
+        ];
+        $this->expectException(\UnexpectedValueException::class);
+        $this->expectExceptionCode(1461598332);
+        $this->subject->addData($input);
+    }
+
+    /**
+     * @test
+     */
+    public function addDataDoesUsePageTsValueForPidIfRecordIsInlineChild()
+    {
+        $input = [
+            'command' => 'new',
+            'tableName' => 'aTable',
+            'vanillaUid' => 23,
+            'databaseRow' => [],
+            'pageTsConfig' => [
+                'TCAdefaults.' => [
+                    'aTable.' => [
+                        'pid' => '42',
+                    ],
+                ],
+            ],
+            'isInlineChild' => true,
+        ];
+        $expected = $input;
+        $expected['databaseRow']['pid'] = 42;
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
 }
-- 
GitLab