TYPO3 CMS  TYPO3_7-6
AbstractDatabaseRecordList.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 
32 
39 {
45  public $tableList = '';
46 
52  public $returnUrl = '';
53 
59  public $thumbs = 0;
60 
66  public $itemsLimitPerTable = 20;
67 
73  public $itemsLimitSingleTable = 100;
74 
80  public $script = 'index.php';
81 
87  public $allFields = 0;
88 
94  public $localizationView = false;
95 
101  public $csvOutput = false;
102 
108  public $sortField;
109 
115  public $sortRev;
116 
123 
130 
136  public $id;
137 
143  public $table = '';
144 
151 
158 
164  public $searchString = '';
165 
171  public $searchLevels = '';
172 
178  public $showLimit = 0;
179 
186  public $pidSelect = '';
187 
193  public $perms_clause = '';
194 
200  public $calcPerms = 0;
201 
207  public $clickTitleMode = '';
208 
214  public $modSharedTSconfig = [];
215 
221  public $pageRecord = [];
222 
228  public $hideTables = '';
229 
235  public $hideTranslations = '';
236 
243 
249  public $tablesCollapsed = [];
250 
256  public $JScode = '';
257 
263  public $HTMLcode = '';
264 
270  public $iLimit = 0;
271 
277  public $eCounter = 0;
278 
284  public $totalItems = '';
285 
291  public $recPath_cache = [];
292 
298  public $setFields = [];
299 
305  public $currentTable = [];
306 
312  public $duplicateStack = [];
313 
317  public $modTSconfig;
318 
323  protected $overrideUrlParameters = [];
324 
334  protected $tableDisplayOrder = [];
335 
347  public function start($id, $table, $pointer, $search = '', $levels = 0, $showLimit = 0)
348  {
349  $backendUser = $this->getBackendUserAuthentication();
350  $db = $this->getDatabaseConnection();
351  // Setting internal variables:
352  // sets the parent id
353  $this->id = (int)$id;
354  if ($GLOBALS['TCA'][$table]) {
355  // Setting single table mode, if table exists:
356  $this->table = $table;
357  }
358  $this->firstElementNumber = $pointer;
359  $this->searchString = trim($search);
360  $this->searchLevels = (int)$levels;
361  $this->showLimit = MathUtility::forceIntegerInRange($showLimit, 0, 10000);
362  // Setting GPvars:
363  $this->csvOutput = (bool)GeneralUtility::_GP('csv');
364  $this->sortField = GeneralUtility::_GP('sortField');
365  $this->sortRev = GeneralUtility::_GP('sortRev');
366  $this->displayFields = GeneralUtility::_GP('displayFields');
367  $this->duplicateField = GeneralUtility::_GP('duplicateField');
368  if (GeneralUtility::_GP('justLocalized')) {
369  $this->localizationRedirect(GeneralUtility::_GP('justLocalized'));
370  }
371  // Init dynamic vars:
372  $this->counter = 0;
373  $this->JScode = '';
374  $this->HTMLcode = '';
375  // Limits
376  if (isset($this->modTSconfig['properties']['itemsLimitPerTable'])) {
377  $this->itemsLimitPerTable = MathUtility::forceIntegerInRange((int)$this->modTSconfig['properties']['itemsLimitPerTable'], 1, 10000);
378  }
379  if (isset($this->modTSconfig['properties']['itemsLimitSingleTable'])) {
380  $this->itemsLimitSingleTable = MathUtility::forceIntegerInRange((int)$this->modTSconfig['properties']['itemsLimitSingleTable'], 1, 10000);
381  }
382  // Set search levels:
384  $this->perms_clause = $backendUser->getPagePermsClause(1);
385  // This will hide records from display - it has nothing to do with user rights!!
386  if ($pidList = $backendUser->getTSConfigVal('options.hideRecords.pages')) {
387  if ($pidList = $db->cleanIntList($pidList)) {
388  $this->perms_clause .= ' AND pages.uid NOT IN (' . $pidList . ')';
389  }
390  }
391  // Get configuration of collapsed tables from user uc and merge with sanitized GP vars
392  $this->tablesCollapsed = is_array($backendUser->uc['moduleData']['list']) ? $backendUser->uc['moduleData']['list'] : [];
393  $collapseOverride = GeneralUtility::_GP('collapse');
394  if (is_array($collapseOverride)) {
395  foreach ($collapseOverride as $collapseTable => $collapseValue) {
396  if (is_array($GLOBALS['TCA'][$collapseTable]) && ($collapseValue == 0 || $collapseValue == 1)) {
397  $this->tablesCollapsed[$collapseTable] = $collapseValue;
398  }
399  }
400  // Save modified user uc
401  $backendUser->uc['moduleData']['list'] = $this->tablesCollapsed;
402  $backendUser->writeUC($backendUser->uc);
404  if ($returnUrl !== '') {
405  HttpUtility::redirect($returnUrl);
406  }
407  }
408  if ($searchLevels > 0) {
409  $allowedMounts = $this->getSearchableWebmounts($this->id, $searchLevels, $this->perms_clause);
410  $pidList = implode(',', $db->cleanIntArray($allowedMounts));
411  $this->pidSelect = 'pid IN (' . $pidList . ')';
412  } elseif ($searchLevels < 0) {
413  // Search everywhere
414  $this->pidSelect = '1=1';
415  } else {
416  $this->pidSelect = 'pid=' . (int)$id;
417  }
418  // Initialize languages:
419  if ($this->localizationView) {
420  $this->initializeLanguages();
421  }
422  }
423 
431  public function generateList()
432  {
433  // Set page record in header
434  $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id);
435  $hideTablesArray = GeneralUtility::trimExplode(',', $this->hideTables);
436 
437  $backendUser = $this->getBackendUserAuthentication();
438 
439  // pre-process tables and add sorting instructions
440  $tableNames = array_flip(array_keys($GLOBALS['TCA']));
441  foreach ($tableNames as $tableName => &$config) {
442  $hideTable = false;
443 
444  // Checking if the table should be rendered:
445  // Checks that we see only permitted/requested tables:
446  if ($this->table && $tableName !== $this->table
447  || $this->tableList && !GeneralUtility::inList($this->tableList, $tableName)
448  || !$backendUser->check('tables_select', $tableName)
449  ) {
450  $hideTable = true;
451  }
452 
453  if (!$hideTable) {
454  // Don't show table if hidden by TCA ctrl section
455  // Don't show table if hidden by pageTSconfig mod.web_list.hideTables
456  $hideTable = $hideTable || !empty($GLOBALS['TCA'][$tableName]['ctrl']['hideTable']) || in_array($tableName, $hideTablesArray, true);
457  // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table
458  if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) {
459  $hideTable = (bool)$this->tableTSconfigOverTCA[$tableName . '.']['hideTable'];
460  }
461  }
462  if ($hideTable) {
463  unset($tableNames[$tableName]);
464  } else {
465  if (isset($this->tableDisplayOrder[$tableName])) {
466  // Copy display order information
467  $tableNames[$tableName] = $this->tableDisplayOrder[$tableName];
468  } else {
469  $tableNames[$tableName] = [];
470  }
471  }
472  }
473  unset($config);
474 
475  $orderedTableNames = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($tableNames);
476 
477  $db = $this->getDatabaseConnection();
478  foreach ($orderedTableNames as $tableName => $_) {
479  // check if we are in single- or multi-table mode
480  if ($this->table) {
481  $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']) ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems'] : $this->itemsLimitSingleTable;
482  } else {
483  // if there are no records in table continue current foreach
484  $firstRow = $db->exec_SELECTgetSingleRow(
485  'uid',
486  $tableName,
487  $this->pidSelect . BackendUtility::deleteClause($tableName) . BackendUtility::versioningPlaceholderClause($tableName)
488  );
489  if ($firstRow === false) {
490  continue;
491  }
492  $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']) ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems'] : $this->itemsLimitPerTable;
493  }
494  if ($this->showLimit) {
495  $this->iLimit = $this->showLimit;
496  }
497  // Setting fields to select:
498  if ($this->allFields) {
499  $fields = $this->makeFieldList($tableName);
500  $fields[] = 'tstamp';
501  $fields[] = 'crdate';
502  $fields[] = '_PATH_';
503  $fields[] = '_CONTROL_';
504  if (is_array($this->setFields[$tableName])) {
505  $fields = array_intersect($fields, $this->setFields[$tableName]);
506  } else {
507  $fields = [];
508  }
509  } else {
510  $fields = [];
511  }
512  // Find ID to use (might be different for "versioning_followPages" tables)
513  if ($this->searchLevels === 0) {
514  $this->pidSelect = 'pid=' . (int)$this->id;
515  }
516  // Finally, render the list:
517  $this->HTMLcode .= $this->getTable($tableName, $this->id, implode(',', $fields));
518  }
519  }
520 
529  public function getTable($tableName, $id, $fields = '')
530  {
531  return '';
532  }
533 
540  public function getSearchBox($formFields = true)
541  {
543  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
544  $lang = $this->getLanguageService();
545  // Setting form-elements, if applicable:
546  $formElements = ['', ''];
547  if ($formFields) {
548  $formElements = ['<form action="' . htmlspecialchars($this->listURL('', '-1', 'firstElementNumber,search_field')) . '" method="post">', '</form>'];
549  }
550  // Make level selector:
551  $opt = [];
552  $parts = explode('|', $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchLevels'));
553  foreach ($parts as $kv => $label) {
554  $opt[] = '<option value="' . $kv . '"' . ($kv === $this->searchLevels ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
555  }
556  $lMenu = '<select class="form-control" name="search_levels" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.title.search_levels', true) . '" id="search_levels">' . implode('', $opt) . '</select>';
557  // Table with the search box:
558  $content = '<div class="db_list-searchbox-form db_list-searchbox-toolbar module-docheader-bar module-docheader-bar-search t3js-module-docheader-bar t3js-module-docheader-bar-search" id="db_list-searchbox-toolbar" style="display: ' . ($this->searchString == '' ? 'none' : 'block') . ';">
559  ' . $formElements[0] . '
560  <div id="typo3-dblist-search">
561  <div class="panel panel-default">
562  <div class="panel-body">
563  <div class="form-inline form-inline-spaced">
564  <div class="form-group">
565  <input class="form-control" type="search" placeholder="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchString', true) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.title.searchString', true) . '" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '" />
566  </div>
567  <div class="form-group">
568  <label for="search_levels">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.label.search_levels', true) . ': </label>
569  ' . $lMenu . '
570  </div>
571  <div class="form-group">
572  <label for="showLimit">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.label.limit', true) . ': </label>
573  <input class="form-control" type="number" min="0" max="10000" placeholder="10" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.title.limit', true) . '" name="showLimit" id="showLimit" value="' . htmlspecialchars(($this->showLimit ? $this->showLimit : '')) . '" />
574  </div>
575  <div class="form-group">
576  <button type="submit" class="btn btn-default" name="search" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.title.search', true) . '">
577  ' . $iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render() . ' ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.search', true) . '
578  </button>
579  </div>
580  </div>
581  </div>
582  </div>
583  </div>
584  ' . $formElements[1] . '</div>';
585  return $content;
586  }
587 
588  /******************************
589  *
590  * Various helper functions
591  *
592  ******************************/
599  public function setDispFields()
600  {
601  $backendUser = $this->getBackendUserAuthentication();
602  // Getting from session:
603  $dispFields = $backendUser->getModuleData('list/displayFields');
604  // If fields has been inputted, then set those as the value and push it to session variable:
605  if (is_array($this->displayFields)) {
606  reset($this->displayFields);
607  $tKey = key($this->displayFields);
608  $dispFields[$tKey] = $this->displayFields[$tKey];
609  $backendUser->pushModuleData('list/displayFields', $dispFields);
610  }
611  // Setting result:
612  $this->setFields = $dispFields;
613  }
614 
623  public function thumbCode($row, $table, $field)
624  {
625  return BackendUtility::thumbCode($row, $table, $field);
626  }
627 
637  public function makeQueryArray($table, $id, $addWhere = '', $fieldList = '*')
638  {
639  $hookObjectsArr = [];
640  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'])) {
641  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'] as $classRef) {
642  $hookObjectsArr[] = GeneralUtility::getUserObj($classRef);
643  }
644  }
645  // Set ORDER BY:
646  $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ? 'ORDER BY ' . $GLOBALS['TCA'][$table]['ctrl']['sortby'] : $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
647  if ($this->sortField) {
648  if (in_array($this->sortField, $this->makeFieldList($table, 1))) {
649  $orderBy = 'ORDER BY ' . $this->sortField;
650  if ($this->sortRev) {
651  $orderBy .= ' DESC';
652  }
653  }
654  }
655  // Set LIMIT:
656  $limit = $this->iLimit ? ($this->firstElementNumber ? $this->firstElementNumber . ',' : '') . $this->iLimit : '';
657  // Filtering on displayable pages (permissions):
658  $pC = $table == 'pages' && $this->perms_clause ? ' AND ' . $this->perms_clause : '';
659  // Adding search constraints:
660  $search = $this->makeSearchString($table, $id);
661  // Compiling query array:
662  $queryParts = [
663  'SELECT' => $fieldList,
664  'FROM' => $table,
665  'WHERE' => $this->pidSelect . ' ' . $pC . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table) . ' ' . $addWhere . ' ' . $search,
666  'GROUPBY' => '',
667  'ORDERBY' => $this->getDatabaseConnection()->stripOrderBy($orderBy),
668  'LIMIT' => $limit
669  ];
670  // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set
671  if ((in_array($table, GeneralUtility::trimExplode(',', $this->hideTranslations)) || $this->hideTranslations === '*') && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && $table !== 'pages_language_overlay') {
672  $queryParts['WHERE'] .= ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=0 ';
673  }
674  // Apply hook as requested in http://forge.typo3.org/issues/16634
675  foreach ($hookObjectsArr as $hookObj) {
676  if (method_exists($hookObj, 'makeQueryArray_post')) {
677  $_params = [
678  'orderBy' => $orderBy,
679  'limit' => $limit,
680  'pC' => $pC,
681  'search' => $search
682  ];
683  $hookObj->makeQueryArray_post($queryParts, $this, $table, $id, $addWhere, $fieldList, $_params);
684  }
685  }
686  // Return query:
687  return $queryParts;
688  }
689 
697  public function setTotalItems($queryParts)
698  {
699  $this->totalItems = $this->getDatabaseConnection()->exec_SELECTcountRows('*', $queryParts['FROM'], $queryParts['WHERE']);
700  }
701 
710  public function makeSearchString($table, $currentPid = -1)
711  {
712  $result = '';
713  $currentPid = (int)$currentPid;
714  $tablePidField = $table === 'pages' ? 'uid' : 'pid';
715  // Make query, only if table is valid and a search string is actually defined:
716  if ($this->searchString) {
717  $result = ' AND 0=1';
718  $searchableFields = $this->getSearchFields($table);
719  if (!empty($searchableFields)) {
720  if (MathUtility::canBeInterpretedAsInteger($this->searchString)) {
721  $whereParts = [
722  'uid=' . $this->searchString
723  ];
724  foreach ($searchableFields as $fieldName) {
725  if (isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
726  $fieldConfig = &$GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
727  $condition = $fieldName . '=' . $this->searchString;
728  if ($fieldConfig['type'] == 'input' && $fieldConfig['eval'] && GeneralUtility::inList($fieldConfig['eval'], 'int')) {
729  if (is_array($fieldConfig['search']) && in_array('pidonly', $fieldConfig['search']) && $currentPid > 0) {
730  $condition = '(' . $condition . ' AND ' . $tablePidField . '=' . $currentPid . ')';
731  }
732  $whereParts[] = $condition;
733  } elseif ($fieldConfig['type'] == 'text' ||
734  $fieldConfig['type'] == 'flex' ||
735  ($fieldConfig['type'] == 'input' && (!$fieldConfig['eval'] || !preg_match('/date|time|int/', $fieldConfig['eval'])))) {
736  $condition = $fieldName . ' LIKE \'%' . $this->searchString . '%\'';
737  $whereParts[] = $condition;
738  }
739  }
740  }
741  } else {
742  $whereParts = [];
743  $db = $this->getDatabaseConnection();
744  $like = '\'%' . $db->quoteStr($db->escapeStrForLike($this->searchString, $table), $table) . '%\'';
745  foreach ($searchableFields as $fieldName) {
746  if (isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
747  $fieldConfig = &$GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
748  $format = 'LOWER(%s) LIKE LOWER(%s)';
749  if (is_array($fieldConfig['search'])) {
750  if (in_array('case', $fieldConfig['search'])) {
751  $format = '%s LIKE %s';
752  }
753  if (in_array('pidonly', $fieldConfig['search']) && $currentPid > 0) {
754  $format = '(' . $format . ' AND ' . $tablePidField . '=' . $currentPid . ')';
755  }
756  if ($fieldConfig['search']['andWhere']) {
757  $format = '((' . $fieldConfig['search']['andWhere'] . ') AND (' . $format . '))';
758  }
759  }
760  if ($fieldConfig['type'] == 'text' || $fieldConfig['type'] == 'flex' || $fieldConfig['type'] == 'input' && (!$fieldConfig['eval'] || !preg_match('/date|time|int/', $fieldConfig['eval']))) {
761  $whereParts[] = sprintf($format, $fieldName, $like);
762  }
763  }
764  }
765  }
766  // If search-fields were defined (and there always are) we create the query:
767  if (!empty($whereParts)) {
768  $result = ' AND (' . implode(' OR ', $whereParts) . ')';
769  }
770  }
771  }
772  return $result;
773  }
774 
781  protected function getSearchFields($tableName)
782  {
783  $fieldArray = [];
784  $fieldListWasSet = false;
785  // Get fields from ctrl section of TCA first
786  if (isset($GLOBALS['TCA'][$tableName]['ctrl']['searchFields'])) {
787  $fieldArray = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$tableName]['ctrl']['searchFields'], true);
788  $fieldListWasSet = true;
789  }
790  // Call hook to add or change the list
791  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'])) {
792  $hookParameters = [
793  'tableHasSearchConfiguration' => $fieldListWasSet,
794  'tableName' => $tableName,
795  'searchFields' => &$fieldArray,
796  'searchString' => $this->searchString
797  ];
798  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'] as $hookFunction) {
799  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
800  }
801  }
802  return $fieldArray;
803  }
804 
813  public function linkWrapTable($table, $code)
814  {
815  if ($this->table !== $table) {
816  return '<a href="' . htmlspecialchars($this->listURL('', $table, 'firstElementNumber')) . '">' . $code . '</a>';
817  }
818  return '<a href="' . htmlspecialchars($this->listURL('', '', 'sortField,sortRev,table,firstElementNumber')) . '">' . $code . '</a>';
819  }
820 
830  public function linkWrapItems($table, $uid, $code, $row)
831  {
832  $lang = $this->getLanguageService();
833  $origCode = $code;
834  // If the title is blank, make a "no title" label:
835  if ((string)$code === '') {
836  $code = '<i>[' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', 1) . ']</i> - ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(
838  $this->getBackendUserAuthentication()->uc['titleLen']
839  ));
840  } else {
841  $code = htmlspecialchars(GeneralUtility::fixed_lgd_cs($code, $this->fixedL), ENT_QUOTES, 'UTF-8', false);
842  if ($code != htmlspecialchars($origCode)) {
843  $code = '<span title="' . htmlspecialchars($origCode, ENT_QUOTES, 'UTF-8', false) . '">' . $code . '</span>';
844  }
845  }
846  switch ((string)$this->clickTitleMode) {
847  case 'edit':
848  // If the listed table is 'pages' we have to request the permission settings for each page:
849  if ($table == 'pages') {
850  $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
851  $permsEdit = $localCalcPerms & Permission::PAGE_EDIT;
852  } else {
853  $permsEdit = $this->calcPerms & Permission::CONTENT_EDIT;
854  }
855  // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
856  if ($permsEdit) {
857  $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
858  $code = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1)) . '" title="' . $lang->getLL('edit', true) . '">' . $code . '</a>';
859  }
860  break;
861  case 'show':
862  // "Show" link (only pages and tt_content elements)
863  if ($table == 'pages' || $table == 'tt_content') {
864  $code = '<a href="#" onclick="' . htmlspecialchars(
865  BackendUtility::viewOnClick(($table == 'tt_content' ? $this->id . '#' . $row['uid'] : $row['uid']))
866  ) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', true) . '">' . $code . '</a>';
867  }
868  break;
869  case 'info':
870  // "Info": (All records)
871  $code = '<a href="#" onclick="' . htmlspecialchars(('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;')) . '" title="' . $lang->getLL('showInfo', true) . '">' . $code . '</a>';
872  break;
873  default:
874  // Output the label now:
875  if ($table == 'pages') {
876  $code = '<a href="' . htmlspecialchars($this->listURL($uid, '', 'firstElementNumber')) . '" onclick="setHighlight(' . $uid . ')">' . $code . '</a>';
877  } else {
878  $code = $this->linkUrlMail($code, $origCode);
879  }
880  }
881  return $code;
882  }
883 
891  public function linkUrlMail($code, $testString)
892  {
893  // Check for URL:
894  $scheme = parse_url($testString, PHP_URL_SCHEME);
895  if ($scheme === 'http' || $scheme === 'https' || $scheme === 'ftp') {
896  return '<a href="' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
897  }
898  // Check for email:
899  if (GeneralUtility::validEmail($testString)) {
900  return '<a href="mailto:' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
901  }
902  // Return if nothing else...
903  return $code;
904  }
905 
916  public function listURL($altId = '', $table = '-1', $exclList = '')
917  {
918  $urlParameters = [];
919  if ((string)$altId !== '') {
920  $urlParameters['id'] = $altId;
921  } else {
922  $urlParameters['id'] = $this->id;
923  }
924  if ($table === '-1') {
925  $urlParameters['table'] = $this->table;
926  } else {
927  $urlParameters['table'] = $table;
928  }
929  if ($this->thumbs) {
930  $urlParameters['imagemode'] = $this->thumbs;
931  }
932  if ($this->returnUrl) {
933  $urlParameters['returnUrl'] = $this->returnUrl;
934  }
935  if ((!$exclList || !GeneralUtility::inList($exclList, 'search_field')) && $this->searchString) {
936  $urlParameters['search_field'] = $this->searchString;
937  }
938  if ($this->searchLevels) {
939  $urlParameters['search_levels'] = $this->searchLevels;
940  }
941  if ($this->showLimit) {
942  $urlParameters['showLimit'] = $this->showLimit;
943  }
944  if ((!$exclList || !GeneralUtility::inList($exclList, 'firstElementNumber')) && $this->firstElementNumber) {
945  $urlParameters['pointer'] = $this->firstElementNumber;
946  }
947  if ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField) {
948  $urlParameters['sortField'] = $this->sortField;
949  }
950  if ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev) {
951  $urlParameters['sortRev'] = $this->sortRev;
952  }
953 
954  $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters);
955 
956  if ($routePath = GeneralUtility::_GP('route')) {
957  $router = GeneralUtility::makeInstance(Router::class);
958  $route = $router->match($routePath);
959  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
960  $url = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'), $urlParameters);
961  } elseif ($moduleName = GeneralUtility::_GP('M')) {
962  $url = BackendUtility::getModuleUrl($moduleName, $urlParameters);
963  } else {
964  $url = GeneralUtility::getIndpEnv('SCRIPT_NAME') . '?' . ltrim(GeneralUtility::implodeArrayForUrl('', $urlParameters), '&');
965  }
966  return $url;
967  }
968 
974  public function requestUri()
975  {
976  return $this->listURL();
977  }
978 
987  public function makeFieldList($table, $dontCheckUser = false, $addDateFields = false)
988  {
989  $backendUser = $this->getBackendUserAuthentication();
990  // Init fieldlist array:
991  $fieldListArr = [];
992  // Check table:
993  if (is_array($GLOBALS['TCA'][$table]) && isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
994  if (isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
995  // Traverse configured columns and add them to field array, if available for user.
996  foreach ($GLOBALS['TCA'][$table]['columns'] as $fN => $fieldValue) {
997  if ($dontCheckUser || (!$fieldValue['exclude'] || $backendUser->check('non_exclude_fields', $table . ':' . $fN)) && $fieldValue['config']['type'] != 'passthrough') {
998  $fieldListArr[] = $fN;
999  }
1000  }
1001 
1002  $fieldListArr[] = 'uid';
1003  $fieldListArr[] = 'pid';
1004 
1005  // Add date fields
1006  if ($dontCheckUser || $backendUser->isAdmin() || $addDateFields) {
1007  if ($GLOBALS['TCA'][$table]['ctrl']['tstamp']) {
1008  $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['tstamp'];
1009  }
1010  if ($GLOBALS['TCA'][$table]['ctrl']['crdate']) {
1011  $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['crdate'];
1012  }
1013  }
1014  // Add more special fields:
1015  if ($dontCheckUser || $backendUser->isAdmin()) {
1016  if ($GLOBALS['TCA'][$table]['ctrl']['cruser_id']) {
1017  $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['cruser_id'];
1018  }
1019  if ($GLOBALS['TCA'][$table]['ctrl']['sortby']) {
1020  $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
1021  }
1022  if (ExtensionManagementUtility::isLoaded('version') && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
1023  $fieldListArr[] = 't3ver_id';
1024  $fieldListArr[] = 't3ver_state';
1025  $fieldListArr[] = 't3ver_wsid';
1026  }
1027  }
1028  } else {
1029  GeneralUtility::sysLog(sprintf('$TCA is broken for the table "%s": no required "columns" entry in $TCA.', $table), 'core', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1030  }
1031  }
1032  return $fieldListArr;
1033  }
1034 
1043  protected function getSearchableWebmounts($id, $depth, $perms_clause)
1044  {
1045  $backendUser = $this->getBackendUserAuthentication();
1047  $tree = GeneralUtility::makeInstance(PageTreeView::class);
1048  $tree->init('AND ' . $perms_clause);
1049  $tree->makeHTML = 0;
1050  $tree->fieldArray = ['uid', 'php_tree_stop'];
1051  $idList = [];
1052 
1053  $allowedMounts = !$backendUser->isAdmin() && $id === 0
1054  ? $backendUser->returnWebmounts()
1055  : [$id];
1056 
1057  foreach ($allowedMounts as $allowedMount) {
1058  $idList[] = $allowedMount;
1059  if ($depth) {
1060  $tree->getTree($allowedMount, $depth, '');
1061  }
1062  $idList = array_merge($idList, $tree->ids);
1063  }
1064 
1065  return $idList;
1066  }
1067 
1074  public function localizationRedirect($justLocalized)
1075  {
1076  list($table, $orig_uid, $language) = explode(':', $justLocalized);
1077  if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
1078  $localizedRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid', $table, $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . (int)$language . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . (int)$orig_uid . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table));
1079  if (is_array($localizedRecord)) {
1080  // Create parameters and finally run the classic page module for creating a new page translation
1081  $url = $this->listURL();
1082  $editUserAccountUrl = BackendUtility::getModuleUrl(
1083  'record_edit',
1084  [
1085  'edit[' . $table . '][' . $localizedRecord['uid'] . ']' => 'edit',
1086  'returnUrl' => $url
1087  ]
1088  );
1089  HttpUtility::redirect($editUserAccountUrl);
1090  }
1091  }
1092  }
1093 
1100  public function setOverrideUrlParameters(array $urlParameters)
1101  {
1102  $this->overrideUrlParameters = $urlParameters;
1103  }
1104 
1117  public function setTableDisplayOrder(array $orderInformation)
1118  {
1119  foreach ($orderInformation as $tableName => &$configuration) {
1120  if (isset($configuration['before'])) {
1121  if (is_string($configuration['before'])) {
1122  $configuration['before'] = GeneralUtility::trimExplode(',', $configuration['before'], true);
1123  } elseif (!is_array($configuration['before'])) {
1124  throw new \UnexpectedValueException('The specified "before" order configuration for table "' . $tableName . '" is invalid.', 1436195933);
1125  }
1126  }
1127  if (isset($configuration['after'])) {
1128  if (is_string($configuration['after'])) {
1129  $configuration['after'] = GeneralUtility::trimExplode(',', $configuration['after'], true);
1130  } elseif (!is_array($configuration['after'])) {
1131  throw new \UnexpectedValueException('The specified "after" order configuration for table "' . $tableName . '" is invalid.', 1436195934);
1132  }
1133  }
1134  }
1135  $this->tableDisplayOrder = $orderInformation;
1136  }
1137 
1141  protected function getBackendUserAuthentication()
1142  {
1143  return $GLOBALS['BE_USER'];
1144  }
1145 
1149  protected function getDatabaseConnection()
1150  {
1151  return $GLOBALS['TYPO3_DB'];
1152  }
1153 }
static editOnClick($params, $_='', $requestUri='')
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static viewOnClick($pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
makeFieldList($table, $dontCheckUser=false, $addDateFields=false)
static fixed_lgd_cs($string, $chars, $appendString='...')
$uid
Definition: server.php:38
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
start($id, $table, $pointer, $search='', $levels=0, $showLimit=0)
static getRecordWSOL($table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
static deleteClause($table, $tableAlias='')