‪TYPO3CMS  9.5
DatabaseRecordList.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 
53 
59 {
61 
65  protected ‪$deprecatedPublicProperties = [
66  'newWizards' => 'Using $newWizards of class DatabaseRecordList from outside is discouraged, property will be removed in TYPO3 v10.0.',
67  ];
68 
69  // *********
70  // External:
71  // *********
72 
79  public ‪$allowedNewTables = [];
80 
87  public ‪$deniedNewTables = [];
88 
97  public ‪$newWizards = false;
98 
105 
111  public ‪$showClipboard = false;
112 
118  public ‪$noControlPanels = false;
119 
125  public ‪$clickMenuEnabled = true;
126 
132  public ‪$totalRowCount;
133 
139  public ‪$spaceIcon;
140 
146  public ‪$disableSingleTableView = false;
147 
148  // *********
149  // Internal:
150  // *********
151 
157  public ‪$pageRow = [];
158 
164  public ‪$modSharedTSconfig = [];
165 
171  public ‪$pageOverlays = [];
172 
178  public ‪$languageIconTitles = [];
179 
185  public ‪$hideTranslations = '';
186 
192  public ‪$csvOutput = false;
193 
199  public ‪$recPath_cache = [];
200 
206  public ‪$sortField;
207 
213  public ‪$itemsLimitPerTable = 20;
214 
221 
227  public ‪$id;
228 
232  public ‪$no_noWrap = 0;
233 
239  public ‪$setLMargin = 1;
240 
246  public ‪$duplicateStack = [];
247 
253  public ‪$script = 'index.php';
254 
261 
267  public ‪$thisScript = '';
268 
274  public ‪$JScode = '';
275 
279  public ‪$translateTools;
280 
286  public ‪$itemsLimitSingleTable = 100;
287 
293  public ‪$tablesCollapsed = [];
294 
298  public ‪$modTSconfig;
299 
305  public ‪$HTMLcode = '';
306 
313 
319  public ‪$thumbs = 0;
320 
326  public ‪$currentTable = [];
327 
333  public ‪$allFields = 0;
334 
340  public ‪$showLimit = 0;
341 
347  public ‪$fieldArray = [];
348 
354  public ‪$hideTables = '';
355 
362 
368  public ‪$oddColumnsCssClass = '';
369 
376  public ‪$fixedL = 30;
377 
383  public ‪$perms_clause = '';
384 
390  public ‪$returnUrl = '';
391 
397  public ‪$table = '';
398 
404  public ‪$calcPerms = 0;
405 
411  public ‪$clickTitleMode = '';
412 
416  public ‪$showIcon = 1;
417 
423  public ‪$searchLevels = '';
424 
430  public ‪$iLimit = 0;
431 
437  public ‪$totalItems = '';
438 
444  public ‪$leftMargin = 0;
445 
451  public ‪$tableTSconfigOverTCA = [];
452 
458  public ‪$pageRecord = [];
459 
465  public ‪$setFields = [];
466 
472  public ‪$counter = 0;
473 
480 
486  public ‪$eCounter = 0;
487 
493  public ‪$searchString = '';
494 
500  public ‪$sortRev;
501 
507  public ‪$duplicateField;
508 
514  public ‪$tableList = '';
515 
521  protected ‪$csvLines = [];
522 
528  public ‪$clipObj;
529 
535  public ‪$CBnames = [];
536 
542  protected ‪$referenceCount = [];
543 
549  public ‪$translations;
550 
557  public ‪$selFieldList;
558 
562  public ‪$pageinfo;
563 
569  public ‪$MOD_MENU;
570 
576  protected ‪$editable = true;
577 
581  protected ‪$iconFactory;
582 
593  protected ‪$tableDisplayOrder = [];
594 
600  protected ‪$overridePageIdList = [];
601 
606  protected ‪$overrideUrlParameters = [];
607 
613  protected ‪$currentLink = [];
614 
620  protected ‪$showOnlyTranslatedRecords = false;
621 
629  protected ‪$systemLanguagesOnPage;
630 
636  protected ‪$languagesAllowedForUser = [];
637 
641  public function ‪__construct()
642  {
643  if (isset(‪$GLOBALS['BE_USER']->uc['titleLen']) && ‪$GLOBALS['BE_USER']->uc['titleLen'] > 0) {
644  $this->fixedL = ‪$GLOBALS['BE_USER']->uc['titleLen'];
645  }
646  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
647  $this->‪getTranslateTools();
648  $this->‪determineScriptUrl();
649 
650  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
651  }
652 
659  public function ‪getButtons()
660  {
661  $module = $this->‪getModule();
662  $backendUser = $this->‪getBackendUserAuthentication();
663  $lang = $this->‪getLanguageService();
664  $buttons = [
665  'csh' => '',
666  'view' => '',
667  'edit' => '',
668  'hide_unhide' => '',
669  'move' => '',
670  'new_record' => '',
671  'paste' => '',
672  'level_up' => '',
673  'cache' => '',
674  'reload' => '',
675  'shortcut' => '',
676  'back' => '',
677  'csv' => '',
678  'export' => ''
679  ];
681  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
682  // Get users permissions for this page record:
683  $localCalcPerms = $backendUser->calcPerms($this->pageRow);
684  // CSH
685  if ((string)$this->id === '') {
686  $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'list_module_noId');
687  } elseif (!$this->id) {
688  $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'list_module_root');
689  } else {
690  $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'list_module');
691  }
692  if (isset($this->id)) {
693  // View Exclude doktypes 254,255 Configuration:
694  // mod.web_list.noViewWithDokTypes = 254,255
695  if (isset($module->modTSconfig['properties']['noViewWithDokTypes'])) {
696  $noViewDokTypes = GeneralUtility::trimExplode(',', $module->modTSconfig['properties']['noViewWithDokTypes'], true);
697  } else {
698  //default exclusion: doktype 254 (folder), 255 (recycler)
699  $noViewDokTypes = [
700  PageRepository::DOKTYPE_SYSFOLDER,
701  PageRepository::DOKTYPE_RECYCLER
702  ];
703  }
704  if (!in_array($this->pageRow['doktype'], $noViewDokTypes)) {
705  $onClick = htmlspecialchars(BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id)));
706  $buttons['view'] = '<a href="#" onclick="' . $onClick . '" title="'
707  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage')) . '">'
708  . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
709  }
710  // New record on pages that are not locked by editlock
711  if (!$module->modTSconfig['properties']['noCreateRecordsLink'] && $this->editLockPermissions()) {
712  $onClick = htmlspecialchars('return jumpExt(' . GeneralUtility::quoteJSvalue((string)$uriBuilder->buildUriFromRoute('db_new', ['id' => $this->id])) . ');');
713  $buttons['new_record'] = '<a href="#" onclick="' . $onClick . '" title="'
714  . htmlspecialchars($lang->getLL('newRecordGeneral')) . '">'
715  . $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render() . '</a>';
716  }
717  // If edit permissions are set, see
718  // \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
719  if ($localCalcPerms & Permission::PAGE_EDIT && !empty($this->id) && $this->‪editLockPermissions() && $this->‪getBackendUserAuthentication()->checkLanguageAccess(0)) {
720  // Edit
721  $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit';
722  $onClick = htmlspecialchars(BackendUtility::editOnClick($params, '', -1));
723  $buttons['edit'] = '<a href="#" onclick="' . $onClick . '" title="' . htmlspecialchars($lang->getLL('editPage')) . '">'
724  . $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render()
725  . '</a>';
726  }
727  // Paste
728  if (($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) && $this->‪editLockPermissions()) {
729  $elFromTable = $this->clipObj->elFromTable('');
730  if (!empty($elFromTable)) {
731  $confirmText = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable);
732  $buttons['paste'] = '<a'
733  . ' href="' . htmlspecialchars($this->clipObj->pasteUrl('', $this->id)) . '"'
734  . ' title="' . htmlspecialchars($lang->getLL('clip_paste')) . '"'
735  . ' class="t3js-modal-trigger"'
736  . ' data-severity="warning"'
737  . ' data-title="' . htmlspecialchars($lang->getLL('clip_paste')) . '"'
738  . ' data-content="' . htmlspecialchars($confirmText) . '"'
739  . '>'
740  . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render()
741  . '</a>';
742  }
743  }
744  // Cache
745  $buttons['cache'] = '<a href="' . htmlspecialchars($this->‪listURL() . '&clear_cache=1') . '" title="'
746  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache')) . '">'
747  . $this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL)->render() . '</a>';
748  if ($this->table && (!isset($module->modTSconfig['properties']['noExportRecordsLinks'])
749  || (isset($module->modTSconfig['properties']['noExportRecordsLinks'])
750  && !$module->modTSconfig['properties']['noExportRecordsLinks']))
751  ) {
752  // CSV
753  $buttons['csv'] = '<a href="' . htmlspecialchars($this->‪listURL() . '&csv=1') . '" title="'
754  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.csv')) . '">'
755  . $this->iconFactory->getIcon('actions-document-export-csv', Icon::SIZE_SMALL)->render() . '</a>';
756  // Export
757  if (ExtensionManagementUtility::isLoaded('impexp')) {
758  $url = (string)$uriBuilder->buildUriFromRoute('xMOD_tximpexp', ['tx_impexp[action]' => 'export']);
759  $buttons['export'] = '<a href="' . htmlspecialchars($url . '&tx_impexp[list][]='
760  . rawurlencode($this->table . ':' . $this->id)) . '" title="'
761  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.export')) . '">'
762  . $this->iconFactory->getIcon('actions-document-export-t3d', Icon::SIZE_SMALL)->render() . '</a>';
763  }
764  }
765  // Reload
766  $buttons['reload'] = '<a href="' . htmlspecialchars($this->‪listURL()) . '" title="'
767  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload')) . '">'
768  . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . '</a>';
769  // Shortcut
770  if ($backendUser->mayMakeShortcut()) {
771  $buttons['shortcut'] = $this->‪getDocumentTemplate()->‪makeShortcutIcon(
772  'id, M, imagemode, pointer, table, search_field, search_levels, showLimit, sortField, sortRev',
773  implode(',', array_keys($this->MOD_MENU)),
774  'web_list'
775  );
776  }
777  // Back
778  if ($this->returnUrl) {
779  $href = htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl, ['id' => $this->id]));
780  $buttons['back'] = '<a href="' . $href . '" class="typo3-goBack" title="'
781  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack')) . '">'
782  . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)->render() . '</a>';
783  }
784  }
785  return $buttons;
786  }
787 
794  public function ‪getDocHeaderButtons(ModuleTemplate ‪$moduleTemplate)
795  {
797  $module = $this->‪getModule();
798  $backendUser = $this->‪getBackendUserAuthentication();
799  $lang = $this->‪getLanguageService();
800  // Get users permissions for this page record:
801  $localCalcPerms = $backendUser->calcPerms($this->pageRow);
803  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
804  // CSH
805  if ((string)$this->id === '') {
806  $fieldName = 'list_module_noId';
807  } elseif (!$this->id) {
808  $fieldName = 'list_module_root';
809  } else {
810  $fieldName = 'list_module';
811  }
812  $cshButton = $buttonBar->makeHelpButton()
813  ->setModuleName('xMOD_csh_corebe')
814  ->setFieldName($fieldName);
815  $buttonBar->addButton($cshButton);
816  if (isset($this->id)) {
817  // View Exclude doktypes 254,255 Configuration:
818  // mod.web_list.noViewWithDokTypes = 254,255
819  if (isset($module->modTSconfig['properties']['noViewWithDokTypes'])) {
820  $noViewDokTypes = GeneralUtility::trimExplode(',', $module->modTSconfig['properties']['noViewWithDokTypes'], true);
821  } else {
822  //default exclusion: doktype 254 (folder), 255 (recycler)
823  $noViewDokTypes = [
824  PageRepository::DOKTYPE_SYSFOLDER,
825  PageRepository::DOKTYPE_RECYCLER
826  ];
827  }
828  // New record on pages that are not locked by editlock
829  if (!$module->modTSconfig['properties']['noCreateRecordsLink'] && $this->editLockPermissions()) {
830  $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue((string)$uriBuilder->buildUriFromRoute('db_new', ['id' => $this->id])) . ');';
831  $newRecordButton = $buttonBar->makeLinkButton()
832  ->setHref('#')
833  ->setOnClick($onClick)
834  ->setTitle($lang->getLL('newRecordGeneral'))
835  ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL));
836  $buttonBar->addButton($newRecordButton, ButtonBar::BUTTON_POSITION_LEFT, 10);
837  }
838  if (!in_array($this->pageRow['doktype'], $noViewDokTypes)) {
839  $onClick = BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id));
840  $viewButton = $buttonBar->makeLinkButton()
841  ->setHref('#')
842  ->setOnClick($onClick)
843  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
844  ->setIcon($this->iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL));
845  $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
846  }
847  // If edit permissions are set, see
848  // \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
849  if ($localCalcPerms & Permission::PAGE_EDIT && !empty($this->id) && $this->‪editLockPermissions() && $backendUser->checkLanguageAccess(0)) {
850  // Edit
851  $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit';
852  $onClick = BackendUtility::editOnClick($params, '', -1);
853  $editButton = $buttonBar->makeLinkButton()
854  ->setHref('#')
855  ->setOnClick($onClick)
856  ->setTitle($lang->getLL('editPage'))
857  ->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL));
858  $buttonBar->addButton($editButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
859  }
860  // Paste
861  if ($this->showClipboard && ($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) && $this->‪editLockPermissions()) {
862  $elFromTable = $this->clipObj->elFromTable('');
863  if (!empty($elFromTable)) {
864  $confirmMessage = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable);
865  $pasteButton = $buttonBar->makeLinkButton()
866  ->setHref($this->clipObj->pasteUrl('', $this->id))
867  ->setTitle($lang->getLL('clip_paste'))
868  ->setClasses('t3js-modal-trigger')
869  ->setDataAttributes([
870  'severity' => 'warning',
871  'content' => $confirmMessage,
872  'title' => $lang->getLL('clip_paste')
873  ])
874  ->setIcon($this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL));
875  $buttonBar->addButton($pasteButton, ButtonBar::BUTTON_POSITION_LEFT, 40);
876  }
877  }
878  // Cache
879  $clearCacheButton = $buttonBar->makeLinkButton()
880  ->setHref($this->‪listURL() . '&clear_cache=1')
881  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
882  ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL));
883  $buttonBar->addButton($clearCacheButton, ButtonBar::BUTTON_POSITION_RIGHT);
884  if ($this->table && (!isset($module->modTSconfig['properties']['noExportRecordsLinks'])
885  || (isset($module->modTSconfig['properties']['noExportRecordsLinks'])
886  && !$module->modTSconfig['properties']['noExportRecordsLinks']))
887  ) {
888  // CSV
889  $csvButton = $buttonBar->makeLinkButton()
890  ->setHref($this->‪listURL() . '&csv=1')
891  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.csv'))
892  ->setIcon($this->iconFactory->getIcon('actions-document-export-csv', Icon::SIZE_SMALL))
893  ->setShowLabelText(true);
894  $buttonBar->addButton($csvButton, ButtonBar::BUTTON_POSITION_LEFT, 40);
895  // Export
896  if (ExtensionManagementUtility::isLoaded('impexp')) {
897  $url = (string)$uriBuilder->buildUriFromRoute('xMOD_tximpexp', ['tx_impexp[action]' => 'export']);
898  $exportButton = $buttonBar->makeLinkButton()
899  ->setHref($url . '&tx_impexp[list][]=' . rawurlencode($this->table . ':' . $this->id))
900  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.export'))
901  ->setIcon($this->iconFactory->getIcon('actions-document-export-t3d', Icon::SIZE_SMALL))
902  ->setShowLabelText(true);
903  $buttonBar->addButton($exportButton, ButtonBar::BUTTON_POSITION_LEFT, 40);
904  }
905  }
906  // Reload
907  $reloadButton = $buttonBar->makeLinkButton()
908  ->setHref($this->‪listURL())
909  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
910  ->setIcon($this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL));
911  $buttonBar->addButton($reloadButton, ButtonBar::BUTTON_POSITION_RIGHT);
912  // Shortcut
913  if ($backendUser->mayMakeShortcut()) {
914  $shortCutButton = $buttonBar->makeShortcutButton()
915  ->setModuleName('web_list')
916  ->setGetVariables([
917  'id',
918  'route',
919  'imagemode',
920  'pointer',
921  'table',
922  'search_field',
923  'search_levels',
924  'showLimit',
925  'sortField',
926  'sortRev'
927  ])
928  ->setSetVariables(array_keys($this->MOD_MENU));
929  $buttonBar->addButton($shortCutButton, ButtonBar::BUTTON_POSITION_RIGHT);
930  }
931  // Back
932  if ($this->returnUrl) {
933  $backButton = $buttonBar->makeLinkButton()
934  ->setHref($this->returnUrl)
935  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
936  ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
937  $buttonBar->addButton($backButton, ButtonBar::BUTTON_POSITION_LEFT);
938  }
939  }
940  }
941 
951  public function ‪getTable(‪$table, ‪$id, $rowList = '')
952  {
953  $rowListArray = GeneralUtility::trimExplode(',', $rowList, true);
954  // if no columns have been specified, show description (if configured)
955  if (!empty(‪$GLOBALS['TCA'][‪$table]['ctrl']['descriptionColumn']) && empty($rowListArray)) {
956  $rowListArray[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['descriptionColumn'];
957  }
958  $backendUser = $this->‪getBackendUserAuthentication();
959  $lang = $this->‪getLanguageService();
960  // Init
961  $addWhere = '';
962  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
963  $titleCol = ‪$GLOBALS['TCA'][‪$table]['ctrl']['label'];
964  $thumbsCol = ‪$GLOBALS['TCA'][‪$table]['ctrl']['thumbnail'];
965  $l10nEnabled = ‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']
966  && ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'];
967  $tableCollapsed = (bool)$this->tablesCollapsed[‪$table];
968  // prepare space icon
969  $this->spaceIcon = '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>';
970  // Cleaning rowlist for duplicates and place the $titleCol as the first column always!
971  $this->fieldArray = [];
972  // title Column
973  // Add title column
974  $this->fieldArray[] = $titleCol;
975  // Control-Panel
976  if (!GeneralUtility::inList($rowList, '_CONTROL_')) {
977  $this->fieldArray[] = '_CONTROL_';
978  }
979  // Clipboard
980  if ($this->showClipboard) {
981  $this->fieldArray[] = '_CLIPBOARD_';
982  }
983  // Ref
984  if (!$this->dontShowClipControlPanels) {
985  $this->fieldArray[] = '_REF_';
986  }
987  // Path
988  if ($this->searchLevels) {
989  $this->fieldArray[] = '_PATH_';
990  }
991  // Localization
992  if ($l10nEnabled) {
993  $this->fieldArray[] = '_LOCALIZATION_';
994  // Do not show the "Localize to:" field when only translated records should be shown
995  if (!$this->‪showOnlyTranslatedRecords) {
996  $this->fieldArray[] = '_LOCALIZATION_b';
997  }
998  // Only restrict to the default language if no search request is in place
999  // And if only translations should be shown
1000  if ($this->searchString === '' && !$this->‪showOnlyTranslatedRecords) {
1001  $addWhere = (string)$queryBuilder->expr()->orX(
1002  $queryBuilder->expr()->lte(‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'], 0),
1003  $queryBuilder->expr()->eq(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'], 0)
1004  );
1005  }
1006  }
1007  // Cleaning up:
1008  $this->fieldArray = array_unique(array_merge($this->fieldArray, $rowListArray));
1009  if ($this->noControlPanels) {
1010  $tempArray = array_flip($this->fieldArray);
1011  unset($tempArray['_CONTROL_']);
1012  unset($tempArray['_CLIPBOARD_']);
1013  $this->fieldArray = array_keys($tempArray);
1014  }
1015  // Creating the list of fields to include in the SQL query:
1016  $selectFields = ‪$this->fieldArray;
1017  $selectFields[] = 'uid';
1018  $selectFields[] = 'pid';
1019  // adding column for thumbnails
1020  if ($thumbsCol) {
1021  $selectFields[] = $thumbsCol;
1022  }
1023  if (‪$table === 'pages') {
1024  $selectFields[] = 'module';
1025  $selectFields[] = 'extendToSubpages';
1026  $selectFields[] = 'nav_hide';
1027  $selectFields[] = 'doktype';
1028  $selectFields[] = 'shortcut';
1029  $selectFields[] = 'shortcut_mode';
1030  $selectFields[] = 'mount_pid';
1031  }
1032  if (is_array(‪$GLOBALS['TCA'][‪$table]['ctrl']['enablecolumns'])) {
1033  $selectFields = array_merge($selectFields, ‪$GLOBALS['TCA'][‪$table]['ctrl']['enablecolumns']);
1034  }
1035  foreach (['type', 'typeicon_column', 'editlock'] as $field) {
1036  if (‪$GLOBALS['TCA'][‪$table]['ctrl'][$field]) {
1037  $selectFields[] = ‪$GLOBALS['TCA'][‪$table]['ctrl'][$field];
1038  }
1039  }
1040  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['versioningWS']) {
1041  $selectFields[] = 't3ver_id';
1042  $selectFields[] = 't3ver_state';
1043  $selectFields[] = 't3ver_wsid';
1044  }
1045  if ($l10nEnabled) {
1046  $selectFields[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'];
1047  $selectFields[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'];
1048  }
1049  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['label_alt']) {
1050  $selectFields = array_merge(
1051  $selectFields,
1052  GeneralUtility::trimExplode(',', ‪$GLOBALS['TCA'][‪$table]['ctrl']['label_alt'], true)
1053  );
1054  }
1055  // Unique list!
1056  $selectFields = array_unique($selectFields);
1057  $fieldListFields = $this->‪makeFieldList($table, 1);
1058  if (empty($fieldListFields) && ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['debug']) {
1059  $message = sprintf($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:missingTcaColumnsMessage'), ‪$table, ‪$table);
1060  $messageTitle = $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:missingTcaColumnsMessageTitle');
1062  $flashMessage = GeneralUtility::makeInstance(
1063  FlashMessage::class,
1064  $message,
1065  $messageTitle,
1066  FlashMessage::WARNING,
1067  true
1068  );
1070  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1072  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1073  $defaultFlashMessageQueue->enqueue($flashMessage);
1074  }
1075  // Making sure that the fields in the field-list ARE in the field-list from TCA!
1076  $selectFields = array_intersect($selectFields, $fieldListFields);
1077  // Implode it into a list of fields for the SQL-statement.
1078  ‪$selFieldList = implode(',', $selectFields);
1079  $this->selFieldList = ‪$selFieldList;
1080  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'] ?? [] as $className) {
1081  $hookObject = GeneralUtility::makeInstance($className);
1082  if (!$hookObject instanceof RecordListGetTableHookInterface) {
1083  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListGetTableHookInterface::class, 1195114460);
1084  }
1085  $hookObject->getDBlistQuery(‪$table, ‪$id, $addWhere, ‪$selFieldList, $this);
1086  }
1087 
1088  if (‪$table == 'pages' && $this->‪showOnlyTranslatedRecords) {
1089  $addWhere .= ' AND ' . ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'] . ' IN(' . implode(',', array_keys($this->languagesAllowedForUser)) . ')';
1090  }
1091 
1092  $additionalConstraints = empty($addWhere) ? [] : [QueryHelper::stripLogicalOperatorPrefix($addWhere)];
1093  ‪$selFieldList = GeneralUtility::trimExplode(',', ‪$selFieldList, true);
1094 
1095  // Create the SQL query for selecting the elements in the listing:
1096  // do not do paging when outputting as CSV
1097  if ($this->csvOutput) {
1098  $this->iLimit = 0;
1099  }
1100  if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
1101  // Get the two previous rows for sorting if displaying page > 1
1102  $this->firstElementNumber -= 2;
1103  $this->iLimit += 2;
1104  // (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList)
1105  $queryBuilder = $this->‪getQueryBuilder($table, ‪$id, $additionalConstraints);
1106  $this->firstElementNumber += 2;
1107  $this->iLimit -= 2;
1108  } else {
1109  // (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList)
1110  $queryBuilder = $this->‪getQueryBuilder($table, ‪$id, $additionalConstraints);
1111  }
1112 
1113  // Finding the total amount of records on the page
1114  // (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList)
1115  $this->‪setTotalItems($table, ‪$id, $additionalConstraints);
1116 
1117  // Init:
1118  $queryResult = $queryBuilder->execute();
1119  $dbCount = 0;
1120  $out = '';
1121  $tableHeader = '';
1122  ‪$listOnlyInSingleTableMode = $this->listOnlyInSingleTableMode && !‪$this->table;
1123  // If the count query returned any number of records, we perform the real query,
1124  // selecting records.
1125  if ($this->totalItems) {
1126  // Fetch records only if not in single table mode
1128  $dbCount = ‪$this->totalItems;
1129  } else {
1130  // Set the showLimit to the number of records when outputting as CSV
1131  if ($this->csvOutput) {
1132  $this->showLimit = ‪$this->totalItems;
1133  $this->iLimit = ‪$this->totalItems;
1134  $dbCount = ‪$this->totalItems;
1135  } else {
1136  if ($this->firstElementNumber + $this->showLimit <= $this->totalItems) {
1137  $dbCount = $this->showLimit + 2;
1138  } else {
1139  $dbCount = $this->totalItems - $this->firstElementNumber + 2;
1140  }
1141  }
1142  }
1143  }
1144  // If any records was selected, render the list:
1145  if ($dbCount) {
1146  $tableIdentifier = ‪$table;
1147  // Use a custom table title for translated pages
1148  if (‪$table == 'pages' && $this->‪showOnlyTranslatedRecords) {
1149  // pages records in list module are split into two own sections, one for pages with
1150  // sys_language_uid = 0 "Page" and an own section for sys_language_uid > 0 "Page Translation".
1151  // This if sets the different title for the page translation case and a unique table identifier
1152  // which is used in DOM as id.
1153  $tableTitle = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:pageTranslation'));
1154  $tableIdentifier = 'pages_translated';
1155  } else {
1156  $tableTitle = htmlspecialchars($lang->sL(‪$GLOBALS['TCA'][‪$table]['ctrl']['title']));
1157  if ($tableTitle === '') {
1158  $tableTitle = ‪$table;
1159  }
1160  }
1161  // Header line is drawn
1162  $theData = [];
1163  if ($this->disableSingleTableView) {
1164  $theData[$titleCol] = '<span class="c-table">' . BackendUtility::wrapInHelp(‪$table, '', $tableTitle)
1165  . '</span> (<span class="t3js-table-total-items">' . $this->totalItems . '</span>)';
1166  } else {
1167  $icon = $this->table
1168  ? '<span title="' . htmlspecialchars($lang->getLL('contractView')) . '">' . $this->iconFactory->getIcon('actions-view-table-collapse', Icon::SIZE_SMALL)->render() . '</span>'
1169  : '<span title="' . htmlspecialchars($lang->getLL('expandView')) . '">' . $this->iconFactory->getIcon('actions-view-table-expand', Icon::SIZE_SMALL)->render() . '</span>';
1170  $theData[$titleCol] = $this->‪linkWrapTable($table, $tableTitle . ' (<span class="t3js-table-total-items">' . $this->totalItems . '</span>) ' . $icon);
1171  }
1173  $tableHeader .= BackendUtility::wrapInHelp(‪$table, '', $theData[$titleCol]);
1174  } else {
1175  // Render collapse button if in multi table mode
1176  $collapseIcon = '';
1177  if (!$this->table) {
1178  $href = htmlspecialchars($this->‪listURL() . '&collapse[' . $table . ']=' . ($tableCollapsed ? '0' : '1'));
1179  $title = $tableCollapsed
1180  ? htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.expandTable'))
1181  : htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.collapseTable'));
1182  $icon = '<span class="collapseIcon">' . $this->iconFactory->getIcon(($tableCollapsed ? 'actions-view-list-expand' : 'actions-view-list-collapse'), Icon::SIZE_SMALL)->render() . '</span>';
1183  $collapseIcon = '<a href="' . $href . '" title="' . $title . '" class="pull-right t3js-toggle-recordlist" data-table="' . htmlspecialchars($tableIdentifier) . '" data-toggle="collapse" data-target="#recordlist-' . htmlspecialchars($tableIdentifier) . '">' . $icon . '</a>';
1184  }
1185  $tableHeader .= $theData[$titleCol] . $collapseIcon;
1186  }
1187  // Render table rows only if in multi table view or if in single table view
1188  $rowOutput = '';
1189  if (!‪$listOnlyInSingleTableMode || $this->table) {
1190  // Fixing an order table for sortby tables
1191  $this->currentTable = [];
1192  $currentIdList = [];
1193  $doSort = ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] && !‪$this->sortField;
1194  $prevUid = 0;
1195  $prevPrevUid = 0;
1196  // Get first two rows and initialize prevPrevUid and prevUid if on page > 1
1197  if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
1198  $row = $queryResult->fetch();
1199  $prevPrevUid = -((int)$row['uid']);
1200  $row = $queryResult->fetch();
1201  $prevUid = $row['uid'];
1202  }
1203  $accRows = [];
1204  // Accumulate rows here
1205  while ($row = $queryResult->fetch()) {
1206  if (!$this->‪isRowListingConditionFulfilled($table, $row)) {
1207  continue;
1208  }
1209  // In offline workspace, look for alternative record:
1210  BackendUtility::workspaceOL(‪$table, $row, $backendUser->workspace, true);
1211  if (is_array($row)) {
1212  $accRows[] = $row;
1213  $currentIdList[] = $row['uid'];
1214  if ($doSort) {
1215  if ($prevUid) {
1216  $this->currentTable['prev'][$row['uid']] = $prevPrevUid;
1217  $this->currentTable['next'][$prevUid] = '-' . $row['uid'];
1218  $this->currentTable['prevUid'][$row['uid']] = $prevUid;
1219  }
1220  $prevPrevUid = isset($this->currentTable['prev'][$row['uid']]) ? -$prevUid : $row['pid'];
1221  $prevUid = $row['uid'];
1222  }
1223  }
1224  }
1225  $this->totalRowCount = count($accRows);
1226  // CSV initiated
1227  if ($this->csvOutput) {
1228  $this->‪initCSV();
1229  }
1230  // Render items:
1231  $this->CBnames = [];
1232  $this->duplicateStack = [];
1233  $this->eCounter = ‪$this->firstElementNumber;
1234  $cc = 0;
1235  foreach ($accRows as $row) {
1236  // Render item row if counter < limit
1237  if ($cc < $this->iLimit) {
1238  $cc++;
1239  $this->translations = false;
1240  $rowOutput .= $this->‪renderListRow($table, $row, $cc, $titleCol, $thumbsCol);
1241  // If no search happened it means that the selected
1242  // records are either default or All language and here we will not select translations
1243  // which point to the main record:
1244  if ($l10nEnabled && $this->searchString === '' && !($this->hideTranslations === '*' || GeneralUtility::inList($this->hideTranslations, ‪$table))) {
1245  // For each available translation, render the record:
1246  if (is_array($this->translations)) {
1247  foreach ($this->translations as $lRow) {
1248  // $lRow isn't always what we want - if record was moved we've to work with the
1249  // placeholder records otherwise the list is messed up a bit
1250  if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) {
1251  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1252  ->getQueryBuilderForTable(‪$table);
1253  $queryBuilder->getRestrictions()
1254  ->removeAll()
1255  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1256  $predicates = [
1257  $queryBuilder->expr()->eq(
1258  't3ver_move_id',
1259  $queryBuilder->createNamedParameter((int)$lRow['uid'], \PDO::PARAM_INT)
1260  ),
1261  $queryBuilder->expr()->eq(
1262  'pid',
1263  $queryBuilder->createNamedParameter((int)$row['_MOVE_PLH_pid'], \PDO::PARAM_INT)
1264  ),
1265  $queryBuilder->expr()->eq(
1266  't3ver_wsid',
1267  $queryBuilder->createNamedParameter((int)$row['t3ver_wsid'], \PDO::PARAM_INT)
1268  ),
1269  ];
1270 
1271  $tmpRow = $queryBuilder
1272  ->select(...‪$selFieldList)
1273  ->from(‪$table)
1274  ->andWhere(...$predicates)
1275  ->execute()
1276  ->fetch();
1277 
1278  $lRow = is_array($tmpRow) ? $tmpRow : $lRow;
1279  }
1280  if (!$this->‪isRowListingConditionFulfilled($table, $lRow)) {
1281  continue;
1282  }
1283  // In offline workspace, look for alternative record:
1284  BackendUtility::workspaceOL(‪$table, $lRow, $backendUser->workspace, true);
1285  if (is_array($lRow) && $backendUser->checkLanguageAccess($lRow[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']])) {
1286  $currentIdList[] = $lRow['uid'];
1287  $rowOutput .= $this->‪renderListRow($table, $lRow, $cc, $titleCol, $thumbsCol, 18);
1288  }
1289  }
1290  }
1291  }
1292  }
1293  // Counter of total rows incremented:
1294  $this->eCounter++;
1295  }
1296  // Record navigation is added to the beginning and end of the table if in single
1297  // table mode
1298  if ($this->table) {
1299  $rowOutput = $this->‪renderListNavigation('top') . $rowOutput . $this->‪renderListNavigation('bottom');
1300  } else {
1301  // Show that there are more records than shown
1302  if ($this->totalItems > $this->itemsLimitPerTable) {
1303  $countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable ? $this->itemsLimitSingleTable : ‪$this->totalItems;
1304  $hasMore = $this->totalItems > ‪$this->itemsLimitSingleTable;
1305  $colspan = $this->showIcon ? count($this->fieldArray) + 1 : count($this->fieldArray);
1306  $rowOutput .= '<tr><td colspan="' . $colspan . '">
1307  <a href="' . htmlspecialchars($this->‪listURL() . '&table=' . rawurlencode($tableIdentifier)) . '" class="btn btn-default">'
1308  . '<span class="t3-icon fa fa-chevron-down"></span> <i>[1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . ']</i></a>
1309  </td></tr>';
1310  }
1311  }
1312  // The header row for the table is now created:
1313  $out .= $this->‪renderListHeader($table, $currentIdList);
1314  }
1315 
1316  $collapseClass = $tableCollapsed && !$this->table ? 'collapse' : 'collapse in';
1317  $dataState = $tableCollapsed && !$this->table ? 'collapsed' : 'expanded';
1318 
1319  // The list of records is added after the header:
1320  $out .= $rowOutput;
1321  // ... and it is all wrapped in a table:
1322  $out = '
1323 
1324 
1325 
1326  <!--
1327  DB listing of elements: "' . htmlspecialchars($tableIdentifier) . '"
1328  -->
1329  <div class="panel panel-space panel-default recordlist">
1330  <div class="panel-heading">
1331  ' . $tableHeader . '
1332  </div>
1333  <div class="' . $collapseClass . '" data-state="' . $dataState . '" id="recordlist-' . htmlspecialchars($tableIdentifier) . '">
1334  <div class="table-fit">
1335  <table data-table="' . htmlspecialchars($tableIdentifier) . '" class="table table-striped table-hover' . (‪$listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '">
1336  ' . $out . '
1337  </table>
1338  </div>
1339  </div>
1340  </div>
1341  ';
1342  // Output csv if...
1343  // This ends the page with exit.
1344  if ($this->csvOutput) {
1345  $this->‪outputCSV($table);
1346  }
1347  }
1348  // Return content:
1349  return $out;
1350  }
1351 
1360  protected function ‪getOnClickForRow(string ‪$table, array $row): string
1361  {
1362  if (‪$table === 'tt_content') {
1363  // Link to a content element, possibly translated and with anchor
1364  $additionalParams = '';
1365  $language = (int)$row[‪$GLOBALS['TCA']['tt_content']['ctrl']['languageField']];
1366  if ($language > 0) {
1367  $additionalParams = '&L=' . $language;
1368  }
1369  $onClick = BackendUtility::viewOnClick(
1370  $this->id,
1371  '',
1372  null,
1373  '#c' . $row['uid'],
1374  '',
1375  $additionalParams
1376  );
1377  } elseif (‪$table === 'pages' && $row[‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']] > 0) {
1378  // Link to a page translation needs uid of default language page as id
1379  $onClick = BackendUtility::viewOnClick(
1380  $row[‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']],
1381  '',
1382  null,
1383  '',
1384  '',
1385  '&L=' . (int)$row[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']]
1386  );
1387  } else {
1388  // Link to a page in the default language
1389  $onClick = BackendUtility::viewOnClick($row['uid']);
1390  }
1391  return $onClick;
1392  }
1393 
1403  protected function ‪isRowListingConditionFulfilled(‪$table, $row)
1404  {
1405  return true;
1406  }
1407 
1421  public function ‪renderListRow(‪$table, $row, $cc, $titleCol, $thumbsCol, $indent = 0)
1422  {
1423  if (!is_array($row)) {
1424  return '';
1425  }
1426  $rowOutput = '';
1427  $id_orig = null;
1428  // If in search mode, make sure the preview will show the correct page
1429  if ((string)$this->searchString !== '') {
1430  $id_orig = ‪$this->id;
1431  $this->id = $row['pid'];
1432  }
1433 
1434  $tagAttributes = [
1435  'class' => [],
1436  'data-table' => ‪$table,
1437  'title' => 'id=' . $row['uid'],
1438  ];
1439 
1440  // Add active class to record of current link
1441  if (
1442  isset($this->currentLink['tableNames'])
1443  && (int)$this->currentLink['uid'] === (int)$row['uid']
1444  && GeneralUtility::inList($this->currentLink['tableNames'], ‪$table)
1445  ) {
1446  $tagAttributes['class'][] = 'active';
1447  }
1448  // Add special classes for first and last row
1449  if ($cc == 1 && $indent == 0) {
1450  $tagAttributes['class'][] = 'firstcol';
1451  }
1452  if ($cc == $this->totalRowCount || $cc == $this->iLimit) {
1453  $tagAttributes['class'][] = 'lastcol';
1454  }
1455  // Overriding with versions background color if any:
1456  if (!empty($row['_CSSCLASS'])) {
1457  $tagAttributes['class'] = [$row['_CSSCLASS']];
1458  }
1459 
1460  $tagAttributes['class'][] = 't3js-entity';
1461 
1462  // Incr. counter.
1463  $this->counter++;
1464  // The icon with link
1465  $toolTip = BackendUtility::getRecordToolTip($row, ‪$table);
1466  $additionalStyle = $indent ? ' style="margin-left: ' . $indent . 'px;"' : '';
1467  $iconImg = '<span ' . $toolTip . ' ' . $additionalStyle . '>'
1468  . $this->iconFactory->getIconForRecord(‪$table, $row, Icon::SIZE_SMALL)->render()
1469  . '</span>';
1470  $theIcon = $this->clickMenuEnabled ? BackendUtility::wrapClickMenuOnIcon($iconImg, ‪$table, $row['uid']) : $iconImg;
1471  // Preparing and getting the data-array
1472  $theData = [];
1473  $localizationMarkerClass = '';
1474  foreach ($this->fieldArray as $fCol) {
1475  if ($fCol == $titleCol) {
1476  $recTitle = BackendUtility::getRecordTitle(‪$table, $row, false, true);
1477  $warning = '';
1478  // If the record is edit-locked by another user, we will show a little warning sign:
1479  $lockInfo = BackendUtility::isRecordLocked(‪$table, $row['uid']);
1480  if ($lockInfo) {
1481  $warning = '<span data-toggle="tooltip" data-placement="right" data-title="' . htmlspecialchars($lockInfo['msg']) . '">'
1482  . $this->iconFactory->getIcon('warning-in-use', Icon::SIZE_SMALL)->render() . '</span>';
1483  }
1484  $theData[$fCol] = $theData['__label'] = $warning . $this->‪linkWrapItems($table, $row['uid'], $recTitle, $row);
1485  // Render thumbnails, if:
1486  // - a thumbnail column exists
1487  // - there is content in it
1488  // - the thumbnail column is visible for the current type
1489  $type = 0;
1490  if (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['type'])) {
1491  $typeColumn = ‪$GLOBALS['TCA'][‪$table]['ctrl']['type'];
1492  $type = $row[$typeColumn];
1493  }
1494  // If current type doesn't exist, set it to 0 (or to 1 for historical reasons,
1495  // if 0 doesn't exist)
1496  if (!isset(‪$GLOBALS['TCA'][‪$table]['types'][$type])) {
1497  $type = isset(‪$GLOBALS['TCA'][‪$table]['types'][0]) ? 0 : 1;
1498  }
1499 
1500  $visibleColumns = $this->‪getVisibleColumns($GLOBALS['TCA'][‪$table], $type);
1501 
1502  if ($this->thumbs &&
1503  trim($row[$thumbsCol]) &&
1504  preg_match('/(^|(.*(;|,)?))' . $thumbsCol . '(((;|,).*)|$)/', $visibleColumns) === 1
1505  ) {
1506  $thumbCode = '<br />' . $this->‪thumbCode($row, ‪$table, $thumbsCol);
1507  $theData[$fCol] .= $thumbCode;
1508  $theData['__label'] .= $thumbCode;
1509  }
1510  if (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'])
1511  && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']] != 0
1512  && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] != 0
1513  ) {
1514  // It's a translated record with a language parent
1515  $localizationMarkerClass = ' localization';
1516  }
1517  } elseif ($fCol === 'pid') {
1518  $theData[$fCol] = $row[$fCol];
1519  } elseif ($fCol === '_PATH_') {
1520  $theData[$fCol] = $this->‪recPath($row['pid']);
1521  } elseif ($fCol === '_REF_') {
1522  $theData[$fCol] = $this->‪createReferenceHtml($table, $row['uid']);
1523  } elseif ($fCol === '_CONTROL_') {
1524  $theData[$fCol] = $this->‪makeControl($table, $row);
1525  } elseif ($fCol === '_CLIPBOARD_') {
1526  $theData[$fCol] = $this->‪makeClip($table, $row);
1527  } elseif ($fCol === '_LOCALIZATION_') {
1528  [$lC1, $lC2] = $this->‪makeLocalizationPanel($table, $row);
1529  $theData[$fCol] = $lC1;
1530  $theData[$fCol . 'b'] = '<div class="btn-group">' . $lC2 . '</div>';
1531  } elseif ($fCol === '_LOCALIZATION_b') {
1532  // deliberately empty
1533  } else {
1534  $pageId = ‪$table === 'pages' ? $row['uid'] : $row['pid'];
1535  $tmpProc = BackendUtility::getProcessedValueExtra(‪$table, $fCol, $row[$fCol], 100, $row['uid'], true, $pageId);
1536  $theData[$fCol] = $this->‪linkUrlMail(htmlspecialchars($tmpProc), $row[$fCol]);
1537  if ($this->csvOutput) {
1538  $row[$fCol] = BackendUtility::getProcessedValueExtra(‪$table, $fCol, $row[$fCol], 0, $row['uid']);
1539  }
1540  }
1541  }
1542  // Reset the ID if it was overwritten
1543  if ((string)$this->searchString !== '') {
1544  $this->id = $id_orig;
1545  }
1546  // Add row to CSV list:
1547  if ($this->csvOutput) {
1548  $hooks = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][__CLASS__]['customizeCsvRow'] ?? [];
1549  if (!empty($hooks)) {
1550  $hookParameters = [
1551  'databaseRow' => &$row,
1552  'tableName' => ‪$table,
1553  'pageId' => ‪$this->id
1554  ];
1555  foreach ($hooks as $hookFunction) {
1556  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
1557  }
1558  }
1559  $this->‪addToCSV($row);
1560  }
1561  // Add classes to table cells
1562  $this->addElement_tdCssClass[$titleCol] = 'col-title col-responsive' . $localizationMarkerClass;
1563  $this->addElement_tdCssClass['__label'] = $this->addElement_tdCssClass[$titleCol];
1564  $this->addElement_tdCssClass['_CONTROL_'] = 'col-control';
1565  if ($this->‪getModule()->MOD_SETTINGS['clipBoard']) {
1566  $this->addElement_tdCssClass['_CLIPBOARD_'] = 'col-clipboard';
1567  }
1568  $this->addElement_tdCssClass['_PATH_'] = 'col-path';
1569  $this->addElement_tdCssClass['_LOCALIZATION_'] = 'col-localizationa';
1570  $this->addElement_tdCssClass['_LOCALIZATION_b'] = 'col-localizationb';
1571  // Create element in table cells:
1572  $theData['uid'] = $row['uid'];
1573  if (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'])
1574  && isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'])
1575  ) {
1576  $theData['_l10nparent_'] = $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']];
1577  }
1578 
1579  $tagAttributes = array_map(
1580  function ($attributeValue) {
1581  if (is_array($attributeValue)) {
1582  return implode(' ', $attributeValue);
1583  }
1584  return $attributeValue;
1585  },
1586  $tagAttributes
1587  );
1588 
1589  $rowOutput .= $this->‪addElement(1, $theIcon, $theData, GeneralUtility::implodeAttributes($tagAttributes, true));
1590  // Finally, return table row element:
1591  return $rowOutput;
1592  }
1593 
1602  protected function ‪getReferenceCount($tableName, $uid)
1603  {
1604  if (!isset($this->referenceCount[$tableName][$uid])) {
1605  $referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
1606  $numberOfReferences = $referenceIndex->getNumberOfReferencedRecords($tableName, $uid);
1607  $this->referenceCount[$tableName][$uid] = $numberOfReferences;
1608  }
1609  return $this->referenceCount[$tableName][$uid];
1610  }
1611 
1622  public function ‪renderListHeader(‪$table, $currentIdList)
1623  {
1624  $tsConfig = BackendUtility::getPagesTSconfig($this->id);
1625  $tsConfigOfTable = is_array($tsConfig['TCEFORM.'][‪$table . '.']) ? $tsConfig['TCEFORM.'][‪$table . '.'] : null;
1626 
1627  $lang = $this->‪getLanguageService();
1628  // Init:
1629  $theData = [];
1630  $icon = '';
1632  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
1633  // Traverse the fields:
1634  foreach ($this->fieldArray as $fCol) {
1635  // Calculate users permissions to edit records in the table:
1636  $permsEdit = $this->calcPerms & (‪$table === 'pages' ? 2 : 16) && $this->‪overlayEditLockPermissions($table);
1637  switch ((string)$fCol) {
1638  case '_PATH_':
1639  // Path
1640  $theData[$fCol] = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels._PATH_')) . ']</i>';
1641  break;
1642  case '_REF_':
1643  // References
1644  $theData[$fCol] = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:c__REF_')) . ']</i>';
1645  break;
1646  case '_LOCALIZATION_':
1647  // Path
1648  $theData[$fCol] = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels._LOCALIZATION_')) . ']</i>';
1649  break;
1650  case '_LOCALIZATION_b':
1651  // Path
1652  $theData[$fCol] = htmlspecialchars($lang->getLL('Localize'));
1653  break;
1654  case '_CLIPBOARD_':
1655  if (!$this->‪getModule()->MOD_SETTINGS['clipBoard']) {
1656  break;
1657  }
1658  // Clipboard:
1659  $cells = [];
1660  // If there are elements on the clipboard for this table, and the parent page is not locked by editlock
1661  // then display the "paste into" icon:
1662  $elFromTable = $this->clipObj->elFromTable(‪$table);
1663  if (!empty($elFromTable) && $this->‪overlayEditLockPermissions($table)) {
1664  $href = htmlspecialchars($this->clipObj->pasteUrl(‪$table, $this->id));
1665  $confirmMessage = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable);
1666  $cells['pasteAfter'] = '<a class="btn btn-default t3js-modal-trigger"'
1667  . ' href="' . $href . '"'
1668  . ' title="' . htmlspecialchars($lang->getLL('clip_paste')) . '"'
1669  . ' data-title="' . htmlspecialchars($lang->getLL('clip_paste')) . '"'
1670  . ' data-content="' . htmlspecialchars($confirmMessage) . '"'
1671  . ' data-severity="warning">'
1672  . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render()
1673  . '</a>';
1674  }
1675  // If the numeric clipboard pads are enabled, display the control icons for that:
1676  if ($this->clipObj->current !== 'normal') {
1677  // The "select" link:
1678  $spriteIcon = $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL)->render();
1679  $cells['copyMarked'] = $this->‪linkClipboardHeaderIcon($spriteIcon, ‪$table, 'setCB', '', $lang->getLL('clip_selectMarked'));
1680  // The "edit marked" link:
1681  $editUri = (string)$uriBuilder->buildUriFromRoute('record_edit')
1682  . '&edit[' . ‪$table . '][{entityIdentifiers:editList}]=edit'
1683  . '&returnUrl={T3_THIS_LOCATION}';
1684  $cells['edit'] = '<a class="btn btn-default t3js-record-edit-multiple" href="#"'
1685  . ' data-uri="' . htmlspecialchars($editUri) . '"'
1686  . ' title="' . htmlspecialchars($lang->getLL('clip_editMarked')) . '">'
1687  . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
1688  // The "Delete marked" link:
1689  $cells['delete'] = $this->‪linkClipboardHeaderIcon(
1690  $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(),
1691  ‪$table,
1692  'delete',
1693  sprintf($lang->getLL('clip_deleteMarkedWarning'), $lang->sL(‪$GLOBALS['TCA'][‪$table]['ctrl']['title'])),
1694  $lang->getLL('clip_deleteMarked')
1695  );
1696  // The "Select all" link:
1697  $onClick = htmlspecialchars('checkOffCB(' . GeneralUtility::quoteJSvalue(implode(',', $this->CBnames)) . ', this); return false;');
1698  $cells['markAll'] = '<a class="btn btn-default" rel="" href="#" onclick="' . $onClick . '" title="'
1699  . htmlspecialchars($lang->getLL('clip_markRecords')) . '">'
1700  . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . '</a>';
1701  } else {
1702  $cells['empty'] = '';
1703  }
1704  /*
1705  * hook: renderListHeaderActions: Allows to change the clipboard icons of the Web>List table headers
1706  * usage: Above each listed table in Web>List a header row is shown.
1707  * This hook allows to modify the icons responsible for the clipboard functions
1708  * (shown above the clipboard checkboxes when a clipboard other than "Normal" is selected),
1709  * or other "Action" functions which perform operations on the listed records.
1710  */
1711  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? [] as $className) {
1712  $hookObject = GeneralUtility::makeInstance($className);
1713  if (!$hookObject instanceof RecordListHookInterface) {
1714  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567850);
1715  }
1716  $cells = $hookObject->renderListHeaderActions(‪$table, $currentIdList, $cells, $this);
1717  }
1718  $theData[$fCol] = '';
1719  if (isset($cells['edit']) && isset($cells['delete'])) {
1720  $theData[$fCol] .= '<div class="btn-group" role="group">' . $cells['edit'] . $cells['delete'] . '</div>';
1721  unset($cells['edit'], $cells['delete']);
1722  }
1723  $theData[$fCol] .= '<div class="btn-group" role="group">' . implode('', $cells) . '</div>';
1724  break;
1725  case '_CONTROL_':
1726  // Control panel:
1727  if ($this->‪isEditable($table)) {
1728  // If new records can be created on this page, add links:
1729  $permsAdditional = (‪$table === 'pages' ? 8 : 16);
1730  if ($this->calcPerms & $permsAdditional && $this->‪showNewRecLink($table)) {
1731  $spriteIcon = ‪$table === 'pages'
1732  ? $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)
1733  : $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL);
1734  if (‪$table === 'tt_content') {
1735  // If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
1736  $newContentElementWizard = BackendUtility::getPagesTSconfig($this->pageinfo['uid'])['mod.']['newContentElementWizard.']['override']
1737  ?? 'new_content_element_wizard';
1738  $url = (string)$uriBuilder->buildUriFromRoute(
1739  $newContentElementWizard,
1740  [
1741  'id' => $this->id,
1742  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
1743  ]
1744  );
1745  $icon = '<a href="' . htmlspecialchars($url) . '" '
1746  . 'data-title="' . htmlspecialchars($lang->getLL('new')) . '"'
1747  . 'class="btn btn-default t3js-toggle-new-content-element-wizard disabled"">'
1748  . $spriteIcon->render()
1749  . '</a>';
1750  } elseif (‪$table === 'pages') {
1751  $parameters = ['id' => ‪$this->id, 'pagesOnly' => 1, 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')];
1752  $href = (string)$uriBuilder->buildUriFromRoute('db_new', $parameters);
1753  $icon = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="' . htmlspecialchars($lang->getLL('new')) . '">'
1754  . $spriteIcon->render() . '</a>';
1755  } else {
1756  $params = '&edit[' . ‪$table . '][' . $this->id . ']=new';
1757  if ($table === 'pages') {
1758  $params .= '&overrideVals[pages][doktype]=' . (int)$this->pageRow['doktype'];
1759  }
1760  $icon = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1))
1761  . '" title="' . htmlspecialchars($lang->getLL('new')) . '">' . $spriteIcon->render() . '</a>';
1762  }
1763  }
1764  // If the table can be edited, add link for editing ALL SHOWN fields for all listed records:
1765  if ($permsEdit && $this->table && is_array($currentIdList)) {
1766  $entityIdentifiers = 'entityIdentifiers';
1767  if ($this->‪clipNumPane()) {
1768  $entityIdentifiers .= ':editList';
1769  }
1770  $editUri = (string)$uriBuilder->buildUriFromRoute('record_edit')
1771  . '&edit[' . ‪$table . '][{' . $entityIdentifiers . '}]=edit'
1772  . '&columnsOnly=' . implode(',', $this->fieldArray)
1773  . '&returnUrl={T3_THIS_LOCATION}';
1774  $icon .= '<a class="btn btn-default t3js-record-edit-multiple" href="#"'
1775  . ' data-uri="' . htmlspecialchars($editUri) . '"'
1776  . ' title="' . htmlspecialchars($lang->getLL('editShownColumns')) . '">'
1777  . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
1778  $icon = '<div class="btn-group" role="group">' . $icon . '</div>';
1779  }
1780  // Add an empty entry, so column count fits again after moving this into $icon
1781  $theData[$fCol] = '&nbsp;';
1782  } else {
1783  $icon = ‪$this->spaceIcon;
1784  }
1785  break;
1786  default:
1787  // Regular fields header:
1788  $theData[$fCol] = '';
1790  // Check if $fCol is really a field and get the label and remove the colons
1791  // at the end
1792  $sortLabel = BackendUtility::getItemLabel(‪$table, $fCol);
1793  if ($sortLabel !== null) {
1794  $sortLabel = rtrim(trim($lang->sL($sortLabel)), ':');
1795 
1796  // Field label
1797  $fieldTSConfig = [];
1798  if (isset($tsConfigOfTable[$fCol . '.'])
1799  && is_array($tsConfigOfTable[$fCol . '.'])
1800  ) {
1801  $fieldTSConfig = $tsConfigOfTable[$fCol . '.'];
1802  }
1803  if (!empty($fieldTSConfig['label'])) {
1804  $sortLabel = $lang->sL($fieldTSConfig['label']);
1805  }
1806  if (!empty($fieldTSConfig['label.'][$lang->lang])) {
1807  $sortLabel = $lang->sL($fieldTSConfig['label.'][$lang->lang]);
1808  }
1809  $sortLabel = htmlspecialchars($sortLabel);
1810  } else {
1811  // No TCA field, only output the $fCol variable with square brackets []
1812  $sortLabel = htmlspecialchars($fCol);
1813  $sortLabel = '<i>[' . rtrim(trim($sortLabel), ':') . ']</i>';
1814  }
1815 
1816  if ($this->table && is_array($currentIdList)) {
1817  // If the numeric clipboard pads are selected, show duplicate sorting link:
1818  if ($this->‪clipNumPane()) {
1819  $theData[$fCol] .= '<a class="btn btn-default" href="' . htmlspecialchars($this->‪listURL('', '-1') . '&duplicateField=' . $fCol)
1820  . '" title="' . htmlspecialchars($lang->getLL('clip_duplicates')) . '">'
1821  . $this->iconFactory->getIcon('actions-document-duplicates-select', Icon::SIZE_SMALL)->render() . '</a>';
1822  }
1823  // If the table can be edited, add link for editing THIS field for all
1824  // listed records:
1825  if ($this->‪isEditable($table) && $permsEdit && ‪$GLOBALS['TCA'][‪$table]['columns'][$fCol]) {
1826  $entityIdentifiers = 'entityIdentifiers';
1827  if ($this->‪clipNumPane()) {
1828  $entityIdentifiers .= ':editList';
1829  }
1830  $editUri = (string)$uriBuilder->buildUriFromRoute('record_edit')
1831  . '&edit[' . ‪$table . '][{' . $entityIdentifiers . '}]=edit'
1832  . '&columnsOnly=' . $fCol
1833  . '&returnUrl={T3_THIS_LOCATION}';
1834  $iTitle = sprintf($lang->getLL('editThisColumn'), $sortLabel);
1835  $theData[$fCol] .= '<a class="btn btn-default t3js-record-edit-multiple" href="#"'
1836  . ' data-uri="' . htmlspecialchars($editUri) . '"'
1837  . ' title="' . htmlspecialchars($iTitle) . '">'
1838  . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
1839  }
1840  if (strlen($theData[$fCol]) > 0) {
1841  $theData[$fCol] = '<div class="btn-group" role="group">' . $theData[$fCol] . '</div> ';
1842  }
1843  }
1844  $theData[$fCol] .= $this->‪addSortLink($sortLabel, $fCol, ‪$table);
1845  }
1846  }
1847  /*
1848  * hook: renderListHeader: Allows to change the contents of columns/cells of the Web>List table headers
1849  * usage: Above each listed table in Web>List a header row is shown.
1850  * Containing the labels of all shown fields and additional icons to create new records for this
1851  * table or perform special clipboard tasks like mark and copy all listed records to clipboard, etc.
1852  */
1853  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? [] as $className) {
1854  $hookObject = GeneralUtility::makeInstance($className);
1855  if (!$hookObject instanceof RecordListHookInterface) {
1856  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567855);
1857  }
1858  $theData = $hookObject->renderListHeader(‪$table, $currentIdList, $theData, $this);
1859  }
1860 
1861  // Create and return header table row:
1862  return '<thead>' . $this->‪addElement(1, $icon, $theData, '', '', '', 'th') . '</thead>';
1863  }
1864 
1871  protected function ‪getPointerForPage($page)
1872  {
1873  return ($page - 1) * ‪$this->iLimit;
1874  }
1875 
1882  protected function ‪renderListNavigation($renderPart = 'top')
1883  {
1884  $totalPages = ceil($this->totalItems / $this->iLimit);
1885  // Show page selector if not all records fit into one page
1886  if ($totalPages <= 1) {
1887  return '';
1888  }
1889  ‪$content = '';
1890  $listURL = $this->‪listURL('', $this->table, 'firstElementNumber');
1891  // 1 = first page
1892  // 0 = first element
1893  $currentPage = floor($this->firstElementNumber / $this->iLimit) + 1;
1894  // Compile first, previous, next, last and refresh buttons
1895  if ($currentPage > 1) {
1896  $labelFirst = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:first'));
1897  $labelPrevious = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:previous'));
1898  $first = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage(1) . '" title="' . $labelFirst . '">'
1899  . $this->iconFactory->getIcon('actions-view-paging-first', Icon::SIZE_SMALL)->render() . '</a></li>';
1900  $previous = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage($currentPage - 1) . '" title="' . $labelPrevious . '">'
1901  . $this->iconFactory->getIcon('actions-view-paging-previous', Icon::SIZE_SMALL)->render() . '</a></li>';
1902  } else {
1903  $first = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-first', Icon::SIZE_SMALL)->render() . '</span></li>';
1904  $previous = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-previous', Icon::SIZE_SMALL)->render() . '</span></li>';
1905  }
1906  if ($currentPage < $totalPages) {
1907  $labelNext = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:next'));
1908  $labelLast = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:last'));
1909  $next = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage($currentPage + 1) . '" title="' . $labelNext . '">'
1910  . $this->iconFactory->getIcon('actions-view-paging-next', Icon::SIZE_SMALL)->render() . '</a></li>';
1911  $last = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage($totalPages) . '" title="' . $labelLast . '">'
1912  . $this->iconFactory->getIcon('actions-view-paging-last', Icon::SIZE_SMALL)->render() . '</a></li>';
1913  } else {
1914  $next = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-next', Icon::SIZE_SMALL)->render() . '</span></li>';
1915  $last = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-last', Icon::SIZE_SMALL)->render() . '</span></li>';
1916  }
1917  $reload = '<li><a href="#" onclick="document.dblistForm.action=' . GeneralUtility::quoteJSvalue($listURL
1918  . '&pointer=') . '+calculatePointer(document.getElementById(' . GeneralUtility::quoteJSvalue('jumpPage-' . $renderPart)
1919  . ').value); document.dblistForm.submit(); return true;" title="'
1920  . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:reload')) . '">'
1921  . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . '</a></li>';
1922  if ($renderPart === 'top') {
1923  // Add js to traverse a page select input to a pointer value
1924  ‪$content = '
1925 <script type="text/javascript">
1926 /*<![CDATA[*/
1927  function calculatePointer(page) {
1928  if (page > ' . $totalPages . ') {
1929  page = ' . $totalPages . ';
1930  }
1931  if (page < 1) {
1932  page = 1;
1933  }
1934  return (page - 1) * ' . $this->iLimit . ';
1935  }
1936 /*]]>*/
1937 </script>
1938 ';
1939  }
1940  $pageNumberInput = '
1941  <input type="number" min="1" max="' . $totalPages . '" value="' . $currentPage . '" size="3" class="form-control input-sm paginator-input" id="jumpPage-' . $renderPart . '" name="jumpPage-'
1942  . $renderPart . '" onkeyup="if (event.keyCode == 13) { document.dblistForm.action=' . htmlspecialchars(GeneralUtility::quoteJSvalue($listURL . '&pointer='))
1943  . '+calculatePointer(this.value); document.dblistForm.submit(); } return true;" />
1944  ';
1945  $pageIndicatorText = sprintf(
1946  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:pageIndicator'),
1947  $pageNumberInput,
1948  $totalPages
1949  );
1950  $pageIndicator = '<li><span>' . $pageIndicatorText . '</span></li>';
1951  if ($this->totalItems > $this->firstElementNumber + $this->iLimit) {
1952  $lastElementNumber = $this->firstElementNumber + ‪$this->iLimit;
1953  } else {
1954  $lastElementNumber = ‪$this->totalItems;
1955  }
1956  $rangeIndicator = '<li><span>' . sprintf(
1957  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:rangeIndicator'),
1958  $this->firstElementNumber + 1,
1959  $lastElementNumber
1960  ) . '</span></li>';
1961 
1962  $titleColumn = $this->fieldArray[0];
1963  $data = [
1964  $titleColumn => ‪$content . '
1965  <nav class="pagination-wrap">
1966  <ul class="pagination pagination-block">
1967  ' . $first . '
1968  ' . $previous . '
1969  ' . $rangeIndicator . '
1970  ' . $pageIndicator . '
1971  ' . $next . '
1972  ' . $last . '
1973  ' . $reload . '
1974  </ul>
1975  </nav>
1976  '
1977  ];
1978  return $this->‪addElement(1, '', $data);
1979  }
1980 
1981  /*********************************
1982  *
1983  * Rendering of various elements
1984  *
1985  *********************************/
1986 
1995  public function ‪makeControl(‪$table, $row)
1996  {
1997  $backendUser = $this->‪getBackendUserAuthentication();
1998  $userTsConfig = $backendUser->getTSConfig();
1999  $module = $this->‪getModule();
2000  $rowUid = $row['uid'];
2001  if (ExtensionManagementUtility::isLoaded('workspaces') && isset($row['_ORIG_uid'])) {
2002  $rowUid = $row['_ORIG_uid'];
2003  }
2004  $cells = [
2005  'primary' => [],
2006  'secondary' => []
2007  ];
2008  // Enables to hide the move elements for localized records - doesn't make much sense to perform these options for them
2009  // For page translations these icons should never be shown
2010  $isL10nOverlay = ‪$table === 'pages' && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] != 0;
2011  if (‪$table === 'pages') {
2012  // If the listed table is 'pages' we have to request the permission settings for each page.
2013  $localCalcPerms = $backendUser->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
2014  } else {
2015  // If the listed table is not 'pages' we have to request the permission settings from the parent page
2016  $localCalcPerms = $backendUser->calcPerms(BackendUtility::getRecord('pages', $row['pid']));
2017  }
2018  $permsEdit = ‪$table === 'pages'
2019  && $backendUser->checkLanguageAccess((int)$row[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']])
2020  && $localCalcPerms & Permission::PAGE_EDIT
2021  || ‪$table !== 'pages'
2022  && $localCalcPerms & Permission::CONTENT_EDIT
2023  && $backendUser->recordEditAccessInternals(‪$table, $row);
2024  $permsEdit = $this->‪overlayEditLockPermissions($table, $row, $permsEdit);
2025  // "Show" link (only pages and tt_content elements)
2027  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
2028 
2029  if (‪$table === 'pages' || ‪$table === 'tt_content') {
2030  $onClick = $this->‪getOnClickForRow($table, $row);
2031  $viewAction = '<a class="btn btn-default" href="#" onclick="'
2032  . htmlspecialchars(
2033  $onClick
2034  ) . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage')) . '">';
2035  if (‪$table === 'pages') {
2036  $viewAction .= $this->iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL)->render();
2037  } else {
2038  $viewAction .= $this->iconFactory->getIcon('actions-view', Icon::SIZE_SMALL)->render();
2039  }
2040  $viewAction .= '</a>';
2041  $this->‪addActionToCellGroup($cells, $viewAction, 'view');
2042  }
2043  // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
2044  if ($permsEdit && $this->‪isEditable($table)) {
2045  $params = '&edit[' . ‪$table . '][' . $row['uid'] . ']=edit';
2046  $iconIdentifier = 'actions-open';
2047  if (‪$table === 'pages') {
2048  // Disallow manual adjustment of the language field for pages
2049  $params .= '&overrideVals[pages][sys_language_uid]=' . (int)$row[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']];
2050  $iconIdentifier = 'actions-page-open';
2051  }
2052  $editAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1))
2053  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('edit')) . '">' . $this->iconFactory->getIcon($iconIdentifier, Icon::SIZE_SMALL)->render() . '</a>';
2054  } else {
2055  $editAction = ‪$this->spaceIcon;
2056  }
2057  $this->‪addActionToCellGroup($cells, $editAction, 'edit');
2058  // "Info": (All records)
2059  $onClick = 'top.TYPO3.InfoWindow.showItem(' . GeneralUtility::quoteJSvalue(‪$table) . ', ' . (int)$row['uid'] . '); return false;';
2060  $viewBigAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('showInfo')) . '">'
2061  . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>';
2062  $this->‪addActionToCellGroup($cells, $viewBigAction, 'viewBig');
2063  // "Move" wizard link for pages/tt_content elements:
2064  if ($permsEdit && (‪$table === 'tt_content' || ‪$table === 'pages') && $this->‪isEditable($table)) {
2065  if ($isL10nOverlay) {
2066  $moveAction = ‪$this->spaceIcon;
2067  } else {
2068  $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue((string)$uriBuilder->buildUriFromRoute('move_element') . '&table=' . ‪$table . '&uid=' . $row['uid']) . ');';
2069  $linkTitleLL = htmlspecialchars($this->‪getLanguageService()->getLL('move_' . (‪$table === 'tt_content' ? 'record' : 'page')));
2070  $icon = (‪$table === 'pages' ? $this->iconFactory->getIcon('actions-page-move', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL));
2071  $moveAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $linkTitleLL . '">' . $icon->render() . '</a>';
2072  }
2073  $this->‪addActionToCellGroup($cells, $moveAction, 'move');
2074  }
2075  // If the table is NOT a read-only table, then show these links:
2076  if ($this->‪isEditable($table)) {
2077  // "Revert" link (history/undo)
2078  if ((bool)\trim($userTsConfig['options.']['showHistory.'][‪$table] ?? $userTsConfig['options.']['showHistory'] ?? '1')) {
2079  $moduleUrl = (string)$uriBuilder->buildUriFromRoute('record_history', ['element' => ‪$table . ':' . $row['uid']]);
2080  $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue($moduleUrl) . ',\'#latest\');';
2081  $historyAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($onClick) . '" title="'
2082  . htmlspecialchars($this->‪getLanguageService()->getLL('history')) . '">'
2083  . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render() . '</a>';
2084  $this->‪addActionToCellGroup($cells, $historyAction, 'history');
2085  }
2086  // "Edit Perms" link:
2087  if (‪$table === 'pages' && $backendUser->check('modules', 'system_BeuserTxPermission') && ExtensionManagementUtility::isLoaded('beuser')) {
2088  if ($isL10nOverlay) {
2089  $permsAction = ‪$this->spaceIcon;
2090  } else {
2091  $href = (string)$uriBuilder->buildUriFromRoute('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&tx_beuser_system_beusertxpermission[action]=edit' . $this->‪makeReturnUrl();
2092  $permsAction = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="'
2093  . htmlspecialchars($this->‪getLanguageService()->getLL('permissions')) . '">'
2094  . $this->iconFactory->getIcon('actions-lock', Icon::SIZE_SMALL)->render() . '</a>';
2095  }
2096  $this->‪addActionToCellGroup($cells, $permsAction, 'perms');
2097  }
2098  // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row
2099  // or if default values can depend on previous record):
2100  if ((‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] || ‪$GLOBALS['TCA'][‪$table]['ctrl']['useColumnsForDefaultValues']) && $permsEdit) {
2101  if (‪$table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT || ‪$table === 'pages' && $this->calcPerms & Permission::PAGE_NEW) {
2102  if (‪$table === 'pages' && $isL10nOverlay) {
2103  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'new');
2104  } elseif ($this->‪showNewRecLink($table)) {
2105  $params = '&edit[' . ‪$table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
2106  $icon = (‪$table === 'pages' ? $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL));
2107  $titleLabel = 'new';
2108  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby']) {
2109  $titleLabel .= (‪$table === 'pages' ? 'Page' : 'Record');
2110  }
2111  $newAction = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1))
2112  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL($titleLabel)) . '">'
2113  . $icon->render() . '</a>';
2114  $this->‪addActionToCellGroup($cells, $newAction, 'new');
2115  }
2116  }
2117  }
2118  // "Up/Down" links
2119  if ($permsEdit && ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) {
2120  if (!$isL10nOverlay && isset($this->currentTable['prev'][$row['uid']])) {
2121  // Up
2122  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']];
2123  $moveUpAction = '<a class="btn btn-default" href="#" onclick="'
2124  . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');')
2125  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('moveUp')) . '">'
2126  . $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render() . '</a>';
2127  } else {
2128  $moveUpAction = ‪$this->spaceIcon;
2129  }
2130  $this->‪addActionToCellGroup($cells, $moveUpAction, 'moveUp');
2131 
2132  if (!$isL10nOverlay && $this->currentTable['next'][$row['uid']]) {
2133  // Down
2134  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']];
2135  $moveDownAction = '<a class="btn btn-default" href="#" onclick="'
2136  . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');')
2137  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('moveDown')) . '">'
2138  . $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render() . '</a>';
2139  } else {
2140  $moveDownAction = ‪$this->spaceIcon;
2141  }
2142  $this->‪addActionToCellGroup($cells, $moveDownAction, 'moveDown');
2143  }
2144  // "Hide/Unhide" links:
2145  $hiddenField = ‪$GLOBALS['TCA'][‪$table]['ctrl']['enablecolumns']['disabled'];
2146 
2147  if (
2148  !empty(‪$GLOBALS['TCA'][‪$table]['columns'][$hiddenField])
2149  && (empty(‪$GLOBALS['TCA'][‪$table]['columns'][$hiddenField]['exclude'])
2150  || $backendUser->check('non_exclude_fields', ‪$table . ':' . $hiddenField))
2151  ) {
2152  if (!$permsEdit || $this->‪isRecordCurrentBackendUser($table, $row)) {
2153  $hideAction = ‪$this->spaceIcon;
2154  } else {
2155  $hideTitle = htmlspecialchars($this->‪getLanguageService()->getLL('hide' . (‪$table === 'pages' ? 'Page' : '')));
2156  $unhideTitle = htmlspecialchars($this->‪getLanguageService()->getLL('unHide' . (‪$table === 'pages' ? 'Page' : '')));
2157  if ($row[$hiddenField]) {
2158  $params = 'data[' . ‪$table . '][' . $rowUid . '][' . $hiddenField . ']=0';
2159  $hideAction = '<a class="btn btn-default t3js-record-hide" data-state="hidden" href="#"'
2160  . ' data-params="' . htmlspecialchars($params) . '"'
2161  . ' title="' . $unhideTitle . '"'
2162  . ' data-toggle-title="' . $hideTitle . '">'
2163  . $this->iconFactory->getIcon('actions-edit-unhide', Icon::SIZE_SMALL)->render() . '</a>';
2164  } else {
2165  $params = 'data[' . ‪$table . '][' . $rowUid . '][' . $hiddenField . ']=1';
2166  $hideAction = '<a class="btn btn-default t3js-record-hide" data-state="visible" href="#"'
2167  . ' data-params="' . htmlspecialchars($params) . '"'
2168  . ' title="' . $hideTitle . '"'
2169  . ' data-toggle-title="' . $unhideTitle . '">'
2170  . $this->iconFactory->getIcon('actions-edit-hide', Icon::SIZE_SMALL)->render() . '</a>';
2171  }
2172  }
2173  $this->‪addActionToCellGroup($cells, $hideAction, 'hide');
2174  }
2175  // "Delete" link:
2176  $disableDelete = (bool)\trim($userTsConfig['options.']['disableDelete.'][‪$table] ?? $userTsConfig['options.']['disableDelete'] ?? '0');
2177  if ($permsEdit && !$disableDelete && (‪$table === 'pages' && $localCalcPerms & Permission::PAGE_DELETE || ‪$table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT)) {
2178  // Check if the record version is in "deleted" state, because that will switch the action to "restore"
2179  if ($backendUser->workspace > 0 && isset($row['t3ver_state']) && VersionState::cast($row['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
2180  $actionName = 'restore';
2181  $refCountMsg = '';
2182  } else {
2183  $actionName = 'delete';
2184  $refCountMsg = BackendUtility::referenceCount(
2185  ‪$table,
2186  $row['uid'],
2187  ' ' . $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.referencesToRecord'),
2188  $this->‪getReferenceCount($table, $row['uid'])
2189  ) . BackendUtility::translationCount(
2190  ‪$table,
2191  $row['uid'],
2192  ' ' . $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.translationsOfRecord')
2193  );
2194  }
2195 
2196  if ($this->‪isRecordCurrentBackendUser($table, $row)) {
2197  $deleteAction = ‪$this->spaceIcon;
2198  } else {
2199  $title = BackendUtility::getRecordTitle(‪$table, $row);
2200  $warningText = $this->‪getLanguageService()->‪getLL($actionName . 'Warning') . ' "' . $title . '" ' . '[' . ‪$table . ':' . $row['uid'] . ']' . $refCountMsg;
2201 
2202  $params = 'cmd[' . ‪$table . '][' . $row['uid'] . '][delete]=1';
2203  $icon = $this->iconFactory->getIcon('actions-edit-' . $actionName, Icon::SIZE_SMALL)->render();
2204  $linkTitle = htmlspecialchars($this->‪getLanguageService()->getLL($actionName));
2205  $l10nParentField = ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'] ?? '';
2206  $deleteAction = '<a class="btn btn-default t3js-record-delete" href="#" '
2207  . ' data-button-ok-text="' . htmlspecialchars($linkTitle) . '"'
2208  . ' data-l10parent="' . ($l10nParentField ? htmlspecialchars($row[$l10nParentField]) : '') . '"'
2209  . ' data-params="' . htmlspecialchars($params) . '" data-title="' . htmlspecialchars($title) . '"'
2210  . ' data-message="' . htmlspecialchars($warningText) . '" title="' . $linkTitle . '"'
2211  . '>' . $icon . '</a>';
2212  }
2213  } else {
2214  $deleteAction = ‪$this->spaceIcon;
2215  }
2216  $this->‪addActionToCellGroup($cells, $deleteAction, 'delete');
2217  // "Levels" links: Moving pages into new levels...
2218  if ($permsEdit && ‪$table === 'pages' && !$this->searchLevels) {
2219  // Up (Paste as the page right after the current parent page)
2220  if ($this->calcPerms & Permission::PAGE_NEW) {
2221  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . -‪$this->id;
2222  $moveLeftAction = '<a class="btn btn-default" href="#" onclick="'
2223  . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');')
2224  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('prevLevel')) . '">'
2225  . $this->iconFactory->getIcon('actions-move-left', Icon::SIZE_SMALL)->render() . '</a>';
2226  $this->‪addActionToCellGroup($cells, $isL10nOverlay ? $this->spaceIcon : $moveLeftAction, 'moveLeft');
2227  }
2228  // Down (Paste as subpage to the page right above)
2229  if (!$isL10nOverlay && $this->currentTable['prevUid'][$row['uid']]) {
2230  $localCalcPerms = $backendUser->calcPerms(BackendUtility::getRecord('pages', $this->currentTable['prevUid'][$row['uid']]));
2231  if ($localCalcPerms & Permission::PAGE_NEW) {
2232  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']];
2233  $moveRightAction = '<a class="btn btn-default" href="#" onclick="'
2234  . htmlspecialchars('return jumpToUrl(' . BackendUtility::getLinkToDataHandlerAction($params, -1) . ');')
2235  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('nextLevel')) . '">'
2236  . $this->iconFactory->getIcon('actions-move-right', Icon::SIZE_SMALL)->render() . '</a>';
2237  } else {
2238  $moveRightAction = ‪$this->spaceIcon;
2239  }
2240  } else {
2241  $moveRightAction = ‪$this->spaceIcon;
2242  }
2243  $this->‪addActionToCellGroup($cells, $moveRightAction, 'moveRight');
2244  }
2245  }
2246  /*
2247  * hook: recStatInfoHooks: Allows to insert HTML before record icons on various places
2248  */
2249  $hooks = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] ?? [];
2250  if (!empty($hooks)) {
2251  $stat = '';
2252  $_params = [‪$table, $row['uid']];
2253  foreach ($hooks as $_funcRef) {
2254  $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2255  }
2256  $this->‪addActionToCellGroup($cells, $stat, 'stat');
2257  }
2258  /*
2259  * hook: makeControl: Allows to change control icons of records in list-module
2260  * usage: This hook method gets passed the current $cells array as third parameter.
2261  * This array contains values for the icons/actions generated for each record in Web>List.
2262  * Each array entry is accessible by an index-key.
2263  * The order of the icons is depending on the order of those array entries.
2264  */
2265  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? false)) {
2266  // for compatibility reason, we move all icons to the rootlevel
2267  // before calling the hooks
2268  foreach ($cells as $section => $actions) {
2269  foreach ($actions as $actionKey => $action) {
2270  $cells[$actionKey] = $action;
2271  }
2272  }
2273  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $className) {
2274  $hookObject = GeneralUtility::makeInstance($className);
2275  if (!$hookObject instanceof RecordListHookInterface) {
2276  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567840);
2277  }
2278  $cells = $hookObject->makeControl(‪$table, $row, $cells, $this);
2279  }
2280  // now sort icons again into primary and secondary sections
2281  // after all hooks are processed
2282  $hookCells = $cells;
2283  foreach ($hookCells as $key => $value) {
2284  if ($key === 'primary' || $key === 'secondary') {
2285  continue;
2286  }
2287  $this->‪addActionToCellGroup($cells, $value, $key);
2288  }
2289  }
2290  ‪$output = '<!-- CONTROL PANEL: ' . ‪$table . ':' . $row['uid'] . ' -->';
2291  foreach ($cells as $classification => $actions) {
2292  $visibilityClass = ($classification !== 'primary' && !$module->MOD_SETTINGS['bigControlPanel'] ? 'collapsed' : 'expanded');
2293  if ($visibilityClass === 'collapsed') {
2294  $cellOutput = '';
2295  foreach ($actions as $action) {
2296  $cellOutput .= $action;
2297  }
2298  ‪$output .= ' <div class="btn-group">' .
2299  '<span id="actions_' . ‪$table . '_' . $row['uid'] . '" class="btn-group collapse collapse-horizontal width">' . $cellOutput . '</span>' .
2300  '<a href="#actions_' . ‪$table . '_' . $row['uid'] . '" class="btn btn-default collapsed" data-toggle="collapse" aria-expanded="false"><span class="t3-icon fa fa-ellipsis-h"></span></a>' .
2301  '</div>';
2302  } else {
2303  ‪$output .= ' <div class="btn-group" role="group">' . implode('', $actions) . '</div>';
2304  }
2305  }
2306  return ‪$output;
2307  }
2308 
2317  public function ‪makeClip(‪$table, $row)
2318  {
2319  // Return blank, if disabled:
2320  if (!$this->‪getModule()->MOD_SETTINGS['clipBoard']) {
2321  return '';
2322  }
2323  if (!$this->‪isEditable($table)) {
2324  return '';
2325  }
2326  $cells = [];
2327  $cells['pasteAfter'] = ($cells['pasteInto'] = ‪$this->spaceIcon);
2328  // Enables to hide the copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them
2329  // For page translations these icons should never be shown
2330  $isL10nOverlay = ‪$table === 'pages' && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] != 0;
2331  // Return blank, if disabled:
2332  // Whether a numeric clipboard pad is active or the normal pad we will see different content of the panel:
2333  // For the "Normal" pad:
2334  if ($this->clipObj->current === 'normal') {
2335  // Show copy/cut icons:
2336  $isSel = (string)$this->clipObj->isSelected(‪$table, $row['uid']);
2337  if ($isL10nOverlay || !$this->‪overlayEditLockPermissions($table, $row)) {
2338  $cells['copy'] = ‪$this->spaceIcon;
2339  $cells['cut'] = ‪$this->spaceIcon;
2340  } else {
2341  $copyIcon = $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL);
2342  $cutIcon = $this->iconFactory->getIcon('actions-edit-cut', Icon::SIZE_SMALL);
2343 
2344  if ($isSel === 'copy') {
2345  $copyIcon = $this->iconFactory->getIcon('actions-edit-copy-release', Icon::SIZE_SMALL);
2346  } elseif ($isSel === 'cut') {
2347  $cutIcon = $this->iconFactory->getIcon('actions-edit-cut-release', Icon::SIZE_SMALL);
2348  }
2349 
2350  $cells['copy'] = '<a class="btn btn-default" href="#" onclick="'
2351  . htmlspecialchars('return jumpSelf(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB(
2352  ‪$table,
2353  $row['uid'],
2354  1,
2355  $isSel === 'copy',
2356  ['returnUrl' => '']
2357  )) . ');')
2358  . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.copy')) . '">'
2359  . $copyIcon->render() . '</a>';
2360 
2361  // Check permission to cut page or content
2362  if (‪$table === 'pages') {
2363  $localCalcPerms = $this->‪getBackendUserAuthentication()->‪calcPerms(BackendUtility::getRecord('pages', $row['uid']));
2364  $permsEdit = $localCalcPerms & Permission::PAGE_EDIT;
2365  } else {
2366  $permsEdit = $this->calcPerms & Permission::CONTENT_EDIT;
2367  }
2368  $permsEdit = $this->‪overlayEditLockPermissions($table, $row, $permsEdit);
2369 
2370  // If the listed table is 'pages' we have to request the permission settings for each page:
2371  if (‪$table === 'pages') {
2372  if ($permsEdit) {
2373  $cells['cut'] = '<a class="btn btn-default" href="#" onclick="'
2374  . htmlspecialchars('return jumpSelf(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB(
2375  ‪$table,
2376  $row['uid'],
2377  0,
2378  $isSel === 'cut',
2379  ['returnUrl' => '']
2380  )) . ');')
2381  . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.cut')) . '">'
2382  . $cutIcon->render() . '</a>';
2383  } else {
2384  $cells['cut'] = ‪$this->spaceIcon;
2385  }
2386  } else {
2387  if ($this->calcPerms & Permission::CONTENT_EDIT) {
2388  $cells['cut'] = '<a class="btn btn-default" href="#" onclick="'
2389  . htmlspecialchars('return jumpSelf(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB(
2390  ‪$table,
2391  $row['uid'],
2392  0,
2393  $isSel === 'cut',
2394  ['returnUrl' => '']
2395  )) . ');')
2396  . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.cut')) . '">'
2397  . $cutIcon->render() . '</a>';
2398  } else {
2399  $cells['cut'] = ‪$this->spaceIcon;
2400  }
2401  }
2402  }
2403  } else {
2404  // For the numeric clipboard pads (showing checkboxes where one can select elements on/off)
2405  // Setting name of the element in ->CBnames array:
2406  $n = ‪$table . '|' . $row['uid'];
2407  $this->CBnames[] = $n;
2408  // Check if the current element is selected and if so, prepare to set the checkbox as selected:
2409  $checked = $this->clipObj->isSelected(‪$table, $row['uid']) ? 'checked="checked" ' : '';
2410  // If the "duplicateField" value is set then select all elements which are duplicates...
2411  if ($this->duplicateField && isset($row[$this->duplicateField])) {
2412  $checked = '';
2413  if (in_array($row[$this->duplicateField], $this->duplicateStack)) {
2414  $checked = 'checked="checked" ';
2415  }
2416  $this->duplicateStack[] = $row[‪$this->duplicateField];
2417  }
2418  // Adding the checkbox to the panel:
2419  $cells['select'] = $isL10nOverlay
2420  ? $this->spaceIcon
2421  : '<input type="hidden" name="CBH[' . $n . ']" value="0" /><label class="btn btn-default btn-checkbox"><input type="checkbox"'
2422  . ' name="CBC[' . $n . ']" value="1" ' . $checked . '/><span class="t3-icon fa"></span></label>';
2423  }
2424  // Now, looking for selected elements from the current table:
2425  $elFromTable = $this->clipObj->elFromTable(‪$table);
2426  if (!empty($elFromTable) && ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby']) {
2427  // IF elements are found, they can be individually ordered and are not locked by editlock, then add a "paste after" icon:
2428  $cells['pasteAfter'] = $isL10nOverlay || !$this->‪overlayEditLockPermissions($table, $row)
2429  ? $this->spaceIcon
2430  : '<a class="btn btn-default t3js-modal-trigger"'
2431  . ' href="' . htmlspecialchars($this->clipObj->pasteUrl(‪$table, -$row['uid'])) . '"'
2432  . ' title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteAfter')) . '"'
2433  . ' data-title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteAfter')) . '"'
2434  . ' data-content="' . htmlspecialchars($this->clipObj->confirmMsgText(‪$table, $row, 'after', $elFromTable)) . '"'
2435  . ' data-severity="warning">'
2436  . $this->iconFactory->getIcon('actions-document-paste-after', Icon::SIZE_SMALL)->render() . '</a>';
2437  }
2438  // Now, looking for elements in general:
2439  $elFromTable = $this->clipObj->elFromTable('');
2440  if (‪$table === 'pages' && !$isL10nOverlay && !empty($elFromTable)) {
2441  $cells['pasteInto'] = '<a class="btn btn-default t3js-modal-trigger"'
2442  . ' href="' . htmlspecialchars($this->clipObj->pasteUrl('', $row['uid'])) . '"'
2443  . ' title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteInto')) . '"'
2444  . ' data-title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteInto')) . '"'
2445  . ' data-content="' . htmlspecialchars($this->clipObj->confirmMsgText(‪$table, $row, 'into', $elFromTable)) . '"'
2446  . ' data-severity="warning">'
2447  . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '</a>';
2448  }
2449  /*
2450  * hook: makeClip: Allows to change clip-icons of records in list-module
2451  * usage: This hook method gets passed the current $cells array as third parameter.
2452  * This array contains values for the clipboard icons generated for each record in Web>List.
2453  * Each array entry is accessible by an index-key.
2454  * The order of the icons is depending on the order of those array entries.
2455  */
2456  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? [] as $className) {
2457  $hookObject = GeneralUtility::makeInstance($className);
2458  if (!$hookObject instanceof RecordListHookInterface) {
2459  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567845);
2460  }
2461  $cells = $hookObject->makeClip(‪$table, $row, $cells, $this);
2462  }
2463  return '<div class="btn-group" role="group">' . implode('', $cells) . '</div>';
2464  }
2465 
2474  protected function ‪createReferenceHtml($tableName, $uid)
2475  {
2476  ‪$referenceCount = GeneralUtility::makeInstance(ConnectionPool::class)
2477  ->getConnectionForTable('sys_refindex')
2478  ->count(
2479  '*',
2480  'sys_refindex',
2481  [
2482  'ref_table' => $tableName,
2483  'ref_uid' => (int)$uid,
2484  'deleted' => 0,
2485  ]
2486  );
2487 
2488  return $this->‪generateReferenceToolTip(
2490  GeneralUtility::quoteJSvalue($tableName) . ', ' . GeneralUtility::quoteJSvalue($uid)
2491  );
2492  }
2493 
2501  public function ‪makeLocalizationPanel(‪$table, $row)
2502  {
2503  $out = [
2504  0 => '',
2505  1 => ''
2506  ];
2507  // Reset translations
2508  $this->translations = [];
2509 
2510  // Language title and icon:
2511  $out[0] = $this->‪languageFlag($row[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']]);
2512  // Guard clause so we can quickly return if a record is localized to "all languages"
2513  // It should only be possible to localize a record off default (uid 0)
2514  // Reasoning: The Parent is for ALL languages... why overlay with a localization?
2515  if ((int)$row[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']] === -1) {
2516  return $out;
2517  }
2518 
2519  ‪$translations = $this->translateTools->translationInfo(‪$table, $row['uid'], 0, $row, $this->selFieldList);
2520  if (is_array(‪$translations)) {
2521  $this->translations = ‪$translations['translations'];
2522  // Traverse page translations and add icon for each language that does NOT yet exist and is included in site configuration:
2523  $lNew = '';
2524  foreach ($this->pageOverlays as $lUid_OnPage => $lsysRec) {
2525  if (isset($this->systemLanguagesOnPage[$lUid_OnPage]) && $this->‪isEditable($table) && !isset(‪$translations['translations'][$lUid_OnPage]) && $this->‪getBackendUserAuthentication()->checkLanguageAccess($lUid_OnPage)) {
2526  $url = $this->‪listURL();
2527  $href = BackendUtility::getLinkToDataHandlerAction(
2528  '&cmd[' . ‪$table . '][' . $row['uid'] . '][localize]=' . $lUid_OnPage,
2529  $url . '&justLocalized=' . rawurlencode(‪$table . ':' . $row['uid'] . ':' . $lUid_OnPage)
2530  );
2531  $language = BackendUtility::getRecord('sys_language', $lUid_OnPage, 'title');
2532  if ($this->languageIconTitles[$lUid_OnPage]['flagIcon']) {
2533  $lC = $this->iconFactory->getIcon($this->languageIconTitles[$lUid_OnPage]['flagIcon'], Icon::SIZE_SMALL)->render();
2534  } else {
2535  $lC = $this->languageIconTitles[$lUid_OnPage]['title'];
2536  }
2537  $lC = '<a href="' . htmlspecialchars($href) . '" title="'
2538  . htmlspecialchars($language['title']) . '" class="btn btn-default t3js-action-localize">'
2539  . $lC . '</a> ';
2540  $lNew .= $lC;
2541  }
2542  }
2543  if ($lNew) {
2544  $out[1] .= $lNew;
2545  }
2546  } elseif ($row['l18n_parent']) {
2547  $out[0] = '&nbsp;&nbsp;&nbsp;&nbsp;' . $out[0];
2548  }
2549  return $out;
2550  }
2551 
2559  public function ‪fieldSelectBox(‪$table, $formFields = true)
2560  {
2561  $lang = $this->‪getLanguageService();
2562  // Init:
2563  $formElements = ['', ''];
2564  if ($formFields) {
2565  $formElements = ['<form action="' . htmlspecialchars($this->‪listURL()) . '" method="post" name="fieldSelectBox">', '</form>'];
2566  }
2567  // Load already selected fields, if any:
2568  ‪$setFields = is_array($this->setFields[‪$table]) ? $this->setFields[‪$table] : [];
2569  // Request fields from table:
2570  ‪$fields = $this->‪makeFieldList($table, false, true);
2571  // Add pseudo "control" fields
2572  ‪$fields[] = '_PATH_';
2573  ‪$fields[] = '_REF_';
2574  ‪$fields[] = '_LOCALIZATION_';
2575  ‪$fields[] = '_CONTROL_';
2576  ‪$fields[] = '_CLIPBOARD_';
2577  // Create a checkbox for each field:
2578  $checkboxes = [];
2579  $checkAllChecked = true;
2580  $tsConfig = BackendUtility::getPagesTSconfig($this->id);
2581  $tsConfigOfTable = is_array($tsConfig['TCEFORM.'][‪$table . '.']) ? $tsConfig['TCEFORM.'][‪$table . '.'] : null;
2582  foreach (‪$fields as $fieldName) {
2583  // Hide field if hidden
2584  if ($tsConfigOfTable && is_array($tsConfigOfTable[$fieldName . '.']) && isset($tsConfigOfTable[$fieldName . '.']['disabled']) && (int)$tsConfigOfTable[$fieldName . '.']['disabled'] === 1) {
2585  continue;
2586  }
2587  // Determine, if checkbox should be checked
2588  if (in_array($fieldName, ‪$setFields, true) || $fieldName === $this->fieldArray[0]) {
2589  $checked = ' checked="checked"';
2590  } else {
2591  $checkAllChecked = false;
2592  $checked = '';
2593  }
2594 
2595  // Field label
2596  $fieldTSConfig = [];
2597  $fieldLabel = '';
2598  if (isset($tsConfigOfTable[$fieldName . '.'])
2599  && is_array($tsConfigOfTable[$fieldName . '.'])
2600  ) {
2601  $fieldTSConfig = $tsConfigOfTable[$fieldName . '.'];
2602  }
2603  if (!empty($fieldTSConfig['label'])) {
2604  $fieldLabel = $fieldTSConfig['label'];
2605  }
2606  if (!empty($fieldTSConfig['label.'][$lang->lang])) {
2607  $fieldLabel = $fieldTSConfig['label.'][$lang->lang];
2608  }
2609 
2610  $fieldLabel = $fieldLabel ?: BackendUtility::getItemLabel(‪$table, $fieldName);
2611 
2612  $checkboxes[] = '<tr><td class="col-checkbox"><input type="checkbox" id="check-' . $fieldName . '" name="displayFields['
2613  . ‪$table . '][]" value="' . $fieldName . '" ' . $checked
2614  . ($fieldName === $this->fieldArray[0] ? ' disabled="disabled"' : '') . '></td><td class="col-title">'
2615  . '<label class="label-block" for="check-' . $fieldName . '">' . htmlspecialchars($lang->sL($fieldLabel)) . ' <span class="text-muted text-monospace">[' . htmlspecialchars($fieldName) . ']</span></label></td></tr>';
2616  }
2617  // Table with the field selector::
2618  ‪$content = $formElements[0] . '
2619  <input type="hidden" name="displayFields[' . ‪$table . '][]" value="">
2620  <div class="table-fit table-scrollable">
2621  <table border="0" cellpadding="0" cellspacing="0" class="table table-transparent table-hover">
2622  <thead>
2623  <tr>
2624  <th class="col-checkbox checkbox" colspan="2">
2625  <label><input type="checkbox" class="checkbox checkAll" ' . ($checkAllChecked ? ' checked="checked"' : '') . '>
2626  ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleall')) . '</label>
2627  </th>
2628  </tr>
2629  </thead>
2630  <tbody>
2631  ' . implode('', $checkboxes) . '
2632  </tbody>
2633  </table>
2634  </div>
2635  <input type="submit" name="search" class="btn btn-default" value="'
2636  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.setFields')) . '"/>
2637  ' . $formElements[1];
2638  return '<div class="fieldSelectBox">' . ‪$content . '</div>';
2639  }
2640 
2641  /*********************************
2642  *
2643  * Helper functions
2644  *
2645  *********************************/
2658  public function ‪linkClipboardHeaderIcon($string, ‪$table, ‪$cmd, $warning = '', $title = '')
2659  {
2660  $jsCode = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue(‪$cmd)
2661  . ';document.dblistForm.cmd_table.value='
2662  . GeneralUtility::quoteJSvalue(‪$table)
2663  . ';document.dblistForm.submit();';
2664 
2665  $attributes = [];
2666  if ($title !== '') {
2667  $attributes['title'] = $title;
2668  }
2669  if ($warning) {
2670  $attributes['class'] = 'btn btn-default t3js-modal-trigger';
2671  $attributes['data-href'] = 'javascript:' . $jsCode;
2672  $attributes['data-severity'] = 'warning';
2673  $attributes['data-title'] = $title;
2674  $attributes['data-content'] = $warning;
2675  } else {
2676  $attributes['class'] = 'btn btn-default';
2677  $attributes['onclick'] = $jsCode . 'return false;';
2678  }
2679 
2680  $attributesString = '';
2681  foreach ($attributes as $key => $value) {
2682  $attributesString .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
2683  }
2684  return '<a href="#" ' . $attributesString . '>' . $string . '</a>';
2685  }
2686 
2692  public function ‪clipNumPane()
2693  {
2694  return in_array('_CLIPBOARD_', $this->fieldArray) && $this->clipObj->current !== 'normal';
2695  }
2696 
2707  public function ‪addSortLink($code, $field, ‪$table)
2708  {
2709  // Certain circumstances just return string right away (no links):
2710  if ($field === '_CONTROL_' || $field === '_LOCALIZATION_' || $field === '_CLIPBOARD_' || $field === '_REF_' || $this->disableSingleTableView) {
2711  return $code;
2712  }
2713  // If "_PATH_" (showing record path) is selected, force sorting by pid field (will at least group the records!)
2714  if ($field === '_PATH_') {
2715  $field = 'pid';
2716  }
2717  // Create the sort link:
2718  $sortUrl = $this->‪listURL('', '-1', 'sortField,sortRev,table,firstElementNumber') . '&table=' . $table
2719  . '&sortField=' . $field . '&sortRev=' . ($this->sortRev || $this->sortField != $field ? 0 : 1);
2720  $sortArrow = $this->sortField === $field
2721  ? $this->iconFactory->getIcon('status-status-sorting-' . ($this->sortRev ? 'desc' : 'asc'), Icon::SIZE_SMALL)->render()
2722  : '';
2723  // Return linked field:
2724  return '<a href="' . htmlspecialchars($sortUrl) . '">' . $code . $sortArrow . '</a>';
2725  }
2726 
2735  public function ‪recPath($pid)
2736  {
2737  if (!isset($this->recPath_cache[$pid])) {
2738  $this->recPath_cache[$pid] = BackendUtility::getRecordPath($pid, $this->perms_clause, 20);
2739  }
2740  return $this->recPath_cache[$pid];
2741  }
2742 
2750  public function ‪showNewRecLink(‪$table)
2751  {
2752  // No deny/allow tables are set:
2753  if (empty($this->allowedNewTables) && empty($this->deniedNewTables)) {
2754  return true;
2755  }
2756  return !in_array(‪$table, $this->deniedNewTables)
2757  && (empty($this->allowedNewTables) || in_array(‪$table, $this->allowedNewTables));
2758  }
2759 
2767  public function ‪makeReturnUrl()
2768  {
2769  return '&returnUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'));
2770  }
2771 
2772  /************************************
2773  *
2774  * CSV related functions
2775  *
2776  ************************************/
2780  protected function ‪initCSV()
2781  {
2782  $this->‪addHeaderRowToCSV();
2783  }
2784 
2788  protected function ‪addHeaderRowToCSV()
2789  {
2790  ‪$fieldArray = array_combine($this->fieldArray, $this->fieldArray);
2791  $hooks = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][__CLASS__]['customizeCsvHeader'] ?? [];
2792  if (!empty($hooks)) {
2793  $hookParameters = [
2794  'fields' => &‪$fieldArray
2795  ];
2796  foreach ($hooks as $hookFunction) {
2797  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
2798  }
2799  }
2800  // Add header row, control fields will be reduced inside addToCSV()
2801  $this->‪addToCSV(‪$fieldArray);
2802  }
2803 
2809  protected function ‪addToCSV(array $row = [])
2810  {
2811  $rowReducedByControlFields = ‪self::removeControlFieldsFromFieldRow($row);
2812  // Get an field array without control fields but in the expected order
2813  ‪$fieldArray = array_intersect_key(array_flip($this->fieldArray), $rowReducedByControlFields);
2814  // Overwrite fieldArray to keep the order with an array of needed fields
2815  $rowReducedToSelectedColumns = array_replace(‪$fieldArray, array_intersect_key($rowReducedByControlFields, ‪$fieldArray));
2816  $this->‪setCsvRow($rowReducedToSelectedColumns);
2817  }
2818 
2825  protected static function ‪removeControlFieldsFromFieldRow(array $row = [])
2826  {
2827  // Possible control fields in a list row
2828  $controlFields = [
2829  '_PATH_',
2830  '_REF_',
2831  '_CONTROL_',
2832  '_CLIPBOARD_',
2833  '_LOCALIZATION_',
2834  '_LOCALIZATION_b'
2835  ];
2836  return array_diff_key($row, array_flip($controlFields));
2837  }
2838 
2844  public function ‪setCsvRow($csvRow)
2845  {
2846  $csvDelimiter = $this->modTSconfig['properties']['csvDelimiter'] ?? ',';
2847  $csvQuote = $this->modTSconfig['properties']['csvQuote'] ?? '"';
2848 
2849  $this->csvLines[] = CsvUtility::csvValues($csvRow, $csvDelimiter, $csvQuote);
2850  }
2851 
2858  public function ‪outputCSV($prefix)
2859  {
2860  // Setting filename:
2861  $filename = $prefix . '_' . date('dmy-Hi') . '.csv';
2862  // Creating output header:
2863  header('Content-Type: application/octet-stream');
2864  header('Content-Disposition: attachment; filename=' . $filename);
2865  // Cache-Control header is needed here to solve an issue with browser IE and
2866  // versions lower than 9. See for more information: http://support.microsoft.com/kb/323308
2867  header("Cache-Control: ''");
2868  // Printing the content of the CSV lines:
2869  echo implode(CRLF, $this->csvLines);
2870  // Exits:
2871  die;
2872  }
2873 
2881  public function ‪addActionToCellGroup(&$cells, $action, $actionKey)
2882  {
2883  $cellsMap = [
2884  'primary' => [
2885  'view', 'edit', 'hide', 'delete', 'stat'
2886  ],
2887  'secondary' => [
2888  'viewBig', 'history', 'perms', 'new', 'move', 'moveUp', 'moveDown', 'moveLeft', 'moveRight', 'version'
2889  ]
2890  ];
2891  $classification = in_array($actionKey, $cellsMap['primary']) ? 'primary' : 'secondary';
2892  $cells[$classification][$actionKey] = $action;
2893  unset($cells[$actionKey]);
2894  }
2903  protected function ‪isRecordCurrentBackendUser(‪$table, $row)
2904  {
2905  return ‪$table === 'be_users' && (int)$row['uid'] === $this->‪getBackendUserAuthentication()->user['uid'];
2906  }
2907 
2911  public function ‪setIsEditable($isEditable)
2912  {
2913  $this->editable = $isEditable;
2914  }
2915 
2921  public function ‪isEditable(‪$table)
2922  {
2923  $backendUser = $this->‪getBackendUserAuthentication();
2924  return !$GLOBALS['TCA'][‪$table]['ctrl']['readOnly']
2925  && $this->editable
2926  && ($backendUser->isAdmin() || $backendUser->check('tables_modify', ‪$table));
2927  }
2928 
2939  protected function ‪overlayEditLockPermissions(‪$table, $row = [], $editPermission = true)
2940  {
2941  if ($editPermission && !$this->‪getBackendUserAuthentication()->isAdmin()) {
2942  // If no $row is submitted we only check for general edit lock of current page (except for table "pages")
2943  if (empty($row)) {
2944  return ‪$table === 'pages' ? true : !$this->pageRow['editlock'];
2945  }
2946  if ((‪$table === 'pages' && $row['editlock']) || (‪$table !== 'pages' && $this->pageRow['editlock'])) {
2947  $editPermission = false;
2948  } elseif (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['editlock']) && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['editlock']]) {
2949  $editPermission = false;
2950  }
2951  }
2952  return $editPermission;
2953  }
2954 
2961  protected function ‪editLockPermissions()
2962  {
2963  return $this->‪getBackendUserAuthentication()->‪isAdmin() || !$this->pageRow['editlock'];
2964  }
2965 
2969  protected function ‪getModule()
2970  {
2971  return ‪$GLOBALS['SOBE'];
2972  }
2973 
2977  protected function ‪getDocumentTemplate()
2978  {
2979  return ‪$GLOBALS['TBE_TEMPLATE'];
2980  }
2981 
2992  public function ‪start(‪$id, ‪$table, ‪$pointer, $search = '', $levels = 0, ‪$showLimit = 0)
2993  {
2994  $backendUser = $this->‪getBackendUserAuthentication();
2995  // Setting internal variables:
2996  // sets the parent id
2997  $this->id = (int)‪$id;
2998  // Store languages that are included in the site configuration for the current page.
2999  $this->systemLanguagesOnPage = $this->translateTools->getSystemLanguages($this->id);
3000  if ($GLOBALS['TCA'][‪$table]) {
3001  // Setting single table mode, if table exists:
3002  $this->table = ‪$table;
3003  }
3004  $this->firstElementNumber = ‪$pointer;
3005  $this->searchString = trim($search);
3006  $this->searchLevels = (int)$levels;
3007  $this->showLimit = MathUtility::forceIntegerInRange(‪$showLimit, 0, 10000);
3008  // Setting GPvars:
3009  $this->csvOutput = (bool)GeneralUtility::_GP('csv');
3010  $this->sortField = GeneralUtility::_GP('sortField');
3011  $this->sortRev = GeneralUtility::_GP('sortRev');
3012  $this->displayFields = GeneralUtility::_GP('displayFields');
3013  $this->duplicateField = GeneralUtility::_GP('duplicateField');
3014  if (GeneralUtility::_GP('justLocalized')) {
3015  $this->‪localizationRedirect(GeneralUtility::_GP('justLocalized'));
3016  }
3017  // Init dynamic vars:
3018  $this->counter = 0;
3019  $this->JScode = '';
3020  $this->HTMLcode = '';
3021  // Limits
3022  if (isset($this->modTSconfig['properties']['itemsLimitPerTable'])) {
3023  $this->itemsLimitPerTable = MathUtility::forceIntegerInRange(
3024  (int)$this->modTSconfig['properties']['itemsLimitPerTable'],
3025  1,
3026  10000
3027  );
3028  }
3029  if (isset($this->modTSconfig['properties']['itemsLimitSingleTable'])) {
3030  $this->itemsLimitSingleTable = MathUtility::forceIntegerInRange(
3031  (int)$this->modTSconfig['properties']['itemsLimitSingleTable'],
3032  1,
3033  10000
3034  );
3035  }
3036 
3037  // If there is a current link to a record, set the current link uid and get the table name from the link handler configuration
3038  $currentLinkValue = isset($this->overrideUrlParameters['P']['currentValue']) ? trim($this->overrideUrlParameters['P']['currentValue']) : '';
3039  if ($currentLinkValue) {
3040  $linkService = GeneralUtility::makeInstance(LinkService::class);
3041  try {
3042  $currentLinkParts = $linkService->resolve($currentLinkValue);
3043  if ($currentLinkParts['type'] === 'record' && isset($currentLinkParts['identifier'])) {
3044  $this->currentLink['tableNames'] = ‪$this->tableList;
3045  $this->currentLink['uid'] = (int)$currentLinkParts['uid'];
3046  }
3047  } catch (UnknownLinkHandlerException $e) {
3048  }
3049  }
3050 
3051  // $table might be NULL at this point in the code. As the expressionBuilder
3052  // is used to limit returned records based on the page permissions and the
3053  // uid field of the pages it can hardcoded to work on the pages table.
3054  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3055  ->getQueryBuilderForTable('pages')
3056  ->expr();
3057  $permsClause = $expressionBuilder->andX($backendUser->getPagePermsClause(Permission::PAGE_SHOW));
3058  // This will hide records from display - it has nothing to do with user rights!!
3059  $pidList = GeneralUtility::intExplode(',', $backendUser->getTSConfig()['options.']['hideRecords.']['pages'] ?? '', true);
3060  if (!empty($pidList)) {
3061  $permsClause->add($expressionBuilder->notIn('pages.uid', $pidList));
3062  }
3063  $this->perms_clause = (string)$permsClause;
3064 
3065  // Get configuration of collapsed tables from user uc and merge with sanitized GP vars
3066  $this->tablesCollapsed = is_array($backendUser->uc['moduleData']['list'])
3067  ? $backendUser->uc['moduleData']['list']
3068  : [];
3069  $collapseOverride = GeneralUtility::_GP('collapse');
3070  if (is_array($collapseOverride)) {
3071  foreach ($collapseOverride as $collapseTable => $collapseValue) {
3072  if (is_array(‪$GLOBALS['TCA'][$collapseTable]) && ($collapseValue == 0 || $collapseValue == 1)) {
3073  $this->tablesCollapsed[$collapseTable] = $collapseValue;
3074  }
3075  }
3076  // Save modified user uc
3077  $backendUser->uc['moduleData']['list'] = ‪$this->tablesCollapsed;
3078  $backendUser->writeUC($backendUser->uc);
3079  ‪$returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
3080  if (‪$returnUrl !== '') {
3081  HttpUtility::redirect(‪$returnUrl);
3082  }
3083  }
3084  $this->‪initializeLanguages();
3085  }
3086 
3092  public function ‪generateList()
3093  {
3094  // Set page record in header
3095  $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id);
3096  $hideTablesArray = GeneralUtility::trimExplode(',', $this->hideTables);
3097 
3098  $backendUser = $this->‪getBackendUserAuthentication();
3099 
3100  // pre-process tables and add sorting instructions
3101  $tableNames = array_flip(array_keys(‪$GLOBALS['TCA']));
3102  foreach ($tableNames as $tableName => &$config) {
3103  $hideTable = false;
3104 
3105  // Checking if the table should be rendered:
3106  // Checks that we see only permitted/requested tables:
3107  if ($this->table && $tableName !== $this->table
3108  || $this->tableList && !GeneralUtility::inList($this->tableList, $tableName)
3109  || !$backendUser->check('tables_select', $tableName)
3110  ) {
3111  $hideTable = true;
3112  }
3113 
3114  if (!$hideTable) {
3115  // Don't show table if hidden by TCA ctrl section
3116  // Don't show table if hidden by pageTSconfig mod.web_list.hideTables
3117  $hideTable = $hideTable
3118  || !empty(‪$GLOBALS['TCA'][$tableName]['ctrl']['hideTable'])
3119  || in_array($tableName, $hideTablesArray, true)
3120  || in_array('*', $hideTablesArray, true);
3121  // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table
3122  if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) {
3123  $hideTable = (bool)$this->tableTSconfigOverTCA[$tableName . '.']['hideTable'];
3124  }
3125  }
3126  if ($hideTable) {
3127  unset($tableNames[$tableName]);
3128  } else {
3129  if (isset($this->tableDisplayOrder[$tableName])) {
3130  // Copy display order information
3131  $tableNames[$tableName] = $this->tableDisplayOrder[$tableName];
3132  } else {
3133  $tableNames[$tableName] = [];
3134  }
3135  }
3136  }
3137  unset($config);
3138 
3139  $orderedTableNames = GeneralUtility::makeInstance(DependencyOrderingService::class)
3140  ->orderByDependencies($tableNames);
3141 
3142  foreach ($orderedTableNames as $tableName => $_) {
3143  // check if we are in single- or multi-table mode
3144  if ($this->table) {
3145  $this->iLimit = isset(‪$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems'])
3146  ? (int)‪$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']
3147  : $this->itemsLimitSingleTable;
3148  } else {
3149  // if there are no records in table continue current foreach
3150  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3151  ->getQueryBuilderForTable($tableName);
3152  $queryBuilder->getRestrictions()
3153  ->removeAll()
3154  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3155  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
3156  $queryBuilder = $this->‪addPageIdConstraint($tableName, $queryBuilder);
3157  $firstRow = $queryBuilder->select('uid')
3158  ->from($tableName)
3159  ->setMaxResults(1)
3160  ->execute()
3161  ->fetch();
3162  if (!is_array($firstRow)) {
3163  continue;
3164  }
3165  $this->iLimit = isset(‪$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems'])
3166  ? (int)‪$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']
3167  : $this->itemsLimitPerTable;
3168  }
3169  if ($this->showLimit) {
3170  $this->iLimit = ‪$this->showLimit;
3171  }
3172  // Setting fields to select:
3173  if ($this->allFields) {
3174  ‪$fields = $this->‪makeFieldList($tableName);
3175  ‪$fields[] = 'tstamp';
3176  ‪$fields[] = 'crdate';
3177  ‪$fields[] = '_PATH_';
3178  ‪$fields[] = '_CONTROL_';
3179  if (is_array($this->setFields[$tableName])) {
3180  ‪$fields = array_intersect(‪$fields, $this->setFields[$tableName]);
3181  } else {
3182  ‪$fields = [];
3183  }
3184  } else {
3185  ‪$fields = [];
3186  }
3187 
3188  // Finally, render the list:
3189  $this->HTMLcode .= $this->‪getTable($tableName, $this->id, implode(',', ‪$fields));
3190  }
3191  }
3192 
3199  public function ‪getSearchBox($formFields = true)
3200  {
3202  ‪$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
3203  $lang = $this->‪getLanguageService();
3204  // Setting form-elements, if applicable:
3205  $formElements = ['', ''];
3206  if ($formFields) {
3207  $formElements = [
3208  '<form action="' . htmlspecialchars(
3209  $this->‪listURL('', '-1', 'firstElementNumber,search_field')
3210  ) . '" method="post">',
3211  '</form>'
3212  ];
3213  }
3214  // Make level selector:
3215  $opt = [];
3216 
3217  // "New" generation of search levels ... based on TS config
3218  $config = BackendUtility::getPagesTSconfig($this->id);
3219  $searchLevelsFromTSconfig = $config['mod.']['web_list.']['searchLevel.']['items.'];
3220  $searchLevelItems = [];
3221 
3222  // get translated labels for search levels from pagets
3223  foreach ($searchLevelsFromTSconfig as $keySearchLevel => $labelConfigured) {
3224  $label = $lang->sL('LLL:' . $labelConfigured);
3225  if ($label === '') {
3226  $label = $labelConfigured;
3227  }
3228  $searchLevelItems[$keySearchLevel] = $label;
3229  }
3230 
3231  foreach ($searchLevelItems as $kv => $label) {
3232  $opt[] = '<option value="' . $kv . '"' . ($kv === $this->searchLevels ? ' selected="selected"' : '') . '>' . htmlspecialchars(
3233  $label
3234  ) . '</option>';
3235  }
3236  $lMenu = '<select class="form-control" name="search_levels" title="' . htmlspecialchars(
3237  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search_levels')
3238  ) . '" id="search_levels">' . implode('', $opt) . '</select>';
3239  // Table with the search box:
3240  ‪$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') . ';">
3241  ' . $formElements[0] . '
3242  <div id="typo3-dblist-search">
3243  <div class="panel panel-default">
3244  <div class="panel-body">
3245  <div class="row">
3246  <div class="col-sm-6 col-xs-12">
3247  <label for="search_field">' . htmlspecialchars(
3248  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.searchString')
3249  ) . '</label>
3250  <input class="form-control" type="search" placeholder="' . htmlspecialchars(
3251  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enterSearchString')
3252  ) . '" title="' . htmlspecialchars(
3253  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchString')
3254  ) . '" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '" />
3255  </div>
3256  <div class="col-xs-12 col-sm-3">
3257  <label for="search_levels">' . htmlspecialchars(
3258  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.search_levels')
3259  ) . '</label>
3260  ' . $lMenu . '
3261  </div>
3262  <div class="col-xs-12 col-sm-3">
3263  <label for="showLimit">' . htmlspecialchars(
3264  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.limit')
3265  ) . '</label>
3266  <input class="form-control" type="number" min="0" max="10000" placeholder="10" title="' . htmlspecialchars(
3267  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.limit')
3268  ) . '" name="showLimit" id="showLimit" value="' . htmlspecialchars(
3269  ($this->showLimit ? $this->showLimit : '')
3270  ) . '" />
3271  </div>
3272  <div class="col-xs-12">
3273  <div class="form-control-wrap">
3274  <button type="submit" class="btn btn-default" name="search" title="' . htmlspecialchars(
3275  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search')
3276  ) . '">
3277  ' . ‪$iconFactory->‪getIcon('actions-search', Icon::SIZE_SMALL)->‪render(
3278  ) . ' ' . htmlspecialchars(
3279  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.search')
3280  ) . '
3281  </button>
3282  </div>
3283  </div>
3284  </div>
3285  </div>
3286  </div>
3287  </div>
3288  ' . $formElements[1] . '</div>';
3289  return ‪$content;
3290  }
3291 
3296  public function ‪setDispFields()
3297  {
3298  $backendUser = $this->‪getBackendUserAuthentication();
3299  // Getting from session:
3300  $dispFields = $backendUser->getModuleData('list/displayFields');
3301  // If fields has been inputted, then set those as the value and push it to session variable:
3302  if (is_array($this->displayFields)) {
3303  reset($this->displayFields);
3304  $tKey = key($this->displayFields);
3305  $dispFields[$tKey] = $this->displayFields[$tKey];
3306  $backendUser->pushModuleData('list/displayFields', $dispFields);
3307  }
3308  // Setting result:
3309  $this->setFields = $dispFields;
3310  }
3311 
3320  public function ‪thumbCode($row, ‪$table, $field)
3321  {
3322  return BackendUtility::thumbCode($row, ‪$table, $field);
3323  }
3324 
3335  public function ‪getQueryBuilder(
3336  string ‪$table,
3337  int $pageId,
3338  array $additionalConstraints = [],
3339  array ‪$fields = ['*']
3340  ): QueryBuilder {
3341  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3342  ->getQueryBuilderForTable(‪$table);
3343  $queryBuilder->getRestrictions()
3344  ->removeAll()
3345  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3346  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
3347  $queryBuilder
3348  ->select(...‪$fields)
3349  ->from(‪$table);
3350 
3351  if (!empty($additionalConstraints)) {
3352  $queryBuilder->andWhere(...$additionalConstraints);
3353  }
3354 
3355  $queryBuilder = $this->‪prepareQueryBuilder($table, $pageId, ‪$fields, $additionalConstraints, $queryBuilder);
3356 
3357  return $queryBuilder;
3358  }
3359 
3372  protected function ‪prepareQueryBuilder(
3373  string ‪$table,
3374  int $pageId,
3375  array $fieldList = ['*'],
3376  array $additionalConstraints = [],
3377  QueryBuilder $queryBuilder,
3378  bool $addSorting = true
3379  ): QueryBuilder {
3380  $parameters = [
3381  'table' => ‪$table,
3382  'fields' => $fieldList,
3383  'groupBy' => null,
3384  'orderBy' => null,
3385  'firstResult' => $this->firstElementNumber ?: null,
3386  'maxResults' => $this->iLimit ?: null
3387  ];
3388 
3389  if ($this->iLimit > 0) {
3390  $queryBuilder->setMaxResults($this->iLimit);
3391  }
3392 
3393  if ($this->firstElementNumber > 0) {
3394  $queryBuilder->setFirstResult($this->firstElementNumber);
3395  }
3396 
3397  if ($addSorting) {
3398  if ($this->sortField && in_array($this->sortField, $this->‪makeFieldList($table, 1))) {
3399  $queryBuilder->orderBy($this->sortField, $this->sortRev ? 'DESC' : 'ASC');
3400  } else {
3401  $orderBy = ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] ?: ‪$GLOBALS['TCA'][‪$table]['ctrl']['default_sortby'];
3402  $orderBys = QueryHelper::parseOrderBy((string)$orderBy);
3403  foreach ($orderBys as $orderBy) {
3404  $queryBuilder->addOrderBy($orderBy[0], $orderBy[1]);
3405  }
3406  }
3407  }
3408 
3409  // Build the query constraints
3410  $queryBuilder = $this->‪addPageIdConstraint($table, $queryBuilder);
3411  $searchWhere = $this->‪makeSearchString($table, $pageId);
3412  if (!empty($searchWhere)) {
3413  $queryBuilder->andWhere($searchWhere);
3414  }
3415 
3416  // Filtering on displayable pages (permissions):
3417  if (‪$table === 'pages' && $this->perms_clause) {
3418  $queryBuilder->andWhere($this->perms_clause);
3419  }
3420 
3421  // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set
3422  if (!empty(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'])
3423  && (GeneralUtility::inList($this->hideTranslations, ‪$table) || $this->hideTranslations === '*')
3424  ) {
3425  $queryBuilder->andWhere(
3426  $queryBuilder->expr()->eq(
3427  ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'],
3428  0
3429  )
3430  );
3431  } elseif (!empty(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']) && $this->‪showOnlyTranslatedRecords) {
3432  // When only translated records should be shown, it is necessary to use l10n_parent=pageId, instead of
3433  // a check to the PID
3434  $queryBuilder->andWhere(
3435  $queryBuilder->expr()->eq(
3436  ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'],
3437  $queryBuilder->createNamedParameter(
3438  $this->id,
3439  \PDO::PARAM_INT
3440  )
3441  )
3442  );
3443  }
3444 
3445  $hookName = DatabaseRecordList::class;
3446  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['buildQueryParameters'])) {
3447  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, the modifyQuery hook should be used instead.
3448  trigger_error('The hook ($GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][' . $hookName . '][\'buildQueryParameters\']) will be removed in TYPO3 v10.0, the modifyQuery hook should be used instead.', E_USER_DEPRECATED);
3449  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['buildQueryParameters'] as $className) {
3450  $hookObject = GeneralUtility::makeInstance($className);
3451  if (method_exists($hookObject, 'buildQueryParametersPostProcess')) {
3452  $hookObject->buildQueryParametersPostProcess(
3453  $parameters,
3454  ‪$table,
3455  $pageId,
3456  $additionalConstraints,
3457  $fieldList,
3458  $this,
3459  $queryBuilder
3460  );
3461  }
3462  }
3463  }
3464  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['modifyQuery'] ?? [] as $className) {
3465  $hookObject = GeneralUtility::makeInstance($className);
3466  if (method_exists($hookObject, 'modifyQuery')) {
3467  $hookObject->modifyQuery(
3468  $parameters,
3469  ‪$table,
3470  $pageId,
3471  $additionalConstraints,
3472  $fieldList,
3473  $queryBuilder
3474  );
3475  }
3476  }
3477 
3478  // array_unique / array_filter used to eliminate empty and duplicate constraints
3479  // the array keys are eliminated by this as well to facilitate argument unpacking
3480  // when used with the querybuilder.
3481  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0
3482  if (!empty($parameters['where'])) {
3483  $parameters['where'] = array_unique(array_filter(array_values($parameters['where'])));
3484  }
3485  if (!empty($parameters['where'])) {
3486  $this->‪logDeprecation('where');
3487  $queryBuilder->where(...$parameters['where']);
3488  }
3489  if (!empty($parameters['orderBy'])) {
3490  $this->‪logDeprecation('orderBy');
3491  foreach ($parameters['orderBy'] as $fieldNameAndSorting) {
3492  [$fieldName, $sorting] = $fieldNameAndSorting;
3493  $queryBuilder->addOrderBy($fieldName, $sorting);
3494  }
3495  }
3496  if (!empty($parameters['firstResult']) && $parameters['firstResult'] !== $this->firstElementNumber) {
3497  $this->‪logDeprecation('firstResult');
3498  $queryBuilder->setFirstResult((int)$parameters['firstResult']);
3499  }
3500  if (!empty($parameters['maxResults']) && $parameters['maxResults'] !== $this->iLimit) {
3501  $this->‪logDeprecation('maxResults');
3502  $queryBuilder->setMaxResults((int)$parameters['maxResults']);
3503  }
3504  if (!empty($parameters['groupBy'])) {
3505  $this->‪logDeprecation('groupBy');
3506  $queryBuilder->groupBy($parameters['groupBy']);
3507  }
3508 
3509  return $queryBuilder;
3510  }
3511 
3520  public function ‪setTotalItems(string ‪$table, int $pageId, array $constraints)
3521  {
3522  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3523  ->getQueryBuilderForTable(‪$table);
3524 
3525  $queryBuilder->getRestrictions()
3526  ->removeAll()
3527  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3528  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
3529  $queryBuilder
3530  ->from(‪$table);
3531 
3532  if (!empty($constraints)) {
3533  $queryBuilder->andWhere(...$constraints);
3534  }
3535 
3536  $queryBuilder = $this->‪prepareQueryBuilder($table, $pageId, ['*'], $constraints, $queryBuilder, false);
3537  // Reset limit and offset for full count query
3538  $queryBuilder->setFirstResult(0);
3539  $queryBuilder->setMaxResults(1);
3540 
3541  $this->totalItems = (int)$queryBuilder->count('*')
3542  ->execute()
3543  ->fetchColumn();
3544  }
3545 
3554  public function ‪makeSearchString(‪$table, $currentPid = -1)
3555  {
3556  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
3557  $expressionBuilder = $queryBuilder->expr();
3558  $constraints = [];
3559  $currentPid = (int)$currentPid;
3560  $tablePidField = ‪$table === 'pages' ? 'uid' : 'pid';
3561  // Make query only if table is valid and a search string is actually defined
3562  if (empty($this->searchString)) {
3563  return '';
3564  }
3565 
3566  $searchableFields = $this->‪getSearchFields($table);
3567  if (MathUtility::canBeInterpretedAsInteger($this->searchString)) {
3568  $constraints[] = $expressionBuilder->eq('uid', (int)$this->searchString);
3569  foreach ($searchableFields as $fieldName) {
3570  if (!isset(‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName])) {
3571  continue;
3572  }
3573  $fieldConfig = ‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName]['config'];
3574  $fieldType = $fieldConfig['type'];
3575  $evalRules = $fieldConfig['eval'] ?: '';
3576  if ($fieldType === 'input' && $evalRules && GeneralUtility::inList($evalRules, 'int')) {
3577  if (!isset($fieldConfig['search']['pidonly'])
3578  || ($fieldConfig['search']['pidonly'] && $currentPid > 0)
3579  ) {
3580  $constraints[] = $expressionBuilder->andX(
3581  $expressionBuilder->eq($fieldName, (int)$this->searchString),
3582  $expressionBuilder->eq($tablePidField, (int)$currentPid)
3583  );
3584  }
3585  } elseif ($fieldType === 'text'
3586  || $fieldType === 'flex'
3587  || ($fieldType === 'input' && (!$evalRules || !preg_match('/\b(?:date|time|int)\b/', $evalRules)))
3588  ) {
3589  $constraints[] = $expressionBuilder->like(
3590  $fieldName,
3591  $queryBuilder->quote('%' . (int)$this->searchString . '%')
3592  );
3593  }
3594  }
3595  } elseif (!empty($searchableFields)) {
3596  $like = $queryBuilder->quote('%' . $queryBuilder->escapeLikeWildcards($this->searchString) . '%');
3597  foreach ($searchableFields as $fieldName) {
3598  if (!isset(‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName])) {
3599  continue;
3600  }
3601  $fieldConfig = ‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName]['config'];
3602  $fieldType = $fieldConfig['type'];
3603  $evalRules = $fieldConfig['eval'] ?: '';
3604  $searchConstraint = $expressionBuilder->andX(
3605  $expressionBuilder->comparison(
3606  'LOWER(' . $queryBuilder->castFieldToTextType($fieldName) . ')',
3607  'LIKE',
3608  'LOWER(' . $like . ')'
3609  )
3610  );
3611  if (is_array($fieldConfig['search'])) {
3612  $searchConfig = $fieldConfig['search'];
3613  if (in_array('case', $searchConfig)) {
3614  // Replace case insensitive default constraint
3615  $searchConstraint = $expressionBuilder->andX($expressionBuilder->like($fieldName, $like));
3616  }
3617  if (in_array('pidonly', $searchConfig) && $currentPid > 0) {
3618  $searchConstraint->add($expressionBuilder->eq($tablePidField, (int)$currentPid));
3619  }
3620  if ($searchConfig['andWhere']) {
3621  $searchConstraint->add(
3622  QueryHelper::stripLogicalOperatorPrefix($fieldConfig['search']['andWhere'])
3623  );
3624  }
3625  }
3626  if ($fieldType === 'text'
3627  || $fieldType === 'flex'
3628  || $fieldType === 'input' && (!$evalRules || !preg_match('/\b(?:date|time|int)\b/', $evalRules))
3629  ) {
3630  if ($searchConstraint->count() !== 0) {
3631  $constraints[] = $searchConstraint;
3632  }
3633  }
3634  }
3635  }
3636  // Call hook to add or change the list
3637  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][DatabaseRecordList::class]['makeSearchStringConstraints'] ?? [] as $className) {
3638  $hookObject = GeneralUtility::makeInstance($className);
3639  if (method_exists($hookObject, 'makeSearchStringConstraints')) {
3640  $constraints = $hookObject->makeSearchStringConstraints(
3641  $queryBuilder,
3642  $constraints,
3643  $this->searchString,
3644  ‪$table,
3645  $currentPid
3646  );
3647  }
3648  }
3649  // If no search field conditions have been built ensure no results are returned
3650  if (empty($constraints)) {
3651  return '0=1';
3652  }
3653 
3654  return $expressionBuilder->orX(...$constraints);
3655  }
3656 
3663  protected function ‪getSearchFields($tableName)
3664  {
3665  ‪$fieldArray = [];
3666  $fieldListWasSet = false;
3667  // Get fields from ctrl section of TCA first
3668  if (isset(‪$GLOBALS['TCA'][$tableName]['ctrl']['searchFields'])) {
3669  ‪$fieldArray = GeneralUtility::trimExplode(',', ‪$GLOBALS['TCA'][$tableName]['ctrl']['searchFields'], true);
3670  $fieldListWasSet = true;
3671  }
3672  // Call hook to add or change the list
3673  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'])) {
3674  $hookParameters = [
3675  'tableHasSearchConfiguration' => $fieldListWasSet,
3676  'tableName' => $tableName,
3677  'searchFields' => &‪$fieldArray,
3678  'searchString' => ‪$this->searchString
3679  ];
3680  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'] as $hookFunction) {
3681  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
3682  }
3683  }
3684  return ‪$fieldArray;
3685  }
3686 
3695  public function ‪linkWrapTable(‪$table, $code)
3696  {
3697  if ($this->table !== ‪$table) {
3698  return '<a href="' . htmlspecialchars(
3699  $this->‪listURL('', $table, 'firstElementNumber')
3700  ) . '">' . $code . '</a>';
3701  }
3702  return '<a href="' . htmlspecialchars(
3703  $this->‪listURL('', '', 'sortField,sortRev,table,firstElementNumber')
3704  ) . '">' . $code . '</a>';
3705  }
3706 
3716  public function ‪linkWrapItems(‪$table, $uid, $code, $row)
3717  {
3718  $lang = $this->‪getLanguageService();
3719  $origCode = $code;
3720  // If the title is blank, make a "no title" label:
3721  if ((string)$code === '') {
3722  $code = '<i>[' . htmlspecialchars(
3723  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title')
3724  ) . ']</i> - '
3725  . htmlspecialchars(BackendUtility::getRecordTitle(‪$table, $row));
3726  } else {
3727  $code = htmlspecialchars($code, ENT_QUOTES, 'UTF-8', false);
3728  if ($code != htmlspecialchars($origCode)) {
3729  $code = '<span title="' . htmlspecialchars(
3730  $origCode,
3731  ENT_QUOTES,
3732  'UTF-8',
3733  false
3734  ) . '">' . $code . '</span>';
3735  } else {
3736  $code = '<span title="' . $code . '">' . $code . '</span>';
3737  }
3738  }
3739  switch ((string)$this->clickTitleMode) {
3740  case 'edit':
3741  // If the listed table is 'pages' we have to request the permission settings for each page:
3742  if (‪$table === 'pages') {
3743  $localCalcPerms = $this->‪getBackendUserAuthentication()->‪calcPerms(
3744  BackendUtility::getRecord('pages', $row['uid'])
3745  );
3746  $permsEdit = $localCalcPerms & Permission::PAGE_EDIT;
3747  } else {
3748  $backendUser = $this->‪getBackendUserAuthentication();
3749  $permsEdit = $this->calcPerms & Permission::CONTENT_EDIT && $backendUser->recordEditAccessInternals(‪$table, $row);
3750  }
3751  // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
3752  if ($permsEdit && $this->‪isEditable($table)) {
3753  $params = '&edit[' . ‪$table . '][' . $row['uid'] . ']=edit';
3754  $code = '<a href="#" onclick="' . htmlspecialchars(
3755  BackendUtility::editOnClick($params, '', -1)
3756  ) . '" title="' . htmlspecialchars($lang->getLL('edit')) . '">' . $code . '</a>';
3757  }
3758  break;
3759  case 'show':
3760  // "Show" link (only pages and tt_content elements)
3761  if (‪$table === 'pages' || ‪$table === 'tt_content') {
3762  $onClick = $this->‪getOnClickForRow($table, $row);
3763  $code = '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . htmlspecialchars(
3764  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage')
3765  ) . '">' . $code . '</a>';
3766  }
3767  break;
3768  case 'info':
3769  // "Info": (All records)
3770  $code = '<a href="#" onclick="' . htmlspecialchars(
3771  'top.TYPO3.InfoWindow.showItem(' . GeneralUtility::quoteJSvalue(‪$table) . ', ' . (int)$row['uid'] . '); return false;'
3772  ) . '" title="' . htmlspecialchars($lang->getLL('showInfo')) . '">' . $code . '</a>';
3773  break;
3774  default:
3775  // Output the label now:
3776  if (‪$table === 'pages') {
3777  $code = '<a href="' . htmlspecialchars(
3778  $this->‪listURL($uid, '', 'firstElementNumber')
3779  ) . '" onclick="setHighlight(' . (int)$uid . ')">' . $code . '</a>';
3780  } else {
3781  $code = $this->‪linkUrlMail($code, $origCode);
3782  }
3783  }
3784  return $code;
3785  }
3786 
3794  public function ‪linkUrlMail($code, $testString)
3795  {
3796  // Check for URL:
3797  $scheme = parse_url($testString, PHP_URL_SCHEME);
3798  if ($scheme === 'http' || $scheme === 'https' || $scheme === 'ftp') {
3799  return '<a href="' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
3800  }
3801  // Check for email:
3802  if (GeneralUtility::validEmail($testString)) {
3803  return '<a href="mailto:' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
3804  }
3805  // Return if nothing else...
3806  return $code;
3807  }
3808 
3819  public function ‪listURL($altId = '', ‪$table = '-1', $exclList = '')
3820  {
3821  $urlParameters = [];
3822  if ((string)$altId !== '') {
3823  $urlParameters['id'] = $altId;
3824  } else {
3825  $urlParameters['id'] = ‪$this->id;
3826  }
3827  if (‪$table === '-1') {
3828  $urlParameters['table'] = ‪$this->table;
3829  } else {
3830  $urlParameters['table'] = ‪$table;
3831  }
3832  if ($this->thumbs) {
3833  $urlParameters['imagemode'] = ‪$this->thumbs;
3834  }
3835  if ($this->returnUrl) {
3836  $urlParameters['returnUrl'] = ‪$this->returnUrl;
3837  }
3838  if ((!$exclList || !GeneralUtility::inList($exclList, 'search_field')) && $this->searchString) {
3839  $urlParameters['search_field'] = ‪$this->searchString;
3840  }
3841  if ($this->searchLevels) {
3842  $urlParameters['search_levels'] = ‪$this->searchLevels;
3843  }
3844  if ($this->showLimit) {
3845  $urlParameters['showLimit'] = ‪$this->showLimit;
3846  }
3847  if ((!$exclList || !GeneralUtility::inList($exclList, 'firstElementNumber')) && $this->firstElementNumber) {
3848  $urlParameters['pointer'] = ‪$this->firstElementNumber;
3849  }
3850  if ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField) {
3851  $urlParameters['sortField'] = ‪$this->sortField;
3852  }
3853  if ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev) {
3854  $urlParameters['sortRev'] = ‪$this->sortRev;
3855  }
3856 
3857  $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters);
3858 
3859  if ($routePath = GeneralUtility::_GP('route')) {
3860  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
3861  $url = (string)$uriBuilder->buildUriFromRoutePath($routePath, $urlParameters);
3862  } else {
3863  $url = GeneralUtility::getIndpEnv('SCRIPT_NAME') . HttpUtility::buildQueryString($urlParameters, '?');
3864  }
3865  return $url;
3866  }
3867 
3872  public function ‪requestUri()
3873  {
3874  return $this->‪listURL();
3875  }
3876 
3885  public function ‪makeFieldList($table, $dontCheckUser = false, $addDateFields = false)
3886  {
3887  $backendUser = $this->‪getBackendUserAuthentication();
3888  // Init fieldlist array:
3889  $fieldListArr = [];
3890  // Check table:
3891  if (is_array(‪$GLOBALS['TCA'][‪$table]) && isset(‪$GLOBALS['TCA'][‪$table]['columns']) && is_array(
3892  ‪$GLOBALS['TCA'][‪$table]['columns']
3893  )) {
3894  if (isset(‪$GLOBALS['TCA'][‪$table]['columns']) && is_array(‪$GLOBALS['TCA'][‪$table]['columns'])) {
3895  // Traverse configured columns and add them to field array, if available for user.
3896  foreach (‪$GLOBALS['TCA'][‪$table]['columns'] as $fN => $fieldValue) {
3897  if ($fieldValue['config']['type'] === 'none') {
3898  // Never render or fetch type=none fields from db
3899  continue;
3900  }
3901  if ($dontCheckUser
3902  || (!$fieldValue['exclude'] || $backendUser->check('non_exclude_fields', ‪$table . ':' . $fN)) && $fieldValue['config']['type'] !== 'passthrough'
3903  ) {
3904  $fieldListArr[] = $fN;
3905  }
3906  }
3907 
3908  $fieldListArr[] = 'uid';
3909  $fieldListArr[] = 'pid';
3910 
3911  // Add date fields
3912  if ($dontCheckUser || $backendUser->isAdmin() || $addDateFields) {
3913  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['tstamp']) {
3914  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['tstamp'];
3915  }
3916  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['crdate']) {
3917  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['crdate'];
3918  }
3919  }
3920  // Add more special fields:
3921  if ($dontCheckUser || $backendUser->isAdmin()) {
3922  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['cruser_id']) {
3923  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['cruser_id'];
3924  }
3925  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby']) {
3926  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'];
3927  }
3928  if (ExtensionManagementUtility::isLoaded(
3929  'workspaces'
3930  ) && ‪$GLOBALS['TCA'][‪$table]['ctrl']['versioningWS']) {
3931  $fieldListArr[] = 't3ver_id';
3932  $fieldListArr[] = 't3ver_state';
3933  $fieldListArr[] = 't3ver_wsid';
3934  }
3935  }
3936  } else {
3937  GeneralUtility::makeInstance(LogManager::class)
3938  ->getLogger(__CLASS__)
3939  ->error('TCA is broken for the table "' . ‪$table . '": no required "columns" entry in TCA.');
3940  }
3941  }
3942  return $fieldListArr;
3943  }
3944 
3950  public function ‪localizationRedirect($justLocalized)
3951  {
3952  [‪$table, $orig_uid, $language] = explode(':', $justLocalized);
3953  if (‪$GLOBALS['TCA'][‪$table]
3954  && ‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']
3955  && ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']
3956  ) {
3957  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
3958  $queryBuilder->getRestrictions()
3959  ->removeAll()
3960  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3961  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
3962 
3963  $localizedRecordUid = $queryBuilder->select('uid')
3964  ->from(‪$table)
3965  ->where(
3966  $queryBuilder->expr()->eq(
3967  ‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'],
3968  $queryBuilder->createNamedParameter($language, \PDO::PARAM_INT)
3969  ),
3970  $queryBuilder->expr()->eq(
3971  ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'],
3972  $queryBuilder->createNamedParameter($orig_uid, \PDO::PARAM_INT)
3973  )
3974  )
3975  ->setMaxResults(1)
3976  ->execute()
3977  ->fetchColumn();
3978 
3979  if ($localizedRecordUid !== false) {
3980  // Create parameters and finally run the classic page module for creating a new page translation
3981  $url = $this->‪listURL();
3983  $uriBuilder = GeneralUtility::makeInstance(\‪TYPO3\CMS\Backend\Routing\UriBuilder::class);
3984 
3985  $editUserAccountUrl = (string)$uriBuilder->buildUriFromRoute(
3986  'record_edit',
3987  [
3988  'edit[' . ‪$table . '][' . $localizedRecordUid . ']' => 'edit',
3989  'returnUrl' => $url
3990  ]
3991  );
3992  HttpUtility::redirect($editUserAccountUrl);
3993  }
3994  }
3995  }
3996 
4002  public function ‪setOverrideUrlParameters(array $urlParameters)
4003  {
4004  $currentUrlParameter = GeneralUtility::_GP('curUrl');
4005  if (isset($currentUrlParameter['url'])) {
4006  $urlParameters['P']['currentValue'] = $currentUrlParameter['url'];
4007  }
4008  $this->overrideUrlParameters = $urlParameters;
4009  }
4010 
4023  public function ‪setTableDisplayOrder(array $orderInformation)
4024  {
4025  foreach ($orderInformation as $tableName => &$configuration) {
4026  if (isset($configuration['before'])) {
4027  if (is_string($configuration['before'])) {
4028  $configuration['before'] = GeneralUtility::trimExplode(',', $configuration['before'], true);
4029  } elseif (!is_array($configuration['before'])) {
4030  throw new \UnexpectedValueException(
4031  'The specified "before" order configuration for table "' . $tableName . '" is invalid.',
4032  1504793406
4033  );
4034  }
4035  }
4036  if (isset($configuration['after'])) {
4037  if (is_string($configuration['after'])) {
4038  $configuration['after'] = GeneralUtility::trimExplode(',', $configuration['after'], true);
4039  } elseif (!is_array($configuration['after'])) {
4040  throw new \UnexpectedValueException(
4041  'The specified "after" order configuration for table "' . $tableName . '" is invalid.',
4042  1504793407
4043  );
4044  }
4045  }
4046  }
4047  $this->tableDisplayOrder = $orderInformation;
4048  }
4049 
4053  public function ‪getOverridePageIdList(): array
4054  {
4056  }
4057 
4061  public function ‪setOverridePageIdList(array ‪$overridePageIdList)
4062  {
4063  $this->overridePageIdList = array_map('intval', ‪$overridePageIdList);
4064  }
4065 
4074  protected function ‪getSearchableWebmounts(‪$id, $depth, ‪$perms_clause)
4075  {
4076  $runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
4077  $hash = 'webmounts_list' . md5(‪$id . '-' . $depth . '-' . ‪$perms_clause);
4078  if ($runtimeCache->has($hash)) {
4079  $idList = $runtimeCache->get($hash);
4080  } else {
4081  $backendUser = $this->‪getBackendUserAuthentication();
4083  $tree = GeneralUtility::makeInstance(PageTreeView::class);
4084  $tree->init('AND ' . ‪$perms_clause);
4085  $tree->makeHTML = 0;
4086  $tree->fieldArray = ['uid', 'php_tree_stop'];
4087  $idList = [];
4088 
4089  $allowedMounts = !$backendUser->isAdmin() && ‪$id === 0
4090  ? $backendUser->returnWebmounts()
4091  : [‪$id];
4092 
4093  foreach ($allowedMounts as $allowedMount) {
4094  $idList[] = $allowedMount;
4095  if ($depth) {
4096  $tree->getTree($allowedMount, $depth, '');
4097  }
4098  $idList = array_merge($idList, $tree->ids);
4099  }
4100  $runtimeCache->set($hash, $idList);
4101  }
4102 
4103  return $idList;
4104  }
4105 
4114  protected function ‪addPageIdConstraint(string $tableName, ‪QueryBuilder $queryBuilder): ‪QueryBuilder
4115  {
4116  // Set search levels:
4118 
4119  // Set search levels to 999 instead of -1 as the following methods
4120  // do not support -1 as valid value for infinite search.
4121  if (‪$searchLevels === -1) {
4122  ‪$searchLevels = 999;
4123  }
4124 
4125  // When querying translated pages, the PID of the translated pages should be the same as the
4126  // the PID of the current page
4127  if ($tableName === 'pages' && $this->‪showOnlyTranslatedRecords) {
4128  $queryBuilder->‪andWhere(
4129  $queryBuilder->‪expr()->‪eq(
4130  $tableName . '.pid',
4131  $queryBuilder->‪createNamedParameter($this->pageRecord['pid'], \PDO::PARAM_INT)
4132  )
4133  );
4134  } elseif (‪$searchLevels === 0) {
4135  $queryBuilder->‪andWhere(
4136  $queryBuilder->‪expr()->‪eq(
4137  $tableName . '.pid',
4138  $queryBuilder->‪createNamedParameter($this->id, \PDO::PARAM_INT)
4139  )
4140  );
4141  } elseif (‪$searchLevels > 0) {
4142  $allowedMounts = $this->‪getSearchableWebmounts($this->id, ‪$searchLevels, $this->perms_clause);
4143  $queryBuilder->‪andWhere(
4144  $queryBuilder->‪expr()->‪in(
4145  $tableName . '.pid',
4146  $queryBuilder->‪createNamedParameter($allowedMounts, Connection::PARAM_INT_ARRAY)
4147  )
4148  );
4149  }
4150 
4151  if (!empty($this->‪getOverridePageIdList())) {
4152  $queryBuilder->‪andWhere(
4153  $queryBuilder->‪expr()->‪in(
4154  $tableName . '.pid',
4155  $queryBuilder->‪createNamedParameter($this->getOverridePageIdList(), Connection::PARAM_INT_ARRAY)
4156  )
4157  );
4158  }
4159 
4160  return $queryBuilder;
4161  }
4162 
4169  protected function ‪logDeprecation(string $index)
4170  {
4171  trigger_error('[index: ' . $index . '] $parameters in "buildQueryParameters"-Hook will be removed in TYPO3 v10.0, use $queryBuilder instead.', E_USER_DEPRECATED);
4172  }
4173 
4177  protected function ‪getBackendUserAuthentication()
4178  {
4179  return ‪$GLOBALS['BE_USER'];
4180  }
4181 
4196  public function ‪addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $colType = 'td')
4197  {
4198  $colType = ($colType === 'th') ? 'th' : 'td';
4199  $noWrap = $this->no_noWrap ? '' : ' nowrap';
4200  // Start up:
4201  $l10nParent = isset($data['_l10nparent_']) ? (int)$data['_l10nparent_'] : 0;
4202  $out = '
4203  <!-- Element, begin: -->
4204  <tr ' . $rowParams . ' data-uid="' . (int)$data['uid'] . '" data-l10nparent="' . $l10nParent . '">';
4205  // Show icon and lines
4206  if ($this->showIcon) {
4207  $out .= '
4208  <' . $colType . ' class="col-icon nowrap">';
4209  if (!$h) {
4210  $out .= '&nbsp;';
4211  } else {
4212  for ($a = 0; $a < $h; $a++) {
4213  if (!$a) {
4214  if ($icon) {
4215  $out .= $icon;
4216  }
4217  }
4218  }
4219  }
4220  $out .= '</' . $colType . '>
4221  ';
4222  }
4223  // Init rendering.
4224  $colsp = '';
4225  $lastKey = '';
4226  $c = 0;
4227  $ccount = 0;
4228  // __label is used as the label key to circumvent problems with uid used as label (see #67756)
4229  // as it was introduced later on, check if it really exists before using it
4231  if ($colType === 'td' && array_key_exists('__label', $data)) {
4232  ‪$fields[0] = '__label';
4233  }
4234  // Traverse field array which contains the data to present:
4235  foreach (‪$fields as $vKey) {
4236  if (isset($data[$vKey])) {
4237  if ($lastKey) {
4238  $cssClass = $this->addElement_tdCssClass[$lastKey];
4239  if ($this->oddColumnsCssClass && $ccount % 2 == 0) {
4240  $cssClass = implode(' ', [$this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass]);
4241  }
4242  $out .= '
4243  <' . $colType . ' class="' . $cssClass . $noWrap . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
4244  }
4245  $lastKey = $vKey;
4246  $c = 1;
4247  $ccount++;
4248  } else {
4249  if (!$lastKey) {
4250  $lastKey = $vKey;
4251  }
4252  $c++;
4253  }
4254  if ($c > 1) {
4255  $colsp = ' colspan="' . $c . '"';
4256  } else {
4257  $colsp = '';
4258  }
4259  }
4260  if ($lastKey) {
4261  $cssClass = $this->addElement_tdCssClass[$lastKey];
4262  if ($this->oddColumnsCssClass) {
4263  $cssClass = implode(' ', [$this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass]);
4264  }
4265  $out .= '
4266  <' . $colType . ' class="' . $cssClass . $noWrap . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
4267  }
4268  // End row
4269  $out .= '
4270  </tr>';
4271  // Return row.
4272  return $out;
4273  }
4274 
4278  public function ‪writeTop()
4279  {
4280  }
4281 
4288  public function ‪fwd_rwd_nav(‪$table = '')
4289  {
4290  $code = '';
4291  if ($this->eCounter >= $this->firstElementNumber && $this->eCounter < $this->firstElementNumber + $this->iLimit) {
4292  if ($this->firstElementNumber && $this->eCounter == $this->firstElementNumber) {
4293  // Reverse
4294  $theData = [];
4295  $titleCol = $this->fieldArray[0];
4296  $theData[$titleCol] = $this->‪fwd_rwd_HTML('fwd', $this->eCounter, ‪$table);
4297  $code = $this->‪addElement(1, '', $theData, 'class="fwd_rwd_nav"');
4298  }
4299  return [1, $code];
4300  }
4301  if ($this->eCounter == $this->firstElementNumber + $this->iLimit) {
4302  // Forward
4303  $theData = [];
4304  $titleCol = $this->fieldArray[0];
4305  $theData[$titleCol] = $this->‪fwd_rwd_HTML('rwd', $this->eCounter, ‪$table);
4306  $code = $this->‪addElement(1, '', $theData, 'class="fwd_rwd_nav"');
4307  }
4308  return [0, $code];
4309  }
4310 
4320  public function ‪fwd_rwd_HTML($type, ‪$pointer, ‪$table = '')
4321  {
4322  ‪$content = '';
4323  $tParam = ‪$table ? '&table=' . rawurlencode(‪$table) : '';
4324  switch ($type) {
4325  case 'fwd':
4326  $href = $this->‪listURL() . '&pointer=' . (‪$pointer - ‪$this->iLimit) . $tParam;
4327  ‪$content = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory->getIcon(
4328  'actions-move-up',
4329  Icon::SIZE_SMALL
4330  )->render() . '</a> <i>[' . (max(0, ‪$pointer - $this->iLimit) + 1) . ' - ' . ‪$pointer . ']</i>';
4331  break;
4332  case 'rwd':
4333  $href = $this->‪listURL() . '&pointer=' . ‪$pointer . $tParam;
4334  ‪$content = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory->getIcon(
4335  'actions-move-down',
4336  Icon::SIZE_SMALL
4337  )->render() . '</a> <i>[' . (‪$pointer + 1) . ' - ' . $this->totalItems . ']</i>';
4338  break;
4339  }
4340  return ‪$content;
4341  }
4342 
4348  public function ‪CBfunctions()
4349  {
4350  return '
4351  // checkOffCB()
4352  function checkOffCB(listOfCBnames, link) { //
4353  var checkBoxes, flag, i;
4354  var checkBoxes = listOfCBnames.split(",");
4355  if (link.rel === "") {
4356  link.rel = "allChecked";
4357  flag = true;
4358  } else {
4359  link.rel = "";
4360  flag = false;
4361  }
4362  for (i = 0; i < checkBoxes.length; i++) {
4363  setcbValue(checkBoxes[i], flag);
4364  }
4365  }
4366  // cbValue()
4367  function cbValue(CBname) { //
4368  var CBfullName = "CBC["+CBname+"]";
4369  return (document.dblistForm[CBfullName] && document.dblistForm[CBfullName].checked ? 1 : 0);
4370  }
4371  // setcbValue()
4372  function setcbValue(CBname,flag) { //
4373  CBfullName = "CBC["+CBname+"]";
4374  if(document.dblistForm[CBfullName]) {
4375  document.dblistForm[CBfullName].checked = flag ? "on" : 0;
4376  }
4377  }
4378 
4379  ';
4380  }
4381 
4385  public function ‪initializeLanguages()
4386  {
4387  // Look up page overlays:
4388  $localizationParentField = ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
4389  $languageField = ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'];
4390  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
4391  ->getQueryBuilderForTable('pages');
4392  $queryBuilder->getRestrictions()
4393  ->removeAll()
4394  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
4395  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
4396  $result = $queryBuilder
4397  ->select('*')
4398  ->from('pages')
4399  ->where(
4400  $queryBuilder->expr()->andX(
4401  $queryBuilder->expr()->eq($localizationParentField, $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
4402  $queryBuilder->expr()->gt(
4403  $languageField,
4404  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
4405  )
4406  )
4407  )
4408  ->execute();
4409 
4410  $this->pageOverlays = [];
4411  while ($row = $result->fetch()) {
4412  $this->pageOverlays[$row[$languageField]] = $row;
4413  }
4414 
4415  $this->languageIconTitles = $this->‪getTranslateTools()->‪getSystemLanguages($this->id);
4416  }
4417 
4425  public function ‪languageFlag($sys_language_uid, $addAsAdditionalText = true)
4426  {
4427  $out = '';
4428  $title = htmlspecialchars($this->languageIconTitles[$sys_language_uid]['title']);
4429  if ($this->languageIconTitles[$sys_language_uid]['flagIcon']) {
4430  $out .= '<span title="' . $title . '">' . $this->iconFactory->getIcon(
4431  $this->languageIconTitles[$sys_language_uid]['flagIcon'],
4432  Icon::SIZE_SMALL
4433  )->render() . '</span>';
4434  if (!$addAsAdditionalText) {
4435  return $out;
4436  }
4437  $out .= '&nbsp;';
4438  }
4439  $out .= $title;
4440  return $out;
4441  }
4442 
4446  protected function ‪determineScriptUrl()
4447  {
4448  if ($routePath = GeneralUtility::_GP('route')) {
4449  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
4450  $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath);
4451  } else {
4452  $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
4453  }
4454  }
4455 
4459  protected function ‪getThisScript()
4460  {
4461  return strpos($this->thisScript, '?') === false ? $this->thisScript . '?' : $this->thisScript . '&';
4462  }
4463 
4469  protected function ‪getTranslateTools()
4470  {
4471  if (!isset($this->translateTools)) {
4472  $this->translateTools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
4473  }
4474  return ‪$this->translateTools;
4475  }
4476 
4485  protected function ‪generateReferenceToolTip($references, $launchViewParameter = '')
4486  {
4487  if (!$references) {
4488  $htmlCode = '-';
4489  } else {
4490  $htmlCode = '<a href="#"';
4491  if ($launchViewParameter !== '') {
4492  $htmlCode .= ' onclick="' . htmlspecialchars(
4493  'top.TYPO3.InfoWindow.showItem(' . $launchViewParameter . '); return false;'
4494  ) . '"';
4495  }
4496  $htmlCode .= ' title="' . htmlspecialchars(
4497  $this->‪getLanguageService()->sL(
4498  'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references'
4499  ) . ' (' . $references . ')'
4500  ) . '">';
4501  $htmlCode .= $references;
4502  $htmlCode .= '</a>';
4503  }
4504  return $htmlCode;
4505  }
4506 
4514  {
4516  }
4517 
4528  protected function ‪getVisibleColumns(array $tableTCA, string $type)
4529  {
4530  $visibleColumns = $tableTCA['types'][$type]['showitem'] ?? '';
4531 
4532  if (strpos($visibleColumns, '--palette--') !== false) {
4533  $matches = [];
4534  preg_match_all('/--palette--\s*;[^;]*;\s*(\w+)/', $visibleColumns, $matches, PREG_SET_ORDER);
4535  if (!empty($matches)) {
4536  foreach ($matches as $palette) {
4537  $paletteColumns = $tableTCA['palettes'][$palette[1]]['showitem'] ?? '';
4538  $paletteColumns = rtrim($paletteColumns, ", \t\r\n");
4539  $visibleColumns = str_replace($palette[0], $paletteColumns, $visibleColumns);
4540  }
4541  }
4542  }
4543 
4544  return $visibleColumns;
4545  }
4546 
4551  protected function ‪getLanguageService()
4552  {
4553  return ‪$GLOBALS['LANG'];
4554  }
4555 
4560  public function ‪setLanguagesAllowedForUser(array ‪$languagesAllowedForUser): DatabaseRecordList
4561  {
4562  $this->languagesAllowedForUser = ‪$languagesAllowedForUser;
4563  return $this;
4564  }
4565 }
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$sortField
‪string $sortField
Definition: DatabaseRecordList.php:186
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\clipNumPane
‪bool clipNumPane()
Definition: DatabaseRecordList.php:2610
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$hideTables
‪string $hideTables
Definition: DatabaseRecordList.php:312
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$selFieldList
‪string $selFieldList
Definition: DatabaseRecordList.php:486
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageOverlays
‪array $pageOverlays
Definition: DatabaseRecordList.php:156
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setLanguagesAllowedForUser
‪DatabaseRecordList setLanguagesAllowedForUser(array $languagesAllowedForUser)
Definition: DatabaseRecordList.php:4478
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$clickTitleMode
‪string $clickTitleMode
Definition: DatabaseRecordList.php:361
‪TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface
Definition: RecordListGetTableHookInterface.php:22
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\renderListNavigation
‪string renderListNavigation($renderPart='top')
Definition: DatabaseRecordList.php:1800
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$duplicateField
‪string $duplicateField
Definition: DatabaseRecordList.php:443
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\outputCSV
‪outputCSV($prefix)
Definition: DatabaseRecordList.php:2776
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$recPath_cache
‪mixed[] $recPath_cache
Definition: DatabaseRecordList.php:180
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$itemsLimitPerTable
‪int $itemsLimitPerTable
Definition: DatabaseRecordList.php:192
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\__construct
‪__construct()
Definition: DatabaseRecordList.php:559
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showOnlyTranslatedRecords
‪bool $showOnlyTranslatedRecords
Definition: DatabaseRecordList.php:540
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\groupBy
‪QueryBuilder groupBy(... $groupBy)
Definition: QueryBuilder.php:679
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:31
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$cmd
‪string $cmd
Definition: RecordListController.php:144
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getQueryBuilder
‪TYPO3 CMS Core Database Query QueryBuilder getQueryBuilder(string $table, int $pageId, array $additionalConstraints=[], array $fields=[' *'])
Definition: DatabaseRecordList.php:3253
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$perms_clause
‪string $perms_clause
Definition: DatabaseRecordList.php:337
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getDocHeaderButtons
‪getDocHeaderButtons(ModuleTemplate $moduleTemplate)
Definition: DatabaseRecordList.php:712
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$CBnames
‪string[] $CBnames
Definition: DatabaseRecordList.php:467
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tablesCollapsed
‪int[][] $tablesCollapsed
Definition: DatabaseRecordList.php:260
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addToCSV
‪addToCSV(array $row=[])
Definition: DatabaseRecordList.php:2727
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getLanguageService
‪LanguageService getLanguageService()
Definition: DatabaseRecordList.php:4469
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getThisScript
‪string getThisScript()
Definition: DatabaseRecordList.php:4377
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$noControlPanels
‪bool $noControlPanels
Definition: DatabaseRecordList.php:110
‪TYPO3\CMS\Backend\Template\DocumentTemplate\makeShortcutIcon
‪string makeShortcutIcon($gvList, $setList, $modName, $motherModName='', $classes='')
Definition: DocumentTemplate.php:323
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getModule
‪BaseScriptClass getModule()
Definition: DatabaseRecordList.php:2887
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$duplicateStack
‪string[] $duplicateStack
Definition: DatabaseRecordList.php:220
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\eq
‪string eq(string $fieldName, $value)
Definition: ExpressionBuilder.php:107
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\logDeprecation
‪logDeprecation(string $index)
Definition: DatabaseRecordList.php:4087
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:25
‪TYPO3\CMS\Core\Imaging\Icon\render
‪string render($alternativeMarkupIdentifier=null)
Definition: Icon.php:231
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addSortLink
‪string addSortLink($code, $field, $table)
Definition: DatabaseRecordList.php:2625
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\calcPerms
‪int calcPerms($row)
Definition: BackendUserAuthentication.php:592
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\listURL
‪string listURL($altId='', $table='-1', $exclList='')
Definition: DatabaseRecordList.php:3737
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$iconFactory
‪IconFactory $iconFactory
Definition: DatabaseRecordList.php:506
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$hideTranslations
‪string $hideTranslations
Definition: DatabaseRecordList.php:168
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$disableSingleTableView
‪bool $disableSingleTableView
Definition: DatabaseRecordList.php:134
‪TYPO3\CMS\Core\Database\ReferenceIndex
Definition: ReferenceIndex.php:50
‪TYPO3
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$MOD_MENU
‪string[] $MOD_MENU
Definition: DatabaseRecordList.php:496
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getTable
‪string getTable($table, $id, $rowList='')
Definition: DatabaseRecordList.php:869
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$searchLevels
‪int $searchLevels
Definition: DatabaseRecordList.php:371
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showIcon
‪int $showIcon
Definition: DatabaseRecordList.php:365
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\createNamedParameter
‪string createNamedParameter($value, int $type=\PDO::PARAM_STR, string $placeHolder=null)
Definition: QueryBuilder.php:894
‪TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface\removeAll
‪QueryRestrictionContainerInterface removeAll()
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tableTSconfigOverTCA
‪mixed[][] $tableTSconfigOverTCA
Definition: DatabaseRecordList.php:395
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$overrideUrlParameters
‪mixed[] $overrideUrlParameters
Definition: DatabaseRecordList.php:528
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\writeTop
‪writeTop()
Definition: DatabaseRecordList.php:4196
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\isAdmin
‪bool isAdmin()
Definition: BackendUserAuthentication.php:294
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isRecordCurrentBackendUser
‪bool isRecordCurrentBackendUser($table, $row)
Definition: DatabaseRecordList.php:2821
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$dontShowClipControlPanels
‪bool $dontShowClipControlPanels
Definition: DatabaseRecordList.php:98
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\languageFlag
‪string languageFlag($sys_language_uid, $addAsAdditionalText=true)
Definition: DatabaseRecordList.php:4343
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\orderBy
‪QueryBuilder orderBy(string $fieldName, string $order=null)
Definition: QueryBuilder.php:794
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkUrlMail
‪string linkUrlMail($code, $testString)
Definition: DatabaseRecordList.php:3712
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getButtons
‪string[] getButtons()
Definition: DatabaseRecordList.php:577
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$totalRowCount
‪int $totalRowCount
Definition: DatabaseRecordList.php:122
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isRowListingConditionFulfilled
‪bool isRowListingConditionFulfilled($table, $row)
Definition: DatabaseRecordList.php:1321
‪TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction
Definition: BackendWorkspaceRestriction.php:28
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$overridePageIdList
‪array $overridePageIdList
Definition: DatabaseRecordList.php:523
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\getRestrictions
‪QueryRestrictionContainerInterface getRestrictions()
Definition: QueryBuilder.php:89
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:31
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$setFields
‪string[] $setFields
Definition: DatabaseRecordList.php:407
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$addElement_tdCssClass
‪array $addElement_tdCssClass
Definition: DatabaseRecordList.php:276
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$translations
‪string[] $translations
Definition: DatabaseRecordList.php:479
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$fieldArray
‪array $fieldArray
Definition: DatabaseRecordList.php:306
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$deprecatedPublicProperties
‪array $deprecatedPublicProperties
Definition: DatabaseRecordList.php:63
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getDocumentTemplate
‪DocumentTemplate getDocumentTemplate()
Definition: DatabaseRecordList.php:2895
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getSearchBox
‪string getSearchBox($formFields=true)
Definition: DatabaseRecordList.php:3117
‪TYPO3\CMS\Backend\Tree\View\PageTreeView
Definition: PageTreeView.php:23
‪$fields
‪$fields
Definition: pages.php:4
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$listOnlyInSingleTableMode
‪bool $listOnlyInSingleTableMode
Definition: DatabaseRecordList.php:232
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$table
‪string $table
Definition: DatabaseRecordList.php:349
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\initCSV
‪initCSV()
Definition: DatabaseRecordList.php:2698
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:40
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\createReferenceHtml
‪string createReferenceHtml($tableName, $uid)
Definition: DatabaseRecordList.php:2392
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$calcPerms
‪int $calcPerms
Definition: DatabaseRecordList.php:355
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\showNewRecLink
‪bool showNewRecLink($table)
Definition: DatabaseRecordList.php:2668
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showLimit
‪int $showLimit
Definition: DatabaseRecordList.php:300
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:23
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$currentTable
‪int[][] $currentTable
Definition: DatabaseRecordList.php:288
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tableList
‪string $tableList
Definition: DatabaseRecordList.php:449
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setDispFields
‪setDispFields()
Definition: DatabaseRecordList.php:3214
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$script
‪string $script
Definition: DatabaseRecordList.php:226
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\initializeLanguages
‪initializeLanguages()
Definition: DatabaseRecordList.php:4303
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setTableDisplayOrder
‪setTableDisplayOrder(array $orderInformation)
Definition: DatabaseRecordList.php:3941
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:47
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$itemsLimitSingleTable
‪int $itemsLimitSingleTable
Definition: DatabaseRecordList.php:254
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:36
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList
Definition: DatabaseRecordList.php:59
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getSearchFields
‪string[] getSearchFields($tableName)
Definition: DatabaseRecordList.php:3581
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tableDisplayOrder
‪array[] $tableDisplayOrder
Definition: DatabaseRecordList.php:517
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$HTMLcode
‪string $HTMLcode
Definition: DatabaseRecordList.php:270
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\renderListHeader
‪string renderListHeader($table, $currentIdList)
Definition: DatabaseRecordList.php:1540
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageRow
‪string[] $pageRow
Definition: DatabaseRecordList.php:144
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$oddColumnsCssClass
‪string $oddColumnsCssClass
Definition: DatabaseRecordList.php:324
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getTranslateTools
‪TranslationConfigurationProvider getTranslateTools()
Definition: DatabaseRecordList.php:4387
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$allowedNewTables
‪string[] $allowedNewTables
Definition: DatabaseRecordList.php:76
‪TYPO3\CMS\Recordlist\RecordList
Definition: AbstractDatabaseRecordList.php:2
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$displayFields
‪string[] $displayFields
Definition: DatabaseRecordList.php:318
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$currentLink
‪array $currentLink
Definition: DatabaseRecordList.php:534
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getPointerForPage
‪int getPointerForPage($page)
Definition: DatabaseRecordList.php:1789
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$thumbs
‪bool $thumbs
Definition: DatabaseRecordList.php:282
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\in
‪string in(string $fieldName, $value)
Definition: ExpressionBuilder.php:242
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$clipObj
‪TYPO3 CMS Backend Clipboard Clipboard $clipObj
Definition: DatabaseRecordList.php:461
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\fieldSelectBox
‪string fieldSelectBox($table, $formFields=true)
Definition: DatabaseRecordList.php:2477
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\removeControlFieldsFromFieldRow
‪static mixed[] removeControlFieldsFromFieldRow(array $row=[])
Definition: DatabaseRecordList.php:2743
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeReturnUrl
‪string makeReturnUrl()
Definition: DatabaseRecordList.php:2685
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$JScode
‪string $JScode
Definition: DatabaseRecordList.php:244
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\andWhere
‪QueryBuilder andWhere(... $where)
Definition: QueryBuilder.php:647
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$modSharedTSconfig
‪array $modSharedTSconfig
Definition: DatabaseRecordList.php:150
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$deniedNewTables
‪string[] $deniedNewTables
Definition: DatabaseRecordList.php:83
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setOverrideUrlParameters
‪setOverrideUrlParameters(array $urlParameters)
Definition: DatabaseRecordList.php:3920
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getSearchableWebmounts
‪int[] getSearchableWebmounts($id, $depth, $perms_clause)
Definition: DatabaseRecordList.php:3992
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:30
‪TYPO3\CMS\Backend\Module\BaseScriptClass
Definition: BaseScriptClass.php:72
‪TYPO3\CMS\Backend\Template\DocumentTemplate
Definition: DocumentTemplate.php:48
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$moduleTemplate
‪ModuleTemplate $moduleTemplate
Definition: RecordListController.php:213
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setCsvRow
‪setCsvRow($csvRow)
Definition: DatabaseRecordList.php:2762
‪TYPO3\CMS\Frontend\Page\PageRepository
Definition: PageRepository.php:53
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$clickMenuEnabled
‪bool $clickMenuEnabled
Definition: DatabaseRecordList.php:116
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:35
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\generateList
‪generateList()
Definition: DatabaseRecordList.php:3010
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeLocalizationPanel
‪string[] makeLocalizationPanel($table, $row)
Definition: DatabaseRecordList.php:2419
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkWrapTable
‪string linkWrapTable($table, $code)
Definition: DatabaseRecordList.php:3613
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$id
‪int $id
Definition: DatabaseRecordList.php:204
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$fixedL
‪int $fixedL
Definition: DatabaseRecordList.php:331
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$systemLanguagesOnPage
‪array $systemLanguagesOnPage
Definition: DatabaseRecordList.php:548
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\editLockPermissions
‪bool editLockPermissions()
Definition: DatabaseRecordList.php:2879
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$no_noWrap
‪int $no_noWrap
Definition: DatabaseRecordList.php:208
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setTotalItems
‪setTotalItems(string $table, int $pageId, array $constraints)
Definition: DatabaseRecordList.php:3438
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getReferenceCount
‪int getReferenceCount($tableName, $uid)
Definition: DatabaseRecordList.php:1520
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setIsEditable
‪setIsEditable($isEditable)
Definition: DatabaseRecordList.php:2829
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Core\Service\DependencyOrderingService
Definition: DependencyOrderingService.php:31
‪TYPO3\CMS\Core\Utility\CsvUtility
Definition: CsvUtility.php:23
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$searchString
‪string $searchString
Definition: DatabaseRecordList.php:431
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageRecord
‪string[] $pageRecord
Definition: DatabaseRecordList.php:401
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:45
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$thisScript
‪string $thisScript
Definition: DatabaseRecordList.php:238
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeControl
‪string makeControl($table, $row)
Definition: DatabaseRecordList.php:1913
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getOnClickForRow
‪string getOnClickForRow(string $table, array $row)
Definition: DatabaseRecordList.php:1278
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setOverridePageIdList
‪setOverridePageIdList(array $overridePageIdList)
Definition: DatabaseRecordList.php:3979
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:72
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$setLMargin
‪int $setLMargin
Definition: DatabaseRecordList.php:214
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkClipboardHeaderIcon
‪string linkClipboardHeaderIcon($string, $table, $cmd, $warning='', $title='')
Definition: DatabaseRecordList.php:2576
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$iLimit
‪int $iLimit
Definition: DatabaseRecordList.php:377
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showClipboard
‪bool $showClipboard
Definition: DatabaseRecordList.php:104
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\fwd_rwd_HTML
‪string fwd_rwd_HTML($type, $pointer, $table='')
Definition: DatabaseRecordList.php:4238
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$content
‪string $content
Definition: RecordListController.php:195
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addActionToCellGroup
‪addActionToCellGroup(&$cells, $action, $actionKey)
Definition: DatabaseRecordList.php:2799
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$returnUrl
‪string $returnUrl
Definition: DatabaseRecordList.php:343
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\setMaxResults
‪QueryBuilder setMaxResults(int $maxResults)
Definition: QueryBuilder.php:329
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:23
‪TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface
Definition: RecordListHookInterface.php:21
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$referenceCount
‪int[][] $referenceCount
Definition: DatabaseRecordList.php:473
‪TYPO3\CMS\Backend\Template\Components\DocHeaderComponent\getButtonBar
‪ButtonBar getButtonBar()
Definition: DocHeaderComponent.php:81
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$newWizards
‪bool $newWizards
Definition: DatabaseRecordList.php:92
‪$output
‪$output
Definition: annotationChecker.php:113
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\overlayEditLockPermissions
‪bool overlayEditLockPermissions($table, $row=[], $editPermission=true)
Definition: DatabaseRecordList.php:2857
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$modTSconfig
‪array[] $modTSconfig
Definition: DatabaseRecordList.php:264
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$editable
‪bool $editable
Definition: DatabaseRecordList.php:502
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
Definition: TranslationConfigurationProvider.php:35
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider\getSystemLanguages
‪array getSystemLanguages($pageId=0)
Definition: TranslationConfigurationProvider.php:51
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:22
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\localizationRedirect
‪localizationRedirect($justLocalized)
Definition: DatabaseRecordList.php:3868
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\prepareQueryBuilder
‪QueryBuilder prepareQueryBuilder(string $table, int $pageId, array $fieldList=[' *'], array $additionalConstraints=[], QueryBuilder $queryBuilder, bool $addSorting=true)
Definition: DatabaseRecordList.php:3290
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeSearchString
‪string makeSearchString($table, $currentPid=-1)
Definition: DatabaseRecordList.php:3472
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\renderListRow
‪string renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent=0)
Definition: DatabaseRecordList.php:1339
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\recPath
‪mixed[] recPath($pid)
Definition: DatabaseRecordList.php:2653
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\thumbCode
‪string thumbCode($row, $table, $field)
Definition: DatabaseRecordList.php:3238
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\setFirstResult
‪QueryBuilder setFirstResult(int $firstResult)
Definition: QueryBuilder.php:304
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:26
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\generateReferenceToolTip
‪string generateReferenceToolTip($references, $launchViewParameter='')
Definition: DatabaseRecordList.php:4403
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeClip
‪string makeClip($table, $row)
Definition: DatabaseRecordList.php:2235
‪TYPO3\CMS\Core\Log\LogManager
Definition: LogManager.php:25
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkWrapItems
‪string linkWrapItems($table, $uid, $code, $row)
Definition: DatabaseRecordList.php:3634
‪TYPO3\CMS\Backend\Template\ModuleTemplate\getDocHeaderComponent
‪DocHeaderComponent getDocHeaderComponent()
Definition: ModuleTemplate.php:314
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\fwd_rwd_nav
‪array fwd_rwd_nav($table='')
Definition: DatabaseRecordList.php:4206
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$counter
‪int $counter
Definition: DatabaseRecordList.php:413
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getVisibleColumns
‪string getVisibleColumns(array $tableTCA, string $type)
Definition: DatabaseRecordList.php:4446
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\determineScriptUrl
‪determineScriptUrl()
Definition: DatabaseRecordList.php:4364
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$csvOutput
‪bool $csvOutput
Definition: DatabaseRecordList.php:174
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\start
‪start($id, $table, $pointer, $search='', $levels=0, $showLimit=0)
Definition: DatabaseRecordList.php:2910
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addElement
‪string addElement($h, $icon, $data, $rowParams='', $_='', $_2='', $colType='td')
Definition: DatabaseRecordList.php:4114
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$leftMargin
‪int $leftMargin
Definition: DatabaseRecordList.php:389
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$spaceIcon
‪string $spaceIcon
Definition: DatabaseRecordList.php:128
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:21
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\showOnlyTranslatedRecords
‪showOnlyTranslatedRecords(bool $showOnlyTranslatedRecords)
Definition: DatabaseRecordList.php:4431
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:29
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$csvLines
‪string[] $csvLines
Definition: DatabaseRecordList.php:455
‪TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait
Definition: PublicPropertyDeprecationTrait.php:66
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getBackendUserAuthentication
‪BackendUserAuthentication getBackendUserAuthentication()
Definition: DatabaseRecordList.php:4095
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageinfo
‪mixed[] $pageinfo
Definition: DatabaseRecordList.php:490
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\addOrderBy
‪QueryBuilder addOrderBy(string $fieldName, string $order=null)
Definition: QueryBuilder.php:809
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface\add
‪QueryRestrictionContainerInterface add(QueryRestrictionInterface $restriction)
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$eCounter
‪int $eCounter
Definition: DatabaseRecordList.php:425
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$languageIconTitles
‪array $languageIconTitles
Definition: DatabaseRecordList.php:162
‪TYPO3\CMS\Core\Localization\LanguageService\getLL
‪string getLL($index)
Definition: LanguageService.php:118
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$languagesAllowedForUser
‪array $languagesAllowedForUser
Definition: DatabaseRecordList.php:554
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$addElement_tdParams
‪array $addElement_tdParams
Definition: DatabaseRecordList.php:198
‪TYPO3\CMS\Core\Imaging\IconFactory\getIcon
‪Icon getIcon($identifier, $size=Icon::SIZE_DEFAULT, $overlayIdentifier=null, IconState $state=null)
Definition: IconFactory.php:73
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$translateTools
‪TranslationConfigurationProvider $translateTools
Definition: DatabaseRecordList.php:248
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addPageIdConstraint
‪QueryBuilder addPageIdConstraint(string $tableName, QueryBuilder $queryBuilder)
Definition: DatabaseRecordList.php:4032
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\requestUri
‪string requestUri()
Definition: DatabaseRecordList.php:3790
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$sortRev
‪bool $sortRev
Definition: DatabaseRecordList.php:437
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addHeaderRowToCSV
‪addHeaderRowToCSV()
Definition: DatabaseRecordList.php:2706
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getOverridePageIdList
‪array getOverridePageIdList()
Definition: DatabaseRecordList.php:3971
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\where
‪QueryBuilder where(... $predicates)
Definition: QueryBuilder.php:630
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isEditable
‪bool isEditable($table)
Definition: DatabaseRecordList.php:2839
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:25
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\expr
‪ExpressionBuilder expr()
Definition: QueryBuilder.php:125
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$allFields
‪int $allFields
Definition: DatabaseRecordList.php:294
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\CBfunctions
‪string CBfunctions()
Definition: DatabaseRecordList.php:4266
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$totalItems
‪string $totalItems
Definition: DatabaseRecordList.php:383
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeFieldList
‪string[] makeFieldList($table, $dontCheckUser=false, $addDateFields=false)
Definition: DatabaseRecordList.php:3803
‪TYPO3\CMS\Recordlist\Controller\RecordListController\$pointer
‪int $pointer
Definition: RecordListController.php:95
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$firstElementNumber
‪int $firstElementNumber
Definition: DatabaseRecordList.php:419