Commit c5ee13f0 authored by Morton Jonuschat's avatar Morton Jonuschat Committed by Christian Kuhn
Browse files

[TASK] FormEngine: Move SelectTree processing into a data provider

The handling of select form elements with renderType "selectTree" has
been cleanly separated into a dedicated pair of element renderer and
data provider.

Methods used by the default select item provider as well as the tree
item provider have been moved into the AbstractItemProvider, the usage
of the AbstractItemProvider class has been cleaned up and is now limited
to data providers that deal with items.

Preparing the javascript for the tree rendering has been moved into a
dedicated method in the SelectTreeElement.

TcaSelectTreeItemsTest only covers the special data parsing/preparation
needed for the tree display, all common test cases for select item
handling are covered in TcaSelectItemsTest which covers the methods
provided by AbstractItemProvider.

Resolves: #69728
Releases: master
Change-Id: Idabb99263fe8dc860e4ec19c26a8cfe5b5a61fa3
Reviewed-on: https://review.typo3.org/43252

Reviewed-by: Andreas Fernandez's avatarAndreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez's avatarAndreas Fernandez <typo3@scripting-base.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent cb391733
......@@ -16,9 +16,6 @@ namespace TYPO3\CMS\Backend\Form\Element;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Tree\TableConfiguration\ExtJsArrayTreeRenderer;
use TYPO3\CMS\Core\Tree\TableConfiguration\TableConfigurationTree;
use TYPO3\CMS\Core\Tree\TableConfiguration\TreeDataProviderFactory;
use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
use TYPO3\CMS\Core\Utility\GeneralUtility;
......@@ -29,101 +26,108 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*/
class SelectTreeElement extends AbstractFormElement
{
/**
* Default height of the tree in pixels.
*
* @const
*/
const DEFAULT_HEIGHT = 280;
/**
* Default width of the tree in pixels.
*
* @const
*/
const DEFAULT_WIDTH = 280;
/**
* Render tree widget
*
* @return array As defined in initializeResultArray() of AbstractNode
* @see AbstractNode::initializeResultArray()
*/
public function render()
{
$table = $this->data['tableName'];
$field = $this->data['fieldName'];
$row = $this->data['databaseRow'];
$resultArray = $this->initializeResultArray();
$parameterArray = $this->data['parameterArray'];
$formElementId = md5($parameterArray['itemFormElName']);
// Field configuration from TCA:
$config = $parameterArray['fieldConf']['config'];
$possibleSelectboxItems = $config['items'];
$resultArray['extJSCODE'] .= LF . $this->generateJavascript($formElementId);
$selectedNodes = $parameterArray['itemFormElValue'];
$html = [];
$html[] = '<div class="typo3-tceforms-tree">';
$html[] = ' <input class="treeRecord" type="hidden"';
$html[] = ' ' . $this->getValidationDataAsDataAttribute($parameterArray['fieldConf']['config']);
$html[] = ' data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '"';
$html[] = ' data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '"';
$html[] = ' name="' . htmlspecialchars($parameterArray['itemFormElName']) . '"';
$html[] = ' id="treeinput' . $formElementId . '"';
$html[] = ' value="' . htmlspecialchars(implode(',', $config['treeData']['selectedNodes'])) . '"';
$html[] = ' />';
$html[] = '</div>';
$html[] = '<div id="tree_' . $formElementId . '"></div>';
$selectedNodesForApi = array();
foreach ($selectedNodes as $selectedNode) {
// @todo: this is ugly - the "old" pipe based value|label syntax is re-created here at the moment
foreach ($possibleSelectboxItems as $possibleSelectboxItem) {
if ((string)$possibleSelectboxItem[1] === (string)$selectedNode) {
$selectedNodesForApi[] = $selectedNode . '|' . rawurlencode($possibleSelectboxItem[0]);
}
}
}
$resultArray['html'] = implode(LF, $html);
$allowedUids = array();
foreach ($possibleSelectboxItems as $item) {
if ((int)$item[1] > 0) {
$allowedUids[] = $item[1];
}
}
$treeDataProvider = TreeDataProviderFactory::getDataProvider($config, $table, $field, $row);
$treeDataProvider->setSelectedList(implode(',', $selectedNodes));
$treeDataProvider->setItemWhiteList($allowedUids);
$treeDataProvider->initializeTreeData();
$treeRenderer = GeneralUtility::makeInstance(ExtJsArrayTreeRenderer::class);
$tree = GeneralUtility::makeInstance(TableConfigurationTree::class);
$tree->setDataProvider($treeDataProvider);
$tree->setNodeRenderer($treeRenderer);
$treeData = $tree->render();
$itemArray = array();
/**
* @todo: Small bug here: In the past, this was the "not processed list" of default items, but now it is
* @todo: a full list of elements. This needs to be fixed later, so "additional" default items are shown again.
if (is_array($config['items'])) {
foreach ($config['items'] as $additionalItem) {
if ($additionalItem[1] !== '--div--') {
$item = new \stdClass();
$item->uid = $additionalItem[1];
$item->text = $this->getLanguageService()->sL($additionalItem[0]);
$item->selectable = TRUE;
$item->leaf = TRUE;
$item->checked = in_array($additionalItem[1], $selectedNodes);
if (file_exists(PATH_typo3 . $additionalItem[3])) {
$item->icon = $additionalItem[3];
} elseif (trim($additionalItem[3]) !== '') {
$item->iconCls = IconUtility::getSpriteIconClasses($additionalItem[3]);
}
$itemArray[] = $item;
}
}
// Wizards:
if (empty($config['readOnly'])) {
$resultArray['html'] = $this->renderWizards(
[$resultArray['html']],
$config['wizards'],
$this->data['tableName'],
$this->data['databaseRow'],
$this->data['fieldName'],
$parameterArray,
$parameterArray['itemFormElName'],
BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])
);
}
*/
$itemArray[] = $treeData;
$id = md5($parameterArray['itemFormElName']);
return $resultArray;
}
/**
* Generates the Ext JS tree JavaScript code.
*
* @param string $formElementId The HTML element ID of the tree select field.
* @return string
*/
protected function generateJavascript($formElementId)
{
$table = $this->data['tableName'];
$field = $this->data['fieldName'];
$parameterArray = $this->data['parameterArray'];
$config = $parameterArray['fieldConf']['config'];
$selectedNodes = $this->data['databaseRow'][$this->data['fieldName']];
$disabled = !empty($config['readOnly']) ? 'true' : 'false';
$maxItems = $config['maxitems'] ? (int)$config['maxitems'] : 99999;
$exclusiveKeys = !empty($config['exclusiveKeys']) ? $config['exclusiveKeys'] : '';
$appearance = !empty($config['treeConfig']['appearance']) ? $config['treeConfig']['appearance'] : [];
$width = isset($appearance['width']) ? (int)$appearance['width'] : static::DEFAULT_WIDTH;
if (isset($config['size']) && (int)$config['size'] > 0) {
$height = (int)$config['size'] * 20;
} else {
$height = 280;
$height = static::DEFAULT_HEIGHT;
}
$showHeader = !empty($appearance['showHeader']);
$expanded = !empty($appearance['expandAll']);
$allowRecursiveMode = !empty($appearance['allowRecursiveMode']) ? 'true' : 'false';
$autoSizeMax = null;
if (isset($config['autoSizeMax']) && (int)$config['autoSizeMax'] > 0) {
$autoSizeMax = (int)$config['autoSizeMax'] * 20;
}
$header = false;
$expanded = false;
$width = 280;
$appearance = $config['treeConfig']['appearance'];
if (is_array($appearance)) {
$header = (bool)$appearance['showHeader'];
$expanded = (bool)$appearance['expandAll'];
if (isset($appearance['width'])) {
$width = (int)$appearance['width'];
}
}
$onChange = '';
if ($parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged']) {
$onChange = $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
}
$onChange = !empty($parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged']) ? $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] : '';
$onChange .= !empty($parameterArray['fieldChangeFunc']['alert']) ? $parameterArray['fieldChangeFunc']['alert'] : '';
// Create a JavaScript code line which will ask the user to save/update the form due to changing the element.
// This is used for eg. "type" fields and others configured with "requestUpdate"
if (
......@@ -138,97 +142,79 @@ class SelectTreeElement extends AbstractFormElement
$onChange .= 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
}
}
$html = '
<div class="typo3-tceforms-tree">
<input class="treeRecord" type="hidden" '
. $this->getValidationDataAsDataAttribute($config)
. ' data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '"'
. ' data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '"'
. ' name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" id="treeinput' . $id . '" value="' . htmlspecialchars(implode(',', $selectedNodesForApi)) . '" />
</div>
<div id="tree_' . $id . '">
</div>';
// Wizards:
if (empty($config['readOnly'])) {
$html = $this->renderWizards(
array($html),
$config['wizards'],
$table,
$row,
$field,
$parameterArray,
$parameterArray['itemFormElName'],
BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])
);
$javascript = [];
$javascript[] = 'Ext.onReady(function() {';
$javascript[] = ' TYPO3.Components.Tree.StandardTreeItemData["' . $formElementId . '"] = ' . json_encode($config['treeData']['items']) . ';';
$javascript[] = ' var tree' . $formElementId . ' = new TYPO3.Components.Tree.StandardTree({';
$javascript[] = ' id: "' . $formElementId . '",';
$javascript[] = ' stateful: true,';
$javascript[] = ' stateId: "tcaTrees." + this.ucId,';
$javascript[] = ' stateEvents: [],';
$javascript[] = ' showHeader: ' . (int)$showHeader . ',';
$javascript[] = ' onChange: ' . GeneralUtility::quoteJSvalue($onChange) . ',';
$javascript[] = ' countSelectedNodes: ' . count($selectedNodes) . ',';
$javascript[] = ' width: ' . $width . ',';
$javascript[] = ' rendering: false,';
$javascript[] = ' listeners: {';
$javascript[] = ' click: function(node, event) {';
$javascript[] = ' if (typeof(node.attributes.checked) == "boolean") {';
$javascript[] = ' node.attributes.checked = ! node.attributes.checked;';
$javascript[] = ' node.getUI().toggleCheck(node.attributes.checked);';
$javascript[] = ' }';
$javascript[] = ' },';
$javascript[] = ' dblclick: function(node, event) {';
$javascript[] = ' if (typeof(node.attributes.checked) == "boolean") {';
$javascript[] = ' node.attributes.checked = ! node.attributes.checked;';
$javascript[] = ' node.getUI().toggleCheck(node.attributes.checked);';
$javascript[] = ' }';
$javascript[] = ' },';
$javascript[] = ' checkchange: TYPO3.Components.Tree.TcaCheckChangeHandler,';
$javascript[] = ' collapsenode: function(node) {';
$javascript[] = ' if (node.id !== "root" && !this.rendering) {';
$javascript[] = ' top.TYPO3.Storage.Persistent.removeFromList("tcaTrees." + this.ucId, node.attributes.uid);';
$javascript[] = ' }';
$javascript[] = ' },';
$javascript[] = ' expandnode: function(node) {';
$javascript[] = ' if (node.id !== "root" && !this.rendering) {';
$javascript[] = ' top.TYPO3.Storage.Persistent.addToList("tcaTrees." + this.ucId, node.attributes.uid);';
$javascript[] = ' }';
$javascript[] = ' },';
$javascript[] = ' beforerender: function(treeCmp) {';
$javascript[] = ' this.rendering = true';
$javascript[] = ' // Check if that tree element is already rendered. It is appended on the first tceforms_inline call.';
$javascript[] = ' if (Ext.fly(treeCmp.getId())) {';
$javascript[] = ' return false;';
$javascript[] = ' }';
$javascript[] = ' },';
$javascript[] = ' afterrender: function(treeCmp) {';
if ($expanded) {
$javascript[] = ' treeCmp.expandAll();';
}
$resultArray = $this->initializeResultArray();
$resultArray['extJSCODE'] .= LF .
'Ext.onReady(function() {
TYPO3.Components.Tree.StandardTreeItemData["' . $id . '"] = ' . json_encode($itemArray) . ';
var tree' . $id . ' = new TYPO3.Components.Tree.StandardTree({
id: "' . $id . '",
showHeader: ' . (int)$header . ',
onChange: ' . GeneralUtility::quoteJSvalue($onChange) . ',
countSelectedNodes: ' . count($selectedNodes) . ',
width: ' . (int)$width . ',
rendering: false,
listeners: {
click: function(node, event) {
if (typeof(node.attributes.checked) == "boolean") {
node.attributes.checked = ! node.attributes.checked;
node.getUI().toggleCheck(node.attributes.checked);
}
},
dblclick: function(node, event) {
if (typeof(node.attributes.checked) == "boolean") {
node.attributes.checked = ! node.attributes.checked;
node.getUI().toggleCheck(node.attributes.checked);
}
},
checkchange: TYPO3.Components.Tree.TcaCheckChangeHandler,
collapsenode: function(node) {
if (node.id !== "root" && !this.rendering) {
top.TYPO3.Storage.Persistent.removeFromList("tcaTrees." + this.ucId, node.attributes.uid);
}
},
expandnode: function(node) {
if (node.id !== "root" && !this.rendering) {
top.TYPO3.Storage.Persistent.addToList("tcaTrees." + this.ucId, node.attributes.uid);
}
},
beforerender: function(treeCmp) {
this.rendering = true;
// Check if that tree element is already rendered. It is appended on the first tceforms_inline call.
if (Ext.fly(treeCmp.getId())) {
return false;
}
},
afterrender: function(treeCmp) {
' . ($expanded ? 'treeCmp.expandAll();' : '') . '
this.rendering = false;
}
},
tcaMaxItems: ' . ($config['maxitems'] ? (int)$config['maxitems'] : 99999) . ',
tcaSelectRecursiveAllowed: ' . ($appearance['allowRecursiveMode'] ? 'true' : 'false') . ',
tcaSelectRecursive: false,
tcaExclusiveKeys: "' . ($config['exclusiveKeys'] ? $config['exclusiveKeys'] : '') . '",
ucId: "' . md5(($table . '|' . $field)) . '",
selModel: TYPO3.Components.Tree.EmptySelectionModel,
disabled: ' . ($config['readOnly'] ? 'true' : 'false') . '
});' . LF .
($autoSizeMax
? 'tree' . $id . '.bodyStyle = "max-height: ' . $autoSizeMax . 'px;min-height: ' . $height . 'px;";'
: 'tree' . $id . '.height = ' . $height . ';'
) . LF .
'window.setTimeout(function() {
tree' . $id . '.render("tree_' . $id . '");
}, 200);
});';
$resultArray['html'] = $html;
$javascript[] = ' this.rendering = false;';
$javascript[] = ' }';
$javascript[] = ' },';
$javascript[] = ' tcaMaxItems: ' . $maxItems . ',';
$javascript[] = ' tcaSelectRecursiveAllowed: ' . $allowRecursiveMode . ',';
$javascript[] = ' tcaSelectRecursive: false,';
$javascript[] = ' tcaExclusiveKeys: "' . $exclusiveKeys . '",';
$javascript[] = ' ucId: "' . md5(($table . '|' . $field)) . '",';
$javascript[] = ' selModel: TYPO3.Components.Tree.EmptySelectionModel,';
$javascript[] = ' disabled: ' . $disabled;
$javascript[] = ' });';
return $resultArray;
if ($autoSizeMax) {
$javascript[] = ' tree' . $formElementId . '.bodyStyle = "max-height: ' . $autoSizeMax . 'px;min-height: ' . $height . 'px;";';
} else {
$javascript[] = ' tree' . $formElementId . '.height = ' . $height . ';';
}
$javascript[] = ' window.setTimeout(function() {';
$javascript[] = ' tree' . $formElementId . '.render("tree_' . $formElementId . '");';
$javascript[] = ' }, 200);';
$javascript[] = '});';
return implode(LF, $javascript);
}
/**
......
......@@ -20,7 +20,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Resolve return Url if not set otherwise.
*/
class ReturnUrl extends AbstractItemProvider implements FormDataProviderInterface
class ReturnUrl implements FormDataProviderInterface
{
/**
* Add return unl
......
......@@ -23,7 +23,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*
* This is the first data provider in the chain of flex form related providers.
*/
class TcaFlexFetch extends AbstractItemProvider implements FormDataProviderInterface
class TcaFlexFetch implements FormDataProviderInterface
{
/**
* Resolve ds pointer stuff and parse both ds and dv
......
......@@ -23,7 +23,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*
* This data provider is typically executed directly after TcaFlexFetch
*/
class TcaFlexPrepare extends AbstractItemProvider implements FormDataProviderInterface
class TcaFlexPrepare implements FormDataProviderInterface
{
/**
* Resolve flex data structures and prepare flex data values.
......
......@@ -25,7 +25,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*
* This is typically the last provider, executed after TcaFlexPrepare
*/
class TcaFlexProcess extends AbstractItemProvider implements FormDataProviderInterface
class TcaFlexProcess implements FormDataProviderInterface
{
/**
* Determine possible pageTsConfig overrides and apply them to ds.
......
......@@ -21,7 +21,7 @@ use TYPO3\CMS\Core\Utility\MathUtility;
/**
* Set or initialize configuration for inline fields in TCA
*/
class TcaInlineConfiguration extends AbstractItemProvider implements FormDataProviderInterface
class TcaInlineConfiguration implements FormDataProviderInterface
{
/**
* Find all inline fields and force proper configuration
......
......@@ -21,7 +21,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
* Fetch information of user specific inline record expanded / collapsed state
* from user->uc and put it into $result['inlineExpandCollapseStateArray']
*/
class TcaInlineExpandCollapseState extends AbstractItemProvider implements FormDataProviderInterface
class TcaInlineExpandCollapseState implements FormDataProviderInterface
{
/**
* Add inline expand / collapse state
......
......@@ -20,13 +20,14 @@ use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
use TYPO3\CMS\Lang\LanguageService;
/**
* Resolve placeholders for fields of type input or text. The placeholder value
* in the processedTca section of the result will be replaced with the resolved
* value.
*/
class TcaInputPlaceholders extends AbstractItemProvider implements FormDataProviderInterface
class TcaInputPlaceholders implements FormDataProviderInterface
{
/**
* Resolve placeholders for input/text fields. Placeholders that are simple
......@@ -208,4 +209,12 @@ class TcaInputPlaceholders extends AbstractItemProvider implements FormDataProvi
return $allowedTable;
}
/**
* @return LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
}
<?php
namespace TYPO3\CMS\Backend\Form\FormDataProvider;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
use TYPO3\CMS\Core\Tree\TableConfiguration\ExtJsArrayTreeRenderer;
use TYPO3\CMS\Core\Tree\TableConfiguration\TableConfigurationTree;
use TYPO3\CMS\Core\Tree\TableConfiguration\TreeDataProviderFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Resolve select items, set processed item list in processedTca, sanitize and resolve database field
*/
class TcaSelectTreeItems extends AbstractItemProvider implements FormDataProviderInterface
{
/**
* Resolve select items
*
* @param array $result
* @return array
* @throws \UnexpectedValueException
*/
public function addData(array $result)
{
$table = $result['tableName'];
foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
if (empty($fieldConfig['config']['type']) || $fieldConfig['config']['type'] !== 'select') {
continue;
}
// Make sure we are only processing supported renderTypes
if ($fieldConfig['config']['renderType'] !== 'selectTree') {
continue;
}
$fieldConfig['config']['items'] = $this->sanitizeItemArray($fieldConfig['config']['items'], $table, $fieldName);
$fieldConfig['config']['maxitems'] = $this->sanitizeMaxItems($fieldConfig['config']['maxitems']);
$fieldConfig['config']['items'] = $this->addItemsFromPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
$fieldConfig['config']['items'] = $this->addItemsFromSpecial($result, $fieldName, $fieldConfig['config']['items']);
$fieldConfig['config']['items'] = $this->addItemsFromFolder($result, $fieldName, $fieldConfig['config']['items']);
$staticItems = $fieldConfig['config']['items'];
$fieldConfig['config']['items'] = $this->addItemsFromForeignTable($result, $fieldName, $fieldConfig['config']['items']);
$dynamicItems = array_diff_key($fieldConfig['config']['items'], $staticItems);
$fieldConfig['config']['items'] = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
$fieldConfig['config']['items'] = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
$fieldConfig['config']['items'] = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $fieldConfig['config']['items']);
$fieldConfig['config']['items'] = $this->removeItemsByUserAuthMode($result, $fieldName, $fieldConfig['config']['items']);
$fieldConfig['config']['items'] = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $fieldConfig['config']['items']);
// Resolve "itemsProcFunc"
if (!empty($fieldConfig['config']['itemsProcFunc'])) {
$fieldConfig['config']['items'] = $this->resolveItemProcessorFunction($result, $fieldName, $fieldConfig['config']['items']);
// itemsProcFunc must not be used anymore
unset($fieldConfig['config']['itemsProcFunc']);
}
// Translate labels
$fieldConfig['config']['items'] = $this->translateLabels($result, $fieldConfig['config']['items'], $table, $fieldName);
$staticValues = $this->getStaticValues($fieldConfig['config']['items'], $dynamicItems);
$result['databaseRow'][$fieldName] = $this->processSelectFieldValue($result, $fieldName, $staticValues);
// Keys may contain table names, so a numeric array is created
$fieldConfig['config']['items'] = array_values($fieldConfig['config']['items']);
$fieldConfig['config']['treeData'] = $this->renderTree($result, $fieldConfig, $fieldName, $staticItems);
$result['processedTca']['columns'][$fieldName] = $fieldConfig;
}
return $result;
}
/**
* Renders the Ext JS tree.
*
* @param array $result The current result array.
* @param array $fieldConfig The configuration of the current field.
* @param string $fieldName The name of the current field.
* @param array $staticItems The static items from the field config.
* @return array The tree data configuration
*/
protected function renderTree(array $result, array $fieldConfig, $fieldName, array $staticItems)
{
$allowedUids = [];
foreach ($fieldConfig['config']['items'] as $item) {
if ((int)$item[1] > 0) {
$allowedUids[] = $item[1];
}
}
$treeDataProvider = TreeDataProviderFactory::getDataProvider(
$fieldConfig['config'],
$result['tableName'],
$fieldName,
$result['databaseRow']
);
$treeDataProvider->setSelectedList(implode(',', $result['databaseRow'][$fieldName]));
$treeDataProvider->setItemWhiteList($allowedUids);
$treeDataProvider->initializeTreeData();
/** @var ExtJsArrayTreeRenderer $treeRenderer */