From de80a95b7c88422c6f80aae047c515065cb144ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20B=C3=BCrk?= <stefan@buerk.tech>
Date: Wed, 30 Aug 2023 15:23:27 +0200
Subject: [PATCH] [BUGFIX] Ensure correct record type for new record in
 SuggestWizard
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

FormEngine sends some information as payload with the suggest
wizard ajax request to the `SuggestWizardController` as context.
The controller loads the record based on the tableName and
the uid to determine the recordType to read the correct TCA field
configuration, respecting special overrides like `columnsOverrides`.

If a new record is created, there is no record uid available and
passed to the controller. Therefore, the recordType is not properly
determined. That leads to wrong record suggestions, if for example
the `allowed` record table is overriden for specific recordTypes.

This change adds the recordTypeValue as additional html data
attribute to the suggest search field, reads and sends it along
with the context payload in the ajax request to the suggest
wizard controller, which now uses the passed value while keeping
the record retrievement as fallback for now.

Suggest records are now directly searched correctly respecting
the full TCA configuration for the type, even for new records.

Additionally, uid is send as null instead of the string "NaN".

Used command(s):

> Build/Scripts/runTests.sh -s buildJavascript

Resolves: #101796
Releases: main, 12.4, 11.5
Change-Id: I3b814d37b7d4d3e9674ad6f2af882520c4f91413
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/80798
Tested-by: Stefan B�rk <stefan@buerk.tech>
Tested-by: core-ci <typo3@b13.com>
Reviewed-by: Stefan B�rk <stefan@buerk.tech>
---
 .../Resources/Public/TypeScript/FormEngineSuggest.ts   |  2 ++
 .../Controller/Wizard/SuggestWizardController.php      | 10 ++++++++--
 .../backend/Classes/Form/Element/GroupElement.php      |  4 ++++
 .../Resources/Public/JavaScript/FormEngineSuggest.js   |  2 +-
 4 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/FormEngineSuggest.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/FormEngineSuggest.ts
index 1dd6cbef9729..3ddc6019b547 100644
--- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/FormEngineSuggest.ts
+++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/FormEngineSuggest.ts
@@ -56,6 +56,7 @@ class FormEngineSuggest {
     const flexFormFieldName: string = searchField.dataset.flexformfieldname;
     const flexFormContainerName: string = searchField.dataset.flexformcontainername;
     const flexFormContainerFieldName: string = searchField.dataset.flexformcontainerfieldname;
+    const recordTypeValue: string = searchField.dataset.recordtypevalue;
     const minimumCharacters: number = parseInt(searchField.dataset.minchars, 10);
     const url: string = TYPO3.settings.ajaxUrls.record_suggest;
     const params = {
@@ -68,6 +69,7 @@ class FormEngineSuggest {
       flexFormFieldName,
       flexFormContainerName,
       flexFormContainerFieldName,
+      recordTypeValue,
     };
 
     function insertValue(element: HTMLElement): void {
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php b/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
index 43e48a942e2a..e5608d430339 100644
--- a/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
@@ -54,6 +54,7 @@ class SuggestWizardController
         $flexFormFieldName = $parsedBody['flexFormFieldName'] ?? null;
         $flexFormContainerName = $parsedBody['flexFormContainerName'] ?? null;
         $flexFormContainerFieldName = $parsedBody['flexFormContainerFieldName'] ?? null;
+        $recordType = (string)($parsedBody['recordTypeValue'] ?? '');
 
         // Determine TCA config of field
         if (empty($dataStructureIdentifier)) {
@@ -62,8 +63,13 @@ class SuggestWizardController
             $fieldNameInPageTsConfig = $fieldName;
 
             // With possible columnsOverrides
-            $row = BackendUtility::getRecord($tableName, $uid) ?? [];
-            $recordType = BackendUtility::getTCAtypeValue($tableName, $row);
+            // @todo Validate if we can move this fallback recordType determination, should be do-able in v13?!
+            if ($recordType === '') {
+                $recordType = BackendUtility::getTCAtypeValue(
+                    $tableName,
+                    BackendUtility::getRecord($tableName, $uid) ?? []
+                );
+            }
             $columnsOverridesConfigOfField = $GLOBALS['TCA'][$tableName]['types'][$recordType]['columnsOverrides'][$fieldName]['config'] ?? null;
             if ($columnsOverridesConfigOfField) {
                 ArrayUtility::mergeRecursiveWithOverrule($fieldConfig, $columnsOverridesConfigOfField);
diff --git a/typo3/sysext/backend/Classes/Form/Element/GroupElement.php b/typo3/sysext/backend/Classes/Form/Element/GroupElement.php
index 83d48fd29443..8b723a44b071 100644
--- a/typo3/sysext/backend/Classes/Form/Element/GroupElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/GroupElement.php
@@ -118,6 +118,7 @@ class GroupElement extends AbstractFormElement
         $parameterArray = $this->data['parameterArray'];
         $config = $parameterArray['fieldConf']['config'];
         $elementName = $parameterArray['itemFormElName'];
+        $recordTypeValue = $this->data['recordTypeValue'] ?? null;
 
         $selectedItems = $parameterArray['itemFormElValue'];
         $maxItems = $config['maxitems'];
@@ -286,6 +287,9 @@ class GroupElement extends AbstractFormElement
             $html[] =                   ' data-flexformfieldname="' . htmlspecialchars($flexFormFieldName) . '"';
             $html[] =                   ' data-flexformcontainername="' . htmlspecialchars($flexFormContainerName) . '"';
             $html[] =                   ' data-flexformcontainerfieldname="' . htmlspecialchars($flexFormContainerFieldName) . '"';
+            if ($recordTypeValue !== null && $recordTypeValue !== '') {
+                $html[] =                   ' data-recordtypevalue="' . htmlspecialchars($recordTypeValue) . '"';
+            }
             $html[] =               '/>';
             $html[] =           '</div>';
             $html[] =       '</div>';
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineSuggest.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineSuggest.js
index 6d683bcf66b8..81d621a16c75 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineSuggest.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngineSuggest.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine","jquery/autocomplete"],(function(e,t,a,s){"use strict";a=__importDefault(a);return class{constructor(e){(0,a.default)(()=>{this.initialize(e)})}initialize(e){const t=e.closest(".t3-form-suggest-container"),i=e.dataset.tablename,n=e.dataset.fieldname,o=e.dataset.field,l=parseInt(e.dataset.uid,10),r=parseInt(e.dataset.pid,10),d=e.dataset.datastructureidentifier,u=e.dataset.flexformsheetname,m=e.dataset.flexformfieldname,c=e.dataset.flexformcontainername,f=e.dataset.flexformcontainerfieldname,p=parseInt(e.dataset.minchars,10),g=TYPO3.settings.ajaxUrls.record_suggest,x={tableName:i,fieldName:n,uid:l,pid:r,dataStructureIdentifier:d,flexFormSheetName:u,flexFormFieldName:m,flexFormContainerName:c,flexFormContainerFieldName:f};(0,a.default)(e).autocomplete({serviceUrl:g,params:x,type:"POST",paramName:"value",dataType:"json",minChars:p,groupBy:"typeLabel",containerClass:"autocomplete-results",appendTo:t,forceFixPosition:!1,preserveInput:!0,showNoSuggestionNotice:!0,noSuggestionNotice:'<div class="autocomplete-info">No results</div>',minLength:p,preventBadQueries:!1,transformResult:e=>({suggestions:e.map(e=>({value:e.text,data:e}))}),formatResult:e=>(0,a.default)("<div>").append((0,a.default)('<a class="autocomplete-suggestion-link" href="#">'+e.data.sprite+e.data.text+"</a></div>").attr({"data-label":e.data.label,"data-table":e.data.table,"data-uid":e.data.uid})).html(),onSearchComplete:function(){t.classList.add("open")},beforeRender:function(e){e.attr("style",""),t.classList.add("open")},onHide:function(){t.classList.remove("open")},onSelect:function(){!function(t){let i="";i="select"===e.dataset.fieldtype?t.dataset.uid:t.dataset.table+"_"+t.dataset.uid,s.setSelectOptionFromExternalSource(o,i,t.dataset.label,t.dataset.label),s.Validation.markFieldAsChanged((0,a.default)(document.querySelector('input[name="'+o+'"]')))}(t.querySelector(".autocomplete-selected a"))}})}}}));
\ No newline at end of file
+var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine","jquery/autocomplete"],(function(e,t,a,s){"use strict";a=__importDefault(a);return class{constructor(e){(0,a.default)(()=>{this.initialize(e)})}initialize(e){const t=e.closest(".t3-form-suggest-container"),i=e.dataset.tablename,o=e.dataset.fieldname,r=e.dataset.field,l=parseInt(e.dataset.uid,10),n=parseInt(e.dataset.pid,10),d=e.dataset.datastructureidentifier,u=e.dataset.flexformsheetname,c=e.dataset.flexformfieldname,m=e.dataset.flexformcontainername,f=e.dataset.flexformcontainerfieldname,p=e.dataset.recordtypevalue,g=parseInt(e.dataset.minchars,10),x=TYPO3.settings.ajaxUrls.record_suggest,h={tableName:i,fieldName:o,uid:l,pid:n,dataStructureIdentifier:d,flexFormSheetName:u,flexFormFieldName:c,flexFormContainerName:m,flexFormContainerFieldName:f,recordTypeValue:p};(0,a.default)(e).autocomplete({serviceUrl:x,params:h,type:"POST",paramName:"value",dataType:"json",minChars:g,groupBy:"typeLabel",containerClass:"autocomplete-results",appendTo:t,forceFixPosition:!1,preserveInput:!0,showNoSuggestionNotice:!0,noSuggestionNotice:'<div class="autocomplete-info">No results</div>',minLength:g,preventBadQueries:!1,transformResult:e=>({suggestions:e.map(e=>({value:e.text,data:e}))}),formatResult:e=>(0,a.default)("<div>").append((0,a.default)('<a class="autocomplete-suggestion-link" href="#">'+e.data.sprite+e.data.text+"</a></div>").attr({"data-label":e.data.label,"data-table":e.data.table,"data-uid":e.data.uid})).html(),onSearchComplete:function(){t.classList.add("open")},beforeRender:function(e){e.attr("style",""),t.classList.add("open")},onHide:function(){t.classList.remove("open")},onSelect:function(){!function(t){let i="";i="select"===e.dataset.fieldtype?t.dataset.uid:t.dataset.table+"_"+t.dataset.uid,s.setSelectOptionFromExternalSource(r,i,t.dataset.label,t.dataset.label),s.Validation.markFieldAsChanged((0,a.default)(document.querySelector('input[name="'+r+'"]')))}(t.querySelector(".autocomplete-selected a"))}})}}}));
\ No newline at end of file
-- 
GitLab