From 8c81e38b5df835ef65b99324479dca214d5884c5 Mon Sep 17 00:00:00 2001
From: Georg Ringer <georg.ringer@gmail.com>
Date: Mon, 12 Dec 2022 16:25:14 +0100
Subject: [PATCH] [TASK] Provide more information to itemsProcFunc calls

Adding the following information to itemsProcFunc helps extension
authors:
- effectivePid: correct page id
- site: current site

Resolves: #99346
Releases: main, 12.4
Change-Id: Ifc54a06c66f3dbf61a2e95f706bb54e74db4b28e
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82240
Tested-by: core-ci <typo3@b13.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
---
 .../FormDataProvider/AbstractItemProvider.php |  3 ++-
 .../FormDataProvider/TcaSelectItemsTest.php   |  9 +++++++++
 .../FormDataProvider/TcaCheckboxItemsTest.php |  7 +++++++
 .../FormDataProvider/TcaRadioItemsTest.php    |  7 +++++++
 .../Tests/Unit/Utility/BackendUtilityTest.php |  8 ++++++++
 .../DataHandling/ItemProcessingService.php    | 19 +++++++++++++++++++
 typo3/sysext/core/Configuration/Services.yaml |  3 +++
 7 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
index c023fc54cf37..be6aec09c2a9 100644
--- a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
+++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
@@ -73,6 +73,8 @@ abstract class AbstractItemProvider
             'table' => $table,
             'row' => $result['databaseRow'],
             'field' => $fieldName,
+            'effectivePid' => $result['effectivePid'],
+            'site' => $result['site'],
             // IMPORTANT: Below fields are only available in FormEngine context.
             // They are not used by the DataHandler when processing itemsProcFunc
             // for checking if a submitted value is valid. This means, in case
@@ -92,7 +94,6 @@ abstract class AbstractItemProvider
         if (!empty($result['flexParentDatabaseRow'])) {
             $processorParameters['flexParentDatabaseRow'] = $result['flexParentDatabaseRow'];
         }
-
         try {
             $items = array_map(
                 fn(array $item) => SelectItem::fromTcaItemArray($item, $config['type']),
diff --git a/typo3/sysext/backend/Tests/Functional/Form/FormDataProvider/TcaSelectItemsTest.php b/typo3/sysext/backend/Tests/Functional/Form/FormDataProvider/TcaSelectItemsTest.php
index c1c0ba459cb4..f689176f75b5 100644
--- a/typo3/sysext/backend/Tests/Functional/Form/FormDataProvider/TcaSelectItemsTest.php
+++ b/typo3/sysext/backend/Tests/Functional/Form/FormDataProvider/TcaSelectItemsTest.php
@@ -1894,6 +1894,8 @@ final class TcaSelectItemsTest extends FunctionalTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'processedTca' => [
                 'columns' => [
                     'aField' => [
@@ -1962,6 +1964,7 @@ final class TcaSelectItemsTest extends FunctionalTestCase
             'inlineTopMostParentTableName' => 'topMostTable',
             'inlineTopMostParentFieldName' => 'topMostField',
             'effectivePid' => 1,
+            'site' => new Site('aSite', 456, []),
             'processedTca' => [
                 'columns' => [
                     'aField' => [
@@ -2040,6 +2043,7 @@ final class TcaSelectItemsTest extends FunctionalTestCase
             'inlineTopMostParentTableName' => 'topMostTable',
             'inlineTopMostParentFieldName' => 'topMostField',
             'effectivePid' => 1,
+            'site' => new Site('aSite', 456, []),
             'processedTca' => [
                 'columns' => [
                     'aField' => [
@@ -2127,6 +2131,7 @@ final class TcaSelectItemsTest extends FunctionalTestCase
             'inlineTopMostParentTableName' => 'topMostTable',
             'inlineTopMostParentFieldName' => 'topMostField',
             'effectivePid' => 1,
+            'site' => new Site('aSite', 456, []),
             'processedTca' => [
                 'columns' => [
                     'aField' => [
@@ -2215,6 +2220,8 @@ final class TcaSelectItemsTest extends FunctionalTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'pageTsConfig' => [
                 'TCEFORM.' => [
                     'aTable.' => [
@@ -2288,6 +2295,8 @@ final class TcaSelectItemsTest extends FunctionalTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'pageTsConfig' => [
                 'TCEFORM.' => [
                     'aTable.' => [
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaCheckboxItemsTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaCheckboxItemsTest.php
index cd5383eaa96e..d705dee1c7bb 100644
--- a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaCheckboxItemsTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaCheckboxItemsTest.php
@@ -22,6 +22,7 @@ use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
+use TYPO3\CMS\Core\Site\Entity\Site;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
@@ -501,6 +502,8 @@ final class TcaCheckboxItemsTest extends UnitTestCase
             'inlineTopMostParentTableName' => 'topMostTable',
             'inlineTopMostParentFieldName' => 'topMostField',
             'databaseRow' => [],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'processedTca' => [
                 'columns' => [
                     'aField' => [
@@ -545,6 +548,8 @@ final class TcaCheckboxItemsTest extends UnitTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'pageTsConfig' => [
                 'TCEFORM.' => [
                     'aTable.' => [
@@ -631,6 +636,8 @@ final class TcaCheckboxItemsTest extends UnitTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'pageTsConfig' => [
                 'TCEFORM.' => [
                     'aTable.' => [
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaRadioItemsTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaRadioItemsTest.php
index 3a40fcb125ba..1106e44327bf 100644
--- a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaRadioItemsTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaRadioItemsTest.php
@@ -22,6 +22,7 @@ use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
+use TYPO3\CMS\Core\Site\Entity\Site;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
@@ -239,6 +240,8 @@ final class TcaRadioItemsTest extends UnitTestCase
             'inlineTopMostParentTableName' => 'topMostTable',
             'inlineTopMostParentFieldName' => 'topMostField',
             'databaseRow' => [],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'processedTca' => [
                 'columns' => [
                     'aField' => [
@@ -284,6 +287,8 @@ final class TcaRadioItemsTest extends UnitTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'pageTsConfig' => [
                 'TCEFORM.' => [
                     'aTable.' => [
@@ -365,6 +370,8 @@ final class TcaRadioItemsTest extends UnitTestCase
             'databaseRow' => [
                 'aField' => 'aValue',
             ],
+            'effectivePid' => 42,
+            'site' => new Site('aSite', 456, []),
             'pageTsConfig' => [
                 'TCEFORM.' => [
                     'aTable.' => [
diff --git a/typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php b/typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php
index ab7811eb0b37..8216e2199fba 100644
--- a/typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php
@@ -23,7 +23,9 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Database\RelationHandler;
+use TYPO3\CMS\Core\DataHandling\ItemProcessingService;
 use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\TypoScript\AST\Node\RootNode;
 use TYPO3\CMS\Core\TypoScript\PageTsConfig;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -921,10 +923,13 @@ final class BackendUtilityTest extends UnitTestCase
             ['pageTsConfig-pid-to-hash-0', 'hash'],
             ['pageTsConfig-hash-to-object-hash', new PageTsConfig(new RootNode())],
         ]);
+        $siteFinderMock = $this->createMock(SiteFinder::class);
+        GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService($siteFinderMock));
         GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerMock);
 
         $label = BackendUtility::getLabelFromItemlist($table, $col, $key);
         self::assertEquals($label, $expectedLabel);
+        GeneralUtility::purgeInstances();
     }
 
     public static function getLabelFromItemListMergedReturnsCorrectFieldsDataProvider(): array
@@ -1082,11 +1087,14 @@ final class BackendUtilityTest extends UnitTestCase
              ['pageTsConfig-pid-to-hash-0', 'hash'],
              ['pageTsConfig-hash-to-object-hash', new PageTsConfig(new RootNode())],
         ]);
+        $siteFinderMock = $this->createMock(SiteFinder::class);
+        GeneralUtility::addInstance(ItemProcessingService::class, new ItemProcessingService($siteFinderMock));
         GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerMock);
 
         $GLOBALS['TCA'][$table] = $tca;
         $label = BackendUtility::getLabelsFromItemsList($table, $col, $keyList, $pageTsConfig);
         self::assertEquals($expectedLabel, $label);
+        GeneralUtility::purgeInstances();
     }
 
     /**
diff --git a/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php b/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php
index c13dd6ab6e09..840957fc15ae 100644
--- a/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php
+++ b/typo3/sysext/core/Classes/DataHandling/ItemProcessingService.php
@@ -16,10 +16,14 @@
 namespace TYPO3\CMS\Core\DataHandling;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Exception\SiteNotFoundException;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Schema\Struct\SelectItem;
+use TYPO3\CMS\Core\Site\Entity\NullSite;
+use TYPO3\CMS\Core\Site\Entity\SiteInterface;
+use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -28,6 +32,10 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class ItemProcessingService
 {
+    public function __construct(
+        protected readonly SiteFinder $siteFinder
+    ) {}
+
     /**
      * Executes an itemsProcFunc if defined in TCA and returns the combined result (predefined + processed items)
      *
@@ -52,6 +60,8 @@ class ItemProcessingService
         $params['table'] = $table;
         $params['row'] = $row;
         $params['field'] = $field;
+        $params['effectivePid'] = $realPid;
+        $params['site'] = $this->resolveSite($realPid);
 
         // The itemsProcFunc method may throw an exception.
         // If it does, display an error message and return items unchanged.
@@ -91,6 +101,15 @@ class ItemProcessingService
         return $selectedItems;
     }
 
+    protected function resolveSite(int $pageId): SiteInterface
+    {
+        try {
+            return $this->siteFinder->getSiteByPageId($pageId);
+        } catch (SiteNotFoundException $e) {
+            return new NullSite();
+        }
+    }
+
     protected function getLanguageService(): LanguageService
     {
         return $GLOBALS['LANG'];
diff --git a/typo3/sysext/core/Configuration/Services.yaml b/typo3/sysext/core/Configuration/Services.yaml
index c7ef53fd31a4..236f6debec7c 100644
--- a/typo3/sysext/core/Configuration/Services.yaml
+++ b/typo3/sysext/core/Configuration/Services.yaml
@@ -76,6 +76,9 @@ services:
   TYPO3\CMS\Core\Database\Schema\SchemaMigrator:
     public: true
 
+  TYPO3\CMS\Core\DataHandling\ItemProcessingService:
+    public: true
+
   TYPO3\CMS\Core\Database\Schema\SqlReader:
     public: true
 
-- 
GitLab