‪TYPO3CMS  9.5
SuggestWizardController.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
26 
32 {
40  public function ‪searchAction(ServerRequestInterface $request): ResponseInterface
41  {
42  $parsedBody = $request->getParsedBody();
43 
44  $search = $parsedBody['value'] ?? null;
45  $tableName = $parsedBody['tableName'] ?? null;
46  $fieldName = $parsedBody['fieldName'] ?? null;
47  $uid = $parsedBody['uid'] ?? null;
48  $pid = isset($parsedBody['pid']) ? (int)$parsedBody['pid'] : 0;
49  $dataStructureIdentifier = '' ?? null;
50  if (!empty($parsedBody['dataStructureIdentifier'])) {
51  $dataStructureIdentifier = $parsedBody['dataStructureIdentifier'];
52  }
53  $flexFormSheetName = $parsedBody['flexFormSheetName'] ?? null;
54  $flexFormFieldName = $parsedBody['flexFormFieldName'] ?? null;
55  $flexFormContainerName = $parsedBody['flexFormContainerName'] ?? null;
56  $flexFormContainerFieldName = $parsedBody['flexFormContainerFieldName'] ?? null;
57 
58  // Determine TCA config of field
59  if (empty($dataStructureIdentifier)) {
60  // Normal columns field
61  $fieldConfig = ‪$GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'];
62  $fieldNameInPageTsConfig = $fieldName;
63  } else {
64  // A flex flex form field
65  $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
66  $dataStructure = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
67  if (empty($flexFormContainerFieldName)) {
68  // @todo: See if a path in pageTsConfig like "TCEForm.tableName.theContainerFieldName =" is useful and works with other pageTs, too.
69  $fieldNameInPageTsConfig = $flexFormFieldName;
70  if (!isset($dataStructure['sheets'][$flexFormSheetName]['ROOT']
71  ['el'][$flexFormFieldName]['TCEforms']['config'])
72  ) {
73  throw new \RuntimeException(
74  'Specified path ' . $flexFormFieldName . ' not found in flex form data structure',
75  1480609491
76  );
77  }
78  $fieldConfig = $dataStructure['sheets'][$flexFormSheetName]['ROOT']
79  ['el'][$flexFormFieldName]['TCEforms']['config'];
80  } else {
81  $fieldNameInPageTsConfig = $flexFormContainerFieldName;
82  if (!isset($dataStructure['sheets'][$flexFormSheetName]['ROOT']
83  ['el'][$flexFormFieldName]
84  ['el'][$flexFormContainerName]
85  ['el'][$flexFormContainerFieldName]['TCEforms']['config'])
86  ) {
87  throw new \RuntimeException(
88  'Specified path ' . $flexFormContainerName . ' not found in flex form section container data structure',
89  1480611208
90  );
91  }
92  $fieldConfig = $dataStructure['sheets'][$flexFormSheetName]['ROOT']
93  ['el'][$flexFormFieldName]
94  ['el'][$flexFormContainerName]
95  ['el'][$flexFormContainerFieldName]['TCEforms']['config'];
96  }
97  }
98 
99  $pageTsConfig = ‪BackendUtility::getPagesTSconfig($pid);
100 
101  $wizardConfig = $fieldConfig['suggestOptions'] ?? [];
102 
103  $queryTables = $this->‪getTablesToQueryFromFieldConfiguration($fieldConfig);
104  $whereClause = $this->‪getWhereClause($fieldConfig);
105 
106  $resultRows = [];
107 
108  // fetch the records for each query table. A query table is a table from which records are allowed to
109  // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA
110  foreach ($queryTables as $queryTable) {
111  // if the table does not exist, skip it
112  if (!is_array(‪$GLOBALS['TCA'][$queryTable]) || empty(‪$GLOBALS['TCA'][$queryTable])) {
113  continue;
114  }
115 
116  $config = $this->‪getConfigurationForTable($queryTable, $wizardConfig, $pageTsConfig, $tableName, $fieldNameInPageTsConfig);
117 
118  // process addWhere
119  if (!isset($config['addWhere']) && $whereClause) {
120  $config['addWhere'] = $whereClause;
121  }
122  if (isset($config['addWhere'])) {
123  $replacement = [
124  '###THIS_UID###' => (int)$uid,
125  '###CURRENT_PID###' => (int)$pid
126  ];
127  if (isset($pageTsConfig['TCEFORM.'][$tableName . '.'][$fieldNameInPageTsConfig . '.'])) {
128  $fieldTSconfig = $pageTsConfig['TCEFORM.'][$tableName . '.'][$fieldNameInPageTsConfig . '.'];
129  if (isset($fieldTSconfig['PAGE_TSCONFIG_ID'])) {
130  $replacement['###PAGE_TSCONFIG_ID###'] = (int)$fieldTSconfig['PAGE_TSCONFIG_ID'];
131  }
132  if (isset($fieldTSconfig['PAGE_TSCONFIG_IDLIST'])) {
133  $replacement['###PAGE_TSCONFIG_IDLIST###'] = implode(',', GeneralUtility::intExplode(',', $fieldTSconfig['PAGE_TSCONFIG_IDLIST']));
134  }
135  if (isset($fieldTSconfig['PAGE_TSCONFIG_STR'])) {
136  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($fieldConfig['foreign_table']);
137  // nasty hack, but it's currently not possible to just quote anything "inside" the value but not escaping
138  // the whole field as it is not known where it is used in the WHERE clause
139  $replacement['###PAGE_TSCONFIG_STR###'] = trim($connection->quote($fieldTSconfig['PAGE_TSCONFIG_STR']), '\'');
140  }
141  }
142  $config['addWhere'] = strtr(' ' . $config['addWhere'], $replacement);
143  }
144 
145  // instantiate the class that should fetch the records for this $queryTable
146  $receiverClassName = $config['receiverClass'];
147  if (!class_exists($receiverClassName)) {
148  $receiverClassName = SuggestWizardDefaultReceiver::class;
149  }
150  $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
151  $params = [
152  'value' => $search,
153  'uid' => $uid,
154  ];
155  $rows = $receiverObj->queryTable($params);
156  if (empty($rows)) {
157  continue;
158  }
159  $resultRows = $rows + $resultRows;
160  unset($rows);
161  }
162 
163  // Limit the number of items in the result list
164  $maxItems = $config['maxItemsInResultList'] ?? 10;
165  $maxItems = min(count($resultRows), $maxItems);
166 
167  array_splice($resultRows, $maxItems);
168  return (new ‪JsonResponse())->setPayload(array_values($resultRows));
169  }
170 
177  protected function ‪isTableHidden(array $tableConfig)
178  {
179  return (bool)$tableConfig['ctrl']['hideTable'];
180  }
181 
189  protected function ‪currentBackendUserMayAccessTable(array $tableConfig)
190  {
191  if ($this->‪getBackendUser()->isAdmin()) {
192  return true;
193  }
194 
195  // If the user is no admin, they may not access admin-only tables
196  if ($tableConfig['ctrl']['adminOnly']) {
197  return false;
198  }
199 
200  // allow access to root level pages if security restrictions should be bypassed
201  return !$tableConfig['ctrl']['rootLevel'] || $tableConfig['ctrl']['security']['ignoreRootLevelRestriction'];
202  }
203 
215  protected function ‪getConfigurationForTable($queryTable, array $wizardConfig, array $TSconfig, $table, $field)
216  {
217  $config = (array)$wizardConfig['default'];
218 
219  if (is_array($wizardConfig[$queryTable])) {
220  ‪ArrayUtility::mergeRecursiveWithOverrule($config, $wizardConfig[$queryTable]);
221  }
222  $globalSuggestTsConfig = $TSconfig['TCEFORM.']['suggest.'];
223  $currentFieldSuggestTsConfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'];
224 
225  // merge the configurations of different "levels" to get the working configuration for this table and
226  // field (i.e., go from the most general to the most special configuration)
227  if (is_array($globalSuggestTsConfig['default.'])) {
228  ‪ArrayUtility::mergeRecursiveWithOverrule($config, $globalSuggestTsConfig['default.']);
229  }
230 
231  if (is_array($globalSuggestTsConfig[$queryTable . '.'])) {
232  ‪ArrayUtility::mergeRecursiveWithOverrule($config, $globalSuggestTsConfig[$queryTable . '.']);
233  }
234 
235  // use $table instead of $queryTable here because we overlay a config
236  // for the input-field here, not for the queried table
237  if (is_array($currentFieldSuggestTsConfig['default.'])) {
238  ‪ArrayUtility::mergeRecursiveWithOverrule($config, $currentFieldSuggestTsConfig['default.']);
239  }
240 
241  if (is_array($currentFieldSuggestTsConfig[$queryTable . '.'])) {
242  ‪ArrayUtility::mergeRecursiveWithOverrule($config, $currentFieldSuggestTsConfig[$queryTable . '.']);
243  }
244 
245  return $config;
246  }
247 
255  protected function ‪getTablesToQueryFromFieldConfiguration(array $fieldConfig)
256  {
257  $queryTables = [];
258 
259  if (isset($fieldConfig['allowed'])) {
260  if ($fieldConfig['allowed'] !== '*') {
261  // list of allowed tables
262  $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
263  } else {
264  // all tables are allowed, if the user can access them
265  foreach (‪$GLOBALS['TCA'] as $tableName => $tableConfig) {
266  if (!$this->‪isTableHidden($tableConfig) && $this->‪currentBackendUserMayAccessTable($tableConfig)) {
267  $queryTables[] = $tableName;
268  }
269  }
270  unset($tableName, $tableConfig);
271  }
272  } elseif (isset($fieldConfig['foreign_table'])) {
273  // use the foreign table
274  $queryTables = [$fieldConfig['foreign_table']];
275  }
276 
277  return $queryTables;
278  }
279 
288  protected function ‪getWhereClause(array $fieldConfig)
289  {
290  if (!isset($fieldConfig['foreign_table'])) {
291  return '';
292  }
293 
294  // strip ORDER BY clause
295  return trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $fieldConfig['foreign_table_where']));
296  }
297 
301  protected function ‪getBackendUser()
302  {
303  return ‪$GLOBALS['BE_USER'];
304  }
305 }
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\getWhereClause
‪string getWhereClause(array $fieldConfig)
Definition: SuggestWizardController.php:288
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\getBackendUser
‪TYPO3 CMS Core Authentication BackendUserAuthentication getBackendUser()
Definition: SuggestWizardController.php:301
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:614
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\currentBackendUserMayAccessTable
‪bool currentBackendUserMayAccessTable(array $tableConfig)
Definition: SuggestWizardController.php:189
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\getTablesToQueryFromFieldConfiguration
‪array getTablesToQueryFromFieldConfiguration(array $fieldConfig)
Definition: SuggestWizardController.php:255
‪TYPO3\CMS\Backend\Controller\Wizard
Definition: AbstractWizardController.php:2
‪TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools
Definition: FlexFormTools.php:36
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\searchAction
‪ResponseInterface searchAction(ServerRequestInterface $request)
Definition: SuggestWizardController.php:40
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:72
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\isTableHidden
‪bool isTableHidden(array $tableConfig)
Definition: SuggestWizardController.php:177
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController
Definition: SuggestWizardController.php:32
‪TYPO3\CMS\Backend\Utility\BackendUtility\getPagesTSconfig
‪static array getPagesTSconfig($id, $rootLine=null, $returnPartArray=false)
Definition: BackendUtility.php:864
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:25
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController\getConfigurationForTable
‪array getConfigurationForTable($queryTable, array $wizardConfig, array $TSconfig, $table, $field)
Definition: SuggestWizardController.php:215
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver
Definition: SuggestWizardDefaultReceiver.php:38