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