TYPO3 CMS  TYPO3_8-7
DatabaseIntegrityCheck.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 
35 {
39  public $genTree_includeDeleted = true;
40 
44  public $genTree_includeVersions = true;
45 
49  public $genTree_includeRecords = false;
50 
54  public $page_idArray = [];
55 
59  public $rec_idArray = [];
60 
64  public $checkFileRefs = [];
65 
69  public $checkSelectDBRefs = [];
70 
74  public $checkGroupDBRefs = [];
75 
79  public $recStats = [
80  'allValid' => [],
81  'published_versions' => [],
82  'deleted' => []
83  ];
84 
88  public $lRecords = [];
89 
93  public $lostPagesList = '';
94 
103  public function genTree($theID, $depthData = '', $versions = false)
104  {
105  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
106  $queryBuilder->getRestrictions()->removeAll();
107  if (!$this->genTree_includeDeleted) {
108  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
109  }
110  $queryBuilder->select('uid', 'title', 'doktype', 'deleted', 'hidden')
111  ->from('pages')
112  ->orderBy('sorting');
113  if ($versions) {
114  $queryBuilder->addSelect('t3ver_wsid', 't3ver_id', 't3ver_count');
115  $queryBuilder->where(
116  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
117  $queryBuilder->expr()->eq('t3ver_oid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
118  );
119  } else {
120  $queryBuilder->where(
121  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
122  );
123  }
124  $result = $queryBuilder->execute();
125  // Traverse the records selected
126  while ($row = $result->fetch()) {
127  $newID = $row['uid'];
128  // Register various data for this item:
129  $this->page_idArray[$newID] = $row;
130  $this->recStats['all_valid']['pages'][$newID] = $newID;
131  if ($row['deleted']) {
132  $this->recStats['deleted']['pages'][$newID] = $newID;
133  }
134  if ($versions && $row['t3ver_count'] >= 1) {
135  $this->recStats['published_versions']['pages'][$newID] = $newID;
136  }
137  if ($row['deleted']) {
138  $this->recStats['deleted']++;
139  }
140  if ($row['hidden']) {
141  $this->recStats['hidden']++;
142  }
143  $this->recStats['doktype'][$row['doktype']]++;
144  // If all records should be shown, do so:
145  if ($this->genTree_includeRecords) {
146  foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
147  if ($tableName !== 'pages') {
148  $this->genTree_records($newID, '', $tableName);
149  }
150  }
151  }
152  // Add sub pages:
153  $this->genTree($newID);
154  // If versions are included in the tree, add those now:
155  if ($this->genTree_includeVersions) {
156  $this->genTree($newID, '', true);
157  }
158  }
159  }
160 
167  public function genTree_records($theID, $_ = '', $table = '', $versions = false)
168  {
169  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
170  $queryBuilder->getRestrictions()->removeAll();
171  if (!$this->genTree_includeDeleted) {
172  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
173  }
174  $queryBuilder
175  ->select(...explode(',', BackendUtility::getCommonSelectFields($table)))
176  ->from($table);
177 
178  // Select all records from table pointing to this page
179  if ($versions) {
180  $queryBuilder->where(
181  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
182  $queryBuilder->expr()->eq('t3ver_oid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
183  );
184  } else {
185  $queryBuilder->where(
186  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
187  );
188  }
189  $queryResult = $queryBuilder->execute();
190  // Traverse selected
191  while ($row = $queryResult->fetch()) {
192  $newID = $row['uid'];
193  // Register various data for this item:
194  $this->rec_idArray[$table][$newID] = $row;
195  $this->recStats['all_valid'][$table][$newID] = $newID;
196  if ($row['deleted']) {
197  $this->recStats['deleted'][$table][$newID] = $newID;
198  }
199  if ($versions && $row['t3ver_count'] >= 1 && $row['t3ver_wsid'] == 0) {
200  $this->recStats['published_versions'][$table][$newID] = $newID;
201  }
202  // Select all versions of this record:
203  if ($this->genTree_includeVersions && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
204  $this->genTree_records($newID, '', $table, true);
205  }
206  }
207  }
208 
214  public function lostRecords($pid_list)
215  {
216  $this->lostPagesList = '';
217  $pageIds = GeneralUtility::intExplode(',', $pid_list);
218  if (is_array($pageIds)) {
219  foreach ($GLOBALS['TCA'] as $table => $tableConf) {
220  $pageIdsForTable = $pageIds;
221  // Remove preceding "-1," for non-versioned tables
223  $pageIdsForTable = array_combine($pageIdsForTable, $pageIdsForTable);
224  unset($pageIdsForTable[-1]);
225  }
226  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
227  $queryBuilder->getRestrictions()->removeAll();
228  $selectFields = ['uid', 'pid'];
229  if (!empty($GLOBALS['TCA'][$table]['ctrl']['label'])) {
230  $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['label'];
231  }
232  $queryResult = $queryBuilder->select(...$selectFields)
233  ->from($table)
234  ->where(
235  $queryBuilder->expr()->notIn(
236  'pid',
237  $queryBuilder->createNamedParameter($pageIdsForTable, Connection::PARAM_INT_ARRAY)
238  )
239  )
240  ->execute();
241  $lostIdList = [];
242  while ($row = $queryResult->fetch()) {
243  $this->lRecords[$table][$row['uid']] = [
244  'uid' => $row['uid'],
245  'pid' => $row['pid'],
246  'title' => strip_tags(BackendUtility::getRecordTitle($table, $row))
247  ];
248  $lostIdList[] = $row['uid'];
249  }
250  if ($table === 'pages') {
251  $this->lostPagesList = implode(',', $lostIdList);
252  }
253  }
254  }
255  }
256 
265  public function fixLostRecord($table, $uid)
266  {
267  if ($table && $GLOBALS['TCA'][$table] && $uid && is_array($this->lRecords[$table][$uid]) && $GLOBALS['BE_USER']->user['admin']) {
268  $updateFields = [
269  'pid' => 0
270  ];
271  // If possible a lost record restored is hidden as default
272  if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) {
273  $updateFields[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']] = 1;
274  }
275  GeneralUtility::makeInstance(ConnectionPool::class)
276  ->getConnectionForTable($table)
277  ->update($table, $updateFields, ['uid' => (int)$uid]);
278  return true;
279  }
280  return false;
281  }
282 
289  public function countRecords($pid_list)
290  {
291  $list = [];
292  $list_n = [];
293  $pageIds = GeneralUtility::intExplode(',', $pid_list);
294  if (!empty($pageIds)) {
295  foreach ($GLOBALS['TCA'] as $table => $tableConf) {
296  $pageIdsForTable = $pageIds;
297  // Remove preceding "-1," for non-versioned tables
299  $pageIdsForTable = array_combine($pageIdsForTable, $pageIdsForTable);
300  unset($pageIdsForTable[-1]);
301  }
302  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
303  $queryBuilder->getRestrictions()->removeAll();
304  $count = $queryBuilder->count('uid')
305  ->from($table)
306  ->where(
307  $queryBuilder->expr()->in(
308  'pid',
309  $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
310  )
311  )
312  ->execute()
313  ->fetchColumn(0);
314  if ($count) {
315  $list[$table] = $count;
316  }
317 
318  // same query excluding all deleted records
319  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
320  $queryBuilder->getRestrictions()
321  ->removeAll()
322  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
323  $count = $queryBuilder->count('uid')
324  ->from($table)
325  ->where(
326  $queryBuilder->expr()->in(
327  'pid',
328  $queryBuilder->createNamedParameter($pageIdsForTable, Connection::PARAM_INT_ARRAY)
329  )
330  )
331  ->execute()
332  ->fetchColumn(0);
333  if ($count) {
334  $list_n[$table] = $count;
335  }
336  }
337  }
338  return ['all' => $list, 'non_deleted' => $list_n];
339  }
340 
347  public function getGroupFields($mode)
348  {
349  $result = [];
350  foreach ($GLOBALS['TCA'] as $table => $tableConf) {
351  $cols = $GLOBALS['TCA'][$table]['columns'];
352  foreach ($cols as $field => $config) {
353  if ($config['config']['type'] === 'group') {
354  if ((!$mode || $mode === 'file') && $config['config']['internal_type'] === 'file' || (!$mode || $mode === 'db') && $config['config']['internal_type'] === 'db') {
355  $result[$table][] = $field;
356  }
357  }
358  if ((!$mode || $mode === 'db') && $config['config']['type'] === 'select' && $config['config']['foreign_table']) {
359  $result[$table][] = $field;
360  }
361  }
362  if ($result[$table]) {
363  $result[$table] = implode(',', $result[$table]);
364  }
365  }
366  return $result;
367  }
368 
375  public function getFileFields($uploadfolder)
376  {
377  $result = [];
378  foreach ($GLOBALS['TCA'] as $table => $tableConf) {
379  $cols = $GLOBALS['TCA'][$table]['columns'];
380  foreach ($cols as $field => $config) {
381  if ($config['config']['type'] === 'group' && $config['config']['internal_type'] === 'file' && $config['config']['uploadfolder'] == $uploadfolder) {
382  $result[] = [$table, $field];
383  }
384  }
385  }
386  return $result;
387  }
388 
395  public function getDBFields($theSearchTable)
396  {
397  $result = [];
398  foreach ($GLOBALS['TCA'] as $table => $tableConf) {
399  $cols = $GLOBALS['TCA'][$table]['columns'];
400  foreach ($cols as $field => $config) {
401  if ($config['config']['type'] === 'group' && $config['config']['internal_type'] === 'db') {
402  if (trim($config['config']['allowed']) === '*' || strstr($config['config']['allowed'], $theSearchTable)) {
403  $result[] = [$table, $field];
404  }
405  } elseif ($config['config']['type'] === 'select' && $config['config']['foreign_table'] == $theSearchTable) {
406  $result[] = [$table, $field];
407  }
408  }
409  }
410  return $result;
411  }
412 
419  public function selectNonEmptyRecordsWithFkeys($fkey_arrays)
420  {
421  if (is_array($fkey_arrays)) {
422  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
423  foreach ($fkey_arrays as $table => $field_list) {
424  if ($GLOBALS['TCA'][$table] && trim($field_list)) {
425  $connection = $connectionPool->getConnectionForTable($table);
426  $schemaManager = $connection->getSchemaManager();
427  $tableColumns = $schemaManager->listTableColumns($table);
428 
429  $queryBuilder = $connectionPool->getQueryBuilderForTable($table);
430  $queryBuilder->getRestrictions()->removeAll();
431 
432  $fields = GeneralUtility::trimExplode(',', $field_list, true);
433 
434  $queryBuilder->select('uid')
435  ->from($table);
436  $whereClause = [];
437 
438  foreach ($fields as $fieldName) {
439  // The array index of $tableColumns is the lowercased column name!
440  // It is quoted for keywords
441  $column = $tableColumns[strtolower($fieldName)]
442  ?? $tableColumns[$connection->quoteIdentifier(strtolower($fieldName))];
443  if (!$column) {
444  // Throw meaningful exception if field does not exist in DB - 'none' is not filtered here since the
445  // method is only called with type=group fields
446  throw new \RuntimeException(
447  'Field ' . $fieldName . ' for table ' . $table . ' has been defined in TCA, but does not exist in DB',
448  1536248936
449  );
450  }
451  $fieldType = $column->getType()->getName();
452  if (in_array(
453  $fieldType,
454  [Type::BIGINT, Type::INTEGER, Type::SMALLINT, Type::DECIMAL, Type::FLOAT],
455  true
456  )) {
457  $whereClause[] = $queryBuilder->expr()->andX(
458  $queryBuilder->expr()->isNotNull($fieldName),
459  $queryBuilder->expr()->neq(
460  $fieldName,
461  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
462  )
463  );
464  } elseif (in_array($fieldType, [Type::STRING, Type::TEXT], true)) {
465  $whereClause[] = $queryBuilder->expr()->andX(
466  $queryBuilder->expr()->isNotNull($fieldName),
467  $queryBuilder->expr()->neq(
468  $fieldName,
469  $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
470  )
471  );
472  } elseif (in_array($fieldType, [Type::BLOB], true)) {
473  $whereClause[] = $queryBuilder->expr()->andX(
474  $queryBuilder->expr()->isNotNull($fieldName),
475  $queryBuilder->expr()
476  ->comparison(
477  $queryBuilder->expr()->length($fieldName),
479  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
480  )
481  );
482  }
483  }
484  $queryResult = $queryBuilder->orWhere(...$whereClause)->execute();
485 
486  while ($row = $queryResult->fetch()) {
487  foreach ($fields as $field) {
488  if (trim($row[$field])) {
489  $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
490  if ($fieldConf['type'] === 'group') {
491  if ($fieldConf['internal_type'] === 'file') {
492  // Files...
493  if ($fieldConf['MM']) {
494  $tempArr = [];
495  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
496  $dbAnalysis->start('', 'files', $fieldConf['MM'], $row['uid']);
497  foreach ($dbAnalysis->itemArray as $somekey => $someval) {
498  if ($someval['id']) {
499  $tempArr[] = $someval['id'];
500  }
501  }
502  } else {
503  $tempArr = explode(',', trim($row[$field]));
504  }
505  foreach ($tempArr as $file) {
506  $file = trim($file);
507  if ($file) {
508  $this->checkFileRefs[$fieldConf['uploadfolder']][$file] += 1;
509  }
510  }
511  }
512  if ($fieldConf['internal_type'] === 'db') {
513  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
514  $dbAnalysis->start(
515  $row[$field],
516  $fieldConf['allowed'],
517  $fieldConf['MM'],
518  $row['uid'],
519  $table,
520  $fieldConf
521  );
522  foreach ($dbAnalysis->itemArray as $tempArr) {
523  $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1;
524  }
525  }
526  }
527  if ($fieldConf['type'] === 'select' && $fieldConf['foreign_table']) {
528  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
529  $dbAnalysis->start(
530  $row[$field],
531  $fieldConf['foreign_table'],
532  $fieldConf['MM'],
533  $row['uid'],
534  $table,
535  $fieldConf
536  );
537  foreach ($dbAnalysis->itemArray as $tempArr) {
538  if ($tempArr['id'] > 0) {
539  $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1;
540  }
541  }
542  }
543  }
544  }
545  }
546  }
547  }
548  }
549  }
550 
556  public function testFileRefs()
557  {
558  $output = [];
559  // Handle direct references with upload folder setting (workaround)
560  $newCheckFileRefs = [];
561  foreach ($this->checkFileRefs as $folder => $files) {
562  // Only direct references without a folder setting
563  if ($folder !== '') {
564  $newCheckFileRefs[$folder] = $files;
565  continue;
566  }
567  foreach ($files as $file => $references) {
568  // Direct file references have often many references (removes occurrences in the moreReferences section of the result array)
569  if ($references > 1) {
570  $references = 1;
571  }
572  // The directory must be empty (prevents checking of the root directory)
573  $directory = dirname($file);
574  if ($directory !== '') {
575  $newCheckFileRefs[$directory][basename($file)] = $references;
576  }
577  }
578  }
579  $this->checkFileRefs = $newCheckFileRefs;
580  foreach ($this->checkFileRefs as $folder => $fileArr) {
581  $path = PATH_site . $folder;
582  if (@is_dir($path) && @is_readable($path)) {
583  $d = dir($path);
584  while ($entry = $d->read()) {
585  if (@is_file(($path . '/' . $entry))) {
586  if (isset($fileArr[$entry])) {
587  if ($fileArr[$entry] > 1) {
588  $temp = $this->whereIsFileReferenced($folder, $entry);
589  $tempList = '';
590  foreach ($temp as $inf) {
591  $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
592  }
593  $output['moreReferences'][] = [$path, $entry, $fileArr[$entry], $tempList];
594  }
595  unset($fileArr[$entry]);
596  } else {
597  // Contains workaround for direct references
598  if (!strstr($entry, 'index.htm') && !preg_match(('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/'), $folder)) {
599  $output['noReferences'][] = [$path, $entry];
600  }
601  }
602  }
603  }
604  $d->close();
605  $tempCounter = 0;
606  foreach ($fileArr as $file => $value) {
607  // Workaround for direct file references
608  if (preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
609  $file = $folder . '/' . $file;
610  $folder = '';
611  $path = substr(PATH_site, 0, -1);
612  }
613  $temp = $this->whereIsFileReferenced($folder, $file);
614  $tempList = '';
615  foreach ($temp as $inf) {
616  $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
617  }
618  $tempCounter++;
619  $output['noFile'][substr($path, -3) . '_' . substr($file, 0, 3) . '_' . $tempCounter] = [$path, $file, $tempList];
620  }
621  } else {
622  $output['error'][] = [$path];
623  }
624  }
625  return $output;
626  }
627 
634  public function testDBRefs($theArray)
635  {
636  $result = '';
637  foreach ($theArray as $table => $dbArr) {
638  if ($GLOBALS['TCA'][$table]) {
639  $ids = array_keys($dbArr);
640  if (!empty($ids)) {
641  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
642  ->getQueryBuilderForTable($table);
643  $queryBuilder->getRestrictions()
644  ->removeAll()
645  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
646  $queryResult = $queryBuilder
647  ->select('uid')
648  ->from($table)
649  ->where(
650  $queryBuilder->expr()->in(
651  'uid',
652  $queryBuilder->createNamedParameter($ids, Connection::PARAM_INT_ARRAY)
653  )
654  )
655  ->execute();
656  while ($row = $queryResult->fetch()) {
657  if (isset($dbArr[$row['uid']])) {
658  unset($dbArr[$row['uid']]);
659  } else {
660  $result .= 'Strange Error. ...<br />';
661  }
662  }
663  foreach ($dbArr as $theId => $theC) {
664  $result .= 'There are ' . $theC . ' records pointing to this missing or deleted record; [' . $table . '][' . $theId . ']<br />';
665  }
666  }
667  } else {
668  $result .= 'Codeerror. Table is not a table...<br />';
669  }
670  }
671  return $result;
672  }
673 
681  public function whereIsRecordReferenced($searchTable, $id)
682  {
683  // Gets tables / Fields that reference to files
684  $fileFields = $this->getDBFields($searchTable);
685  $theRecordList = [];
686  foreach ($fileFields as $info) {
687  list($table, $field) = $info;
688  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
689  $queryBuilder->getRestrictions()->removeAll();
690  $queryResult = $queryBuilder
691  ->select('uid', 'pid', $GLOBALS['TCA'][$table]['ctrl']['label'], $field)
692  ->from($table)
693  ->where(
694  $queryBuilder->expr()->like(
695  $field,
696  $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($id) . '%')
697  )
698  )
699  ->execute();
700 
701  while ($row = $queryResult->fetch()) {
702  // Now this is the field, where the reference COULD come from.
703  // But we're not guaranteed, so we must carefully examine the data.
704  $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
705  $allowedTables = $fieldConf['type'] === 'group' ? $fieldConf['allowed'] : $fieldConf['foreign_table'];
706  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
707  $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf);
708  foreach ($dbAnalysis->itemArray as $tempArr) {
709  if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) {
710  $theRecordList[] = [
711  'table' => $table,
712  'uid' => $row['uid'],
713  'field' => $field,
714  'pid' => $row['pid']
715  ];
716  }
717  }
718  }
719  }
720  return $theRecordList;
721  }
722 
730  public function whereIsFileReferenced($uploadFolder, $filename)
731  {
732  // Gets tables / Fields that reference to files
733  $fileFields = $this->getFileFields($uploadFolder);
734  $theRecordList = [];
735  foreach ($fileFields as $info) {
736  list($table, $field) = $info;
737  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
738  $queryBuilder->getRestrictions()->removeAll();
739  $queryResult = $queryBuilder
740  ->select('uid', 'pid', $GLOBALS['TCA'][$table]['ctrl']['label'], $field)
741  ->from($table)
742  ->where(
743  $queryBuilder->expr()->like(
744  $field,
745  $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($filename) . '%')
746  )
747  )
748  ->execute();
749  while ($row = $queryResult->fetch()) {
750  // Now this is the field, where the reference COULD come from.
751  // But we're not guaranteed, so we must carefully examine the data.
752  $tempArr = explode(',', trim($row[$field]));
753  foreach ($tempArr as $file) {
754  $file = trim($file);
755  if ($file == $filename) {
756  $theRecordList[] = [
757  'table' => $table,
758  'uid' => $row['uid'],
759  'field' => $field,
760  'pid' => $row['pid']
761  ];
762  }
763  }
764  }
765  }
766  return $theRecordList;
767  }
768 }
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
genTree_records($theID, $_='', $table='', $versions=false)
static getCommonSelectFields($table, $prefix='', $fields=[])
genTree($theID, $depthData='', $versions=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static makeInstance($className,... $constructorArguments)
$fields
Definition: pages.php:4
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']