‪TYPO3CMS  10.4
DatabaseRecordList.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
51 
57 {
58  // *********
59  // External:
60  // *********
61 
68  public ‪$allowedNewTables = [];
69 
76  public ‪$deniedNewTables = [];
77 
83  public ‪$dontShowClipControlPanels = false;
84 
90  public ‪$showClipboard = false;
91 
97  public ‪$noControlPanels = false;
98 
104  public ‪$clickMenuEnabled = true;
105 
111  public ‪$totalRowCount;
112 
118  public ‪$spaceIcon;
119 
125  public ‪$disableSingleTableView = false;
126 
127  // *********
128  // Internal:
129  // *********
130 
136  public ‪$pageRow = [];
137 
143  public ‪$pageOverlays = [];
144 
151 
157  public ‪$hideTranslations = '';
158 
164  public ‪$csvOutput = false;
165 
171  public ‪$recPath_cache = [];
172 
178  public ‪$sortField;
179 
185  public ‪$itemsLimitPerTable = 20;
186 
193  protected ‪$moduleData = [];
194 
200  public ‪$addElement_tdParams = [];
201 
207  public ‪$id;
208 
214  public ‪$duplicateStack = [];
215 
221  public ‪$script = 'index.php';
222 
228  public ‪$listOnlyInSingleTableMode = false;
229 
235  public ‪$thisScript = '';
236 
240  public ‪$translateTools;
241 
247  public ‪$itemsLimitSingleTable = 100;
248 
254  public ‪$tablesCollapsed = [];
255 
259  public ‪$modTSconfig;
260 
266  public ‪$HTMLcode = '';
267 
274 
280  public ‪$thumbs = false;
281 
287  public ‪$currentTable = [];
288 
294  public ‪$allFields = 0;
295 
301  public ‪$showLimit = 0;
302 
308  public ‪$fieldArray = [];
309 
315  public ‪$hideTables = '';
316 
323 
329  public ‪$oddColumnsCssClass = '';
330 
337  public ‪$fixedL = 30;
338 
344  public ‪$perms_clause = '';
345 
351  public ‪$returnUrl = '';
352 
358  public ‪$table = '';
359 
365  public ‪$calcPerms = 0;
366 
372  public ‪$clickTitleMode = '';
373 
377  public ‪$showIcon = 1;
378 
384  public ‪$searchLevels = 0;
385 
391  public ‪$iLimit = 0;
392 
398  public ‪$totalItems = '';
399 
405  public ‪$tableTSconfigOverTCA = [];
406 
412  public ‪$pageRecord = [];
413 
419  public ‪$setFields = [];
420 
426  public ‪$counter = 0;
427 
433  public ‪$firstElementNumber = 0;
434 
440  public ‪$eCounter = 0;
441 
447  public ‪$searchString = '';
448 
454  public ‪$sortRev;
455 
461  public ‪$duplicateField;
462 
468  public ‪$tableList = '';
469 
475  protected ‪$csvLines = [];
476 
482  public ‪$clipObj;
483 
489  public ‪$CBnames = [];
490 
496  protected ‪$referenceCount = [];
497 
503  public ‪$translations;
504 
511  public ‪$selFieldList;
512 
516  public ‪$pageinfo;
517 
523  public ‪$MOD_MENU;
524 
530  protected ‪$editable = true;
531 
535  protected ‪$iconFactory;
536 
540  protected ‪$uriBuilder;
541 
552  protected ‪$tableDisplayOrder = [];
553 
559  protected ‪$overridePageIdList = [];
560 
565  protected ‪$overrideUrlParameters = [];
566 
572  protected ‪$currentLink = [];
573 
579  protected ‪$showOnlyTranslatedRecords = false;
580 
588  protected ‪$systemLanguagesOnPage;
589 
595  protected ‪$languagesAllowedForUser = [];
596 
600  public function ‪__construct()
601  {
602  if (isset(‪$GLOBALS['BE_USER']->uc['titleLen']) && ‪$GLOBALS['BE_USER']->uc['titleLen'] > 0) {
603  $this->fixedL = ‪$GLOBALS['BE_USER']->uc['titleLen'];
604  }
605  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
606  $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
607 
608  $this->‪getTranslateTools();
609  $this->‪determineScriptUrl();
610  }
611 
618  public function ‪getDocHeaderButtons(‪ModuleTemplate $moduleTemplate)
619  {
620  $buttonBar = $moduleTemplate->‪getDocHeaderComponent()->‪getButtonBar();
621  $modulePageTsConfig = ‪BackendUtility::getPagesTSconfig($this->id)['mod.']['web_list.'] ?? [];
622  $backendUser = $this->‪getBackendUserAuthentication();
623  $lang = $this->‪getLanguageService();
624  // Get users permissions for this page record:
625  $localCalcPerms = $backendUser->calcPerms($this->pageRow);
626  // CSH
627  if ((string)$this->id === '') {
628  $fieldName = 'list_module_noId';
629  } elseif (!$this->id) {
630  $fieldName = 'list_module_root';
631  } else {
632  $fieldName = 'list_module';
633  }
634  $cshButton = $buttonBar->makeHelpButton()
635  ->setModuleName('xMOD_csh_corebe')
636  ->setFieldName($fieldName);
637  $buttonBar->addButton($cshButton);
638  if (isset($this->id)) {
639  // New record on pages that are not locked by editlock
640  if (!($modulePageTsConfig['noCreateRecordsLink'] ?? false) && $this->‪editLockPermissions()) {
641  $newRecordButton = $buttonBar->makeLinkButton()
642  ->setHref((string)$this->uriBuilder->buildUriFromRoute('db_new', ['id' => $this->id, 'returnUrl' => $this->listURL()]))
643  ->setTitle($lang->getLL('newRecordGeneral'))
644  ->setIcon($this->iconFactory->getIcon('actions-add', ‪Icon::SIZE_SMALL));
645  $buttonBar->addButton($newRecordButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 10);
646  }
647 
648  if ($this->id !== 0 && !in_array($this->pageRow['doktype'] ?? null, $this->‪getNoViewWithDokTypes($modulePageTsConfig))) {
649  $onClick = ‪BackendUtility::viewOnClick($this->id, '', ‪BackendUtility::BEgetRootLine($this->id));
650  $viewButton = $buttonBar->makeLinkButton()
651  ->setHref('#')
652  ->setOnClick($onClick)
653  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
654  ->setIcon($this->iconFactory->getIcon('actions-view-page', ‪Icon::SIZE_SMALL));
655  $buttonBar->addButton($viewButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 20);
656  }
657  // If edit permissions are set, see
658  // \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
659  if ($localCalcPerms & ‪Permission::PAGE_EDIT && !empty($this->id) && $this->‪editLockPermissions() && $backendUser->checkLanguageAccess(0)) {
660  // Edit
661  $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit';
662  $editLink = $this->uriBuilder->buildUriFromRoute('record_edit') . $params . $this->‪makeReturnUrl();
663  $editButton = $buttonBar->makeLinkButton()
664  ->setHref($editLink)
665  ->setTitle($lang->getLL('editPage'))
666  ->setIcon($this->iconFactory->getIcon('actions-page-open', ‪Icon::SIZE_SMALL));
667  $buttonBar->addButton($editButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 20);
668  }
669  // Paste
670  if ($this->showClipboard && ($localCalcPerms & ‪Permission::PAGE_NEW || $localCalcPerms & ‪Permission::CONTENT_EDIT) && $this->‪editLockPermissions()) {
671  $elFromTable = $this->clipObj->elFromTable('');
672  if (!empty($elFromTable)) {
673  $confirmMessage = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable);
674  $pasteButton = $buttonBar->makeLinkButton()
675  ->setHref($this->clipObj->pasteUrl('', $this->id))
676  ->setTitle($lang->getLL('clip_paste'))
677  ->setClasses('t3js-modal-trigger')
678  ->setDataAttributes([
679  'severity' => 'warning',
680  'content' => $confirmMessage,
681  'title' => $lang->getLL('clip_paste')
682  ])
683  ->setIcon($this->iconFactory->getIcon('actions-document-paste-into', ‪Icon::SIZE_SMALL));
684  $buttonBar->addButton($pasteButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 40);
685  }
686  }
687  // Cache
688  if ($this->id !== 0) {
689  $clearCacheButton = $buttonBar->makeLinkButton()
690  ->setHref('#')
691  ->setDataAttributes(['id' => $this->id])
692  ->setClasses('t3js-clear-page-cache')
693  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
694  ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', ‪Icon::SIZE_SMALL));
695  $buttonBar->addButton($clearCacheButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
696  }
697  if ($this->table && (!isset($modulePageTsConfig['noExportRecordsLinks'])
698  || (isset($modulePageTsConfig['noExportRecordsLinks'])
699  && !$modulePageTsConfig['noExportRecordsLinks']))
700  ) {
701  // CSV
702  $csvButton = $buttonBar->makeLinkButton()
703  ->setHref($this->‪listURL() . '&csv=1')
704  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.csv'))
705  ->setIcon($this->iconFactory->getIcon('actions-document-export-csv', ‪Icon::SIZE_SMALL))
706  ->setShowLabelText(true);
707  $buttonBar->addButton($csvButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 40);
708  // Export
710  $url = (string)$this->uriBuilder->buildUriFromRoute('tx_impexp_export');
711  $exportButton = $buttonBar->makeLinkButton()
712  ->setHref($url . '&tx_impexp[list][]=' . rawurlencode($this->table . ':' . $this->id))
713  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.export'))
714  ->setIcon($this->iconFactory->getIcon('actions-document-export-t3d', ‪Icon::SIZE_SMALL))
715  ->setShowLabelText(true);
716  $buttonBar->addButton($exportButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 40);
717  }
718  }
719  // Reload
720  $reloadButton = $buttonBar->makeLinkButton()
721  ->setHref($this->‪listURL())
722  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
723  ->setIcon($this->iconFactory->getIcon('actions-refresh', ‪Icon::SIZE_SMALL));
724  $buttonBar->addButton($reloadButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
725  // Shortcut
726  if ($backendUser->mayMakeShortcut()) {
727  $shortCutButton = $buttonBar->makeShortcutButton()
728  ->setModuleName('web_list')
729  ->setGetVariables([
730  'id',
731  'route',
732  'imagemode',
733  'pointer',
734  'table',
735  'search_field',
736  'search_levels',
737  'showLimit',
738  'sortField',
739  'sortRev'
740  ])
741  ->setSetVariables(array_keys($this->MOD_MENU));
742  $buttonBar->addButton($shortCutButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
743  }
744  // Back
745  if ($this->returnUrl) {
746  $backButton = $buttonBar->makeLinkButton()
747  ->setHref($this->returnUrl)
748  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
749  ->setIcon($this->iconFactory->getIcon('actions-view-go-back', ‪Icon::SIZE_SMALL));
750  $buttonBar->addButton($backButton, ‪ButtonBar::BUTTON_POSITION_LEFT);
751  }
752  }
753  }
754 
764  public function ‪getTable(‪$table, ‪$id, $rowList = '')
765  {
766  $rowListArray = ‪GeneralUtility::trimExplode(',', $rowList, true);
767  // if no columns have been specified, show description (if configured)
768  if (!empty(‪$GLOBALS['TCA'][‪$table]['ctrl']['descriptionColumn']) && empty($rowListArray)) {
769  $rowListArray[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['descriptionColumn'];
770  }
771  $backendUser = $this->‪getBackendUserAuthentication();
772  $lang = $this->‪getLanguageService();
773  // Init
774  $addWhere = '';
775  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
776  $titleCol = ‪$GLOBALS['TCA'][‪$table]['ctrl']['label'];
777  $thumbsCol = ‪$GLOBALS['TCA'][‪$table]['ctrl']['thumbnail'];
778  $l10nEnabled = ‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']
779  && ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'];
780  $tableCollapsed = (bool)$this->tablesCollapsed[‪$table];
781  // prepare space icon
782  $this->spaceIcon = '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', ‪Icon::SIZE_SMALL)->render() . '</span>';
783  // Cleaning rowlist for duplicates and place the $titleCol as the first column always!
784  $this->fieldArray = [];
785  // title Column
786  // Add title column
787  $this->fieldArray[] = $titleCol;
788  // Control-Panel
789  if (!GeneralUtility::inList($rowList, '_CONTROL_')) {
790  $this->fieldArray[] = '_CONTROL_';
791  }
792  // Clipboard
793  if ($this->showClipboard) {
794  $this->fieldArray[] = '_CLIPBOARD_';
795  }
796  // Ref
797  if (!$this->dontShowClipControlPanels) {
798  $this->fieldArray[] = '_REF_';
799  }
800  // Path
801  if ($this->searchLevels) {
802  $this->fieldArray[] = '_PATH_';
803  }
804  // Localization
805  if ($l10nEnabled) {
806  $this->fieldArray[] = '_LOCALIZATION_';
807  // Do not show the "Localize to:" field when only translated records should be shown
808  if (!$this->‪showOnlyTranslatedRecords) {
809  $this->fieldArray[] = '_LOCALIZATION_b';
810  }
811  // Only restrict to the default language if no search request is in place
812  // And if only translations should be shown
813  if ($this->searchString === '' && !$this->‪showOnlyTranslatedRecords) {
814  $addWhere = '(' . (string)$queryBuilder->expr()->orX(
815  $queryBuilder->expr()->lte(‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'], 0),
816  $queryBuilder->expr()->eq(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'], 0)
817  ) . ')';
818  }
819  }
820  // Cleaning up:
821  $this->fieldArray = array_unique(array_merge($this->fieldArray, $rowListArray));
822  if ($this->noControlPanels) {
823  $tempArray = array_flip($this->fieldArray);
824  unset($tempArray['_CONTROL_']);
825  unset($tempArray['_CLIPBOARD_']);
826  $this->fieldArray = array_keys($tempArray);
827  }
828  // Creating the list of fields to include in the SQL query:
829  $selectFields = ‪$this->fieldArray;
830  $selectFields[] = 'uid';
831  $selectFields[] = 'pid';
832  // adding column for thumbnails
833  if ($thumbsCol) {
834  $selectFields[] = $thumbsCol;
835  }
836  if (‪$table === 'pages') {
837  $selectFields[] = 'module';
838  $selectFields[] = 'extendToSubpages';
839  $selectFields[] = 'nav_hide';
840  $selectFields[] = 'doktype';
841  $selectFields[] = 'shortcut';
842  $selectFields[] = 'shortcut_mode';
843  $selectFields[] = 'mount_pid';
844  }
845  if (is_array(‪$GLOBALS['TCA'][‪$table]['ctrl']['enablecolumns'])) {
846  $selectFields = array_merge($selectFields, ‪$GLOBALS['TCA'][‪$table]['ctrl']['enablecolumns']);
847  }
848  foreach (['type', 'typeicon_column', 'editlock'] as $field) {
849  if (‪$GLOBALS['TCA'][‪$table]['ctrl'][$field]) {
850  $selectFields[] = ‪$GLOBALS['TCA'][‪$table]['ctrl'][$field];
851  }
852  }
854  $selectFields[] = 't3ver_state';
855  $selectFields[] = 't3ver_wsid';
856  $selectFields[] = 't3ver_oid';
857  }
858  if ($l10nEnabled) {
859  $selectFields[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'];
860  $selectFields[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'];
861  }
862  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['label_alt']) {
863  $selectFields = array_merge(
864  $selectFields,
865  ‪GeneralUtility::trimExplode(',', ‪$GLOBALS['TCA'][‪$table]['ctrl']['label_alt'], true)
866  );
867  }
868  // Unique list!
869  $selectFields = array_unique($selectFields);
870  $fieldListFields = $this->‪makeFieldList($table, true);
871  if (empty($fieldListFields) && ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['debug']) {
872  $message = sprintf($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:missingTcaColumnsMessage'), ‪$table, ‪$table);
873  $messageTitle = $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:missingTcaColumnsMessageTitle');
875  $flashMessage = GeneralUtility::makeInstance(
876  FlashMessage::class,
877  $message,
878  $messageTitle,
880  true
881  );
883  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
885  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
886  $defaultFlashMessageQueue->enqueue($flashMessage);
887  }
888  // Making sure that the fields in the field-list ARE in the field-list from TCA!
889  $selectFields = array_intersect($selectFields, $fieldListFields);
890  // Implode it into a list of fields for the SQL-statement.
891  ‪$selFieldList = implode(',', $selectFields);
892  $this->selFieldList = ‪$selFieldList;
893  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'] ?? [] as $className) {
894  $hookObject = GeneralUtility::makeInstance($className);
895  if (!$hookObject instanceof RecordListGetTableHookInterface) {
896  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListGetTableHookInterface::class, 1195114460);
897  }
898  $hookObject->getDBlistQuery(‪$table, ‪$id, $addWhere, ‪$selFieldList, $this);
899  }
900 
901  if (‪$table == 'pages' && $this->‪showOnlyTranslatedRecords) {
902  $addWhere .= ' AND ' . ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'] . ' IN(' . implode(',', array_keys($this->languagesAllowedForUser)) . ')';
903  }
904 
905  $additionalConstraints = empty($addWhere) ? [] : [‪QueryHelper::stripLogicalOperatorPrefix($addWhere)];
907 
908  // Create the SQL query for selecting the elements in the listing:
909  // do not do paging when outputting as CSV
910  if ($this->csvOutput) {
911  $this->iLimit = 0;
912  }
913  if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
914  // Get the two previous rows for sorting if displaying page > 1
915  $this->firstElementNumber -= 2;
916  $this->iLimit += 2;
917  $queryBuilder = $this->‪getQueryBuilder($table, ‪$id, $additionalConstraints);
918  $this->firstElementNumber += 2;
919  $this->iLimit -= 2;
920  } else {
921  $queryBuilder = $this->‪getQueryBuilder($table, ‪$id, $additionalConstraints);
922  }
923 
924  // Finding the total amount of records on the page
925  $this->‪setTotalItems($table, ‪$id, $additionalConstraints);
926 
927  // Init:
928  $queryResult = $queryBuilder->execute();
929  $dbCount = 0;
930  $out = '';
931  $tableHeader = '';
932  ‪$listOnlyInSingleTableMode = $this->listOnlyInSingleTableMode && !‪$this->table;
933  // If the count query returned any number of records, we perform the real query,
934  // selecting records.
935  if ($this->totalItems) {
936  // Fetch records only if not in single table mode
938  $dbCount = ‪$this->totalItems;
939  } else {
940  // Set the showLimit to the number of records when outputting as CSV
941  if ($this->csvOutput) {
942  $this->showLimit = ‪$this->totalItems;
943  $this->iLimit = ‪$this->totalItems;
944  $dbCount = ‪$this->totalItems;
945  } else {
946  if ($this->firstElementNumber + $this->showLimit <= $this->totalItems) {
947  $dbCount = $this->showLimit + 2;
948  } else {
949  $dbCount = $this->totalItems - $this->firstElementNumber + 2;
950  }
951  }
952  }
953  }
954  // If any records was selected, render the list:
955  if ($dbCount) {
956  $tableIdentifier = ‪$table;
957  // Use a custom table title for translated pages
958  if (‪$table == 'pages' && $this->‪showOnlyTranslatedRecords) {
959  // pages records in list module are split into two own sections, one for pages with
960  // sys_language_uid = 0 "Page" and an own section for sys_language_uid > 0 "Page Translation".
961  // This if sets the different title for the page translation case and a unique table identifier
962  // which is used in DOM as id.
963  $tableTitle = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:pageTranslation'));
964  $tableIdentifier = 'pages_translated';
965  } else {
966  $tableTitle = htmlspecialchars($lang->sL(‪$GLOBALS['TCA'][‪$table]['ctrl']['title']));
967  if ($tableTitle === '') {
968  $tableTitle = ‪$table;
969  }
970  }
971  // Header line is drawn
972  $theData = [];
973  if ($this->disableSingleTableView) {
974  $theData[$titleCol] = '<span class="c-table">' . ‪BackendUtility::wrapInHelp(‪$table, '', $tableTitle)
975  . '</span> (<span class="t3js-table-total-items">' . $this->totalItems . '</span>)';
976  } else {
977  $icon = $this->table
978  ? '<span title="' . htmlspecialchars($lang->getLL('contractView')) . '">' . $this->iconFactory->getIcon('actions-view-table-collapse', ‪Icon::SIZE_SMALL)->render() . '</span>'
979  : '<span title="' . htmlspecialchars($lang->getLL('expandView')) . '">' . $this->iconFactory->getIcon('actions-view-table-expand', ‪Icon::SIZE_SMALL)->render() . '</span>';
980  $theData[$titleCol] = $this->‪linkWrapTable($table, $tableTitle . ' (<span class="t3js-table-total-items">' . $this->totalItems . '</span>) ' . $icon);
981  }
983  $tableHeader .= ‪BackendUtility::wrapInHelp(‪$table, '', $theData[$titleCol]);
984  } else {
985  // Render collapse button if in multi table mode
986  $collapseIcon = '';
987  if (!$this->table) {
988  $title = $tableCollapsed
989  ? htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.expandTable'))
990  : htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.collapseTable'));
991  $icon = '<span class="collapseIcon">' . $this->iconFactory->getIcon(($tableCollapsed ? 'actions-view-list-expand' : 'actions-view-list-collapse'), ‪Icon::SIZE_SMALL)->render() . '</span>';
992  $collapseIcon = '<a href="#" title="' . $title . '" class="pull-right t3js-toggle-recordlist" data-table="' . htmlspecialchars($tableIdentifier) . '" data-toggle="collapse" data-target="#recordlist-' . htmlspecialchars($tableIdentifier) . '">' . $icon . '</a>';
993  }
994  $tableHeader .= $theData[$titleCol] . $collapseIcon;
995  }
996  // Render table rows only if in multi table view or if in single table view
997  $rowOutput = '';
998  if (!‪$listOnlyInSingleTableMode || $this->table) {
999  // Fixing an order table for sortby tables
1000  $this->currentTable = [];
1001  $currentIdList = [];
1002  $doSort = ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] && !‪$this->sortField;
1003  $prevUid = 0;
1004  $prevPrevUid = 0;
1005  // Get first two rows and initialize prevPrevUid and prevUid if on page > 1
1006  if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
1007  $row = $queryResult->fetch();
1008  $prevPrevUid = -((int)$row['uid']);
1009  $row = $queryResult->fetch();
1010  $prevUid = $row['uid'];
1011  }
1012  $accRows = [];
1013  // Accumulate rows here
1014  while ($row = $queryResult->fetch()) {
1015  if (!$this->‪isRowListingConditionFulfilled($table, $row)) {
1016  continue;
1017  }
1018  // In offline workspace, look for alternative record:
1019  ‪BackendUtility::workspaceOL(‪$table, $row, $backendUser->workspace, true);
1020  if (is_array($row)) {
1021  $accRows[] = $row;
1022  $currentIdList[] = $row['uid'];
1023  if ($doSort) {
1024  if ($prevUid) {
1025  $this->currentTable['prev'][$row['uid']] = $prevPrevUid;
1026  $this->currentTable['next'][$prevUid] = '-' . $row['uid'];
1027  $this->currentTable['prevUid'][$row['uid']] = $prevUid;
1028  }
1029  $prevPrevUid = isset($this->currentTable['prev'][$row['uid']]) ? -$prevUid : $row['pid'];
1030  $prevUid = $row['uid'];
1031  }
1032  }
1033  }
1034  $this->totalRowCount = count($accRows);
1035  // CSV initiated
1036  if ($this->csvOutput) {
1037  $this->‪initCSV();
1038  }
1039  // Render items:
1040  $this->CBnames = [];
1041  $this->duplicateStack = [];
1042  $this->eCounter = ‪$this->firstElementNumber;
1043  $cc = 0;
1044  foreach ($accRows as $row) {
1045  // Render item row if counter < limit
1046  if ($cc < $this->iLimit) {
1047  $cc++;
1048  $this->translations = false;
1049  $rowOutput .= $this->‪renderListRow($table, $row, $cc, $titleCol, $thumbsCol);
1050  // If no search happened it means that the selected
1051  // records are either default or All language and here we will not select translations
1052  // which point to the main record:
1053  if ($l10nEnabled && $this->searchString === '' && !($this->hideTranslations === '*' || GeneralUtility::inList($this->hideTranslations, ‪$table))) {
1054  // For each available translation, render the record:
1055  if (is_array($this->translations)) {
1056  foreach ($this->translations as $lRow) {
1057  // $lRow isn't always what we want - if record was moved we've to work with the
1058  // placeholder records otherwise the list is messed up a bit
1059  if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) {
1060  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1061  ->getQueryBuilderForTable(‪$table);
1062  $queryBuilder->getRestrictions()
1063  ->removeAll()
1064  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1065  $predicates = [
1066  $queryBuilder->expr()->eq(
1067  't3ver_move_id',
1068  $queryBuilder->createNamedParameter((int)$lRow['uid'], \PDO::PARAM_INT)
1069  ),
1070  $queryBuilder->expr()->eq(
1071  'pid',
1072  $queryBuilder->createNamedParameter((int)$row['_MOVE_PLH_pid'], \PDO::PARAM_INT)
1073  ),
1074  $queryBuilder->expr()->eq(
1075  't3ver_wsid',
1076  $queryBuilder->createNamedParameter((int)$row['t3ver_wsid'], \PDO::PARAM_INT)
1077  ),
1078  ];
1079 
1080  $tmpRow = $queryBuilder
1081  ->select(...‪$selFieldList)
1082  ->from(‪$table)
1083  ->andWhere(...$predicates)
1084  ->execute()
1085  ->fetch();
1087  $lRow = is_array($tmpRow) ? $tmpRow : $lRow;
1088  }
1089  if (!$this->‪isRowListingConditionFulfilled($table, $lRow)) {
1090  continue;
1091  }
1092  // In offline workspace, look for alternative record:
1093  ‪BackendUtility::workspaceOL(‪$table, $lRow, $backendUser->workspace, true);
1094  if (is_array($lRow) && $backendUser->checkLanguageAccess($lRow[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']])) {
1095  $currentIdList[] = $lRow['uid'];
1096  $rowOutput .= $this->‪renderListRow($table, $lRow, $cc, $titleCol, $thumbsCol, 18);
1097  }
1098  }
1099  }
1100  }
1101  }
1102  // Counter of total rows incremented:
1103  $this->eCounter++;
1104  }
1105  // Record navigation is added to the beginning and end of the table if in single
1106  // table mode
1107  if ($this->table) {
1108  $rowOutput = $this->‪renderListNavigation('top') . $rowOutput . $this->‪renderListNavigation('bottom');
1109  } else {
1110  // Show that there are more records than shown
1111  if ($this->totalItems > $this->itemsLimitPerTable) {
1112  $countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable ? $this->itemsLimitSingleTable : ‪$this->totalItems;
1113  $hasMore = $this->totalItems > ‪$this->itemsLimitSingleTable;
1114  $colspan = $this->showIcon ? count($this->fieldArray) + 1 : count($this->fieldArray);
1115  $rowOutput .= '<tr><td colspan="' . $colspan . '">
1116  <a href="' . htmlspecialchars($this->‪listURL() . '&table=' . rawurlencode($tableIdentifier)) . '" class="btn btn-default">'
1117  . '<span class="t3-icon fa fa-chevron-down"></span> <i>[1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . ']</i></a>
1118  </td></tr>';
1119  }
1120  }
1121  // The header row for the table is now created:
1122  $out .= $this->‪renderListHeader($table, $currentIdList);
1123  }
1124 
1125  $collapseClass = $tableCollapsed && !$this->table ? 'collapse' : 'collapse in';
1126  $dataState = $tableCollapsed && !$this->table ? 'collapsed' : 'expanded';
1127 
1128  // The list of records is added after the header and wrapped
1129  $out .= $rowOutput;
1130  $out = '
1131  <div class="panel panel-space panel-default recordlist" id="t3-table-' . htmlspecialchars($tableIdentifier) . '">
1132  <div class="panel-heading">
1133  ' . $tableHeader . '
1134  </div>
1135  <div class="' . $collapseClass . '" data-state="' . $dataState . '" id="recordlist-' . htmlspecialchars($tableIdentifier) . '">
1136  <div class="table-fit">
1137  <table data-table="' . htmlspecialchars($tableIdentifier) . '" class="table table-striped table-hover' . (‪$listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '">
1138  ' . $out . '
1139  </table>
1140  </div>
1141  </div>
1142  </div>
1143  ';
1144  // Output csv if...
1145  // This ends the page with exit.
1146  if ($this->csvOutput) {
1147  $this->‪outputCSV($table);
1148  }
1149  }
1150  // Return content:
1151  return $out;
1152  }
1153 
1162  protected function ‪getOnClickForRow(string ‪$table, array $row): string
1163  {
1164  if (‪$table === 'tt_content') {
1165  // Link to a content element, possibly translated and with anchor
1166  $additionalParams = '';
1167  $language = (int)$row[‪$GLOBALS['TCA']['tt_content']['ctrl']['languageField']];
1168  if ($language > 0) {
1169  $additionalParams = '&L=' . $language;
1170  }
1171  $onClick = ‪BackendUtility::viewOnClick(
1172  $this->id,
1173  '',
1174  null,
1175  '#c' . $row['uid'],
1176  '',
1177  $additionalParams
1178  );
1179  } elseif (‪$table === 'pages' && $row[‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']] > 0) {
1180  // Link to a page translation needs uid of default language page as id
1181  $onClick = ‪BackendUtility::viewOnClick(
1182  $row[‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']],
1183  '',
1184  null,
1185  '',
1186  '',
1187  '&L=' . (int)$row[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']]
1188  );
1189  } else {
1190  // Link to a page in the default language
1191  $onClick = ‪BackendUtility::viewOnClick($row['uid']);
1192  }
1193  return $onClick;
1194  }
1195 
1205  protected function ‪isRowListingConditionFulfilled(‪$table, $row)
1206  {
1207  return true;
1208  }
1209 
1223  public function ‪renderListRow(‪$table, $row, $cc, $titleCol, $thumbsCol, $indent = 0)
1224  {
1225  if (!is_array($row)) {
1226  return '';
1227  }
1228  $languageService = $this->‪getLanguageService();
1229  $rowOutput = '';
1230  $id_orig = null;
1231  // If in search mode, make sure the preview will show the correct page
1232  if ((string)$this->searchString !== '') {
1233  $id_orig = ‪$this->id;
1234  $this->id = $row['pid'];
1235  }
1236 
1237  $tagAttributes = [
1238  'class' => [],
1239  'data-table' => ‪$table,
1240  'title' => 'id=' . $row['uid'],
1241  ];
1242 
1243  // Add active class to record of current link
1244  if (
1245  isset($this->currentLink['tableNames'])
1246  && (int)$this->currentLink['uid'] === (int)$row['uid']
1247  && GeneralUtility::inList($this->currentLink['tableNames'], ‪$table)
1248  ) {
1249  $tagAttributes['class'][] = 'active';
1250  }
1251  // Add special classes for first and last row
1252  if ($cc == 1 && $indent == 0) {
1253  $tagAttributes['class'][] = 'firstcol';
1254  }
1255  if ($cc == $this->totalRowCount || $cc == $this->iLimit) {
1256  $tagAttributes['class'][] = 'lastcol';
1257  }
1258  // Overriding with versions background color if any:
1259  if (!empty($row['_CSSCLASS'])) {
1260  $tagAttributes['class'] = [$row['_CSSCLASS']];
1261  }
1262 
1263  $tagAttributes['class'][] = 't3js-entity';
1264 
1265  // Incr. counter.
1266  $this->counter++;
1267  // The icon with link
1269  $additionalStyle = $indent ? ' style="margin-left: ' . $indent . 'px;"' : '';
1270  $iconImg = '<span ' . $toolTip . ' ' . $additionalStyle . '>'
1271  . $this->iconFactory->getIconForRecord(‪$table, $row, ‪Icon::SIZE_SMALL)->render()
1272  . '</span>';
1273  $theIcon = ($this->clickMenuEnabled && !$this->‪isRecordDeletePlaceholder($row)) ? ‪BackendUtility::wrapClickMenuOnIcon($iconImg, ‪$table, $row['uid']) : $iconImg;
1274  // Preparing and getting the data-array
1275  $theData = [];
1276  $localizationMarkerClass = '';
1277  $deletePlaceholderClass = '';
1278  foreach ($this->fieldArray as $fCol) {
1279  if ($fCol == $titleCol) {
1280  $recTitle = ‪BackendUtility::getRecordTitle(‪$table, $row, false, true);
1281  $warning = '';
1282  // If the record is edit-locked by another user, we will show a little warning sign:
1283  $lockInfo = ‪BackendUtility::isRecordLocked(‪$table, $row['uid']);
1284  if ($lockInfo) {
1285  $warning = '<span data-toggle="tooltip" data-placement="right" data-title="' . htmlspecialchars($lockInfo['msg']) . '">'
1286  . $this->iconFactory->getIcon('warning-in-use', ‪Icon::SIZE_SMALL)->render() . '</span>';
1287  }
1288  if ($this->‪isRecordDeletePlaceholder($row)) {
1289  // Delete placeholder records do not link to formEngine edit and are rendered strike-through
1290  $deletePlaceholderClass = ' deletePlaceholder';
1291  $theData[$fCol] = $theData['__label'] =
1292  $warning
1293  . '<span title="' . htmlspecialchars($languageService->sL('LLL:EXT:recordlist/Resources/Private/Language/locallang.xlf:row.deletePlaceholder.title')) . '">'
1294  . htmlspecialchars($recTitle)
1295  . '</span>';
1296  } else {
1297  $theData[$fCol] = $theData['__label'] = $warning . $this->‪linkWrapItems($table, $row['uid'], $recTitle, $row);
1298  }
1299  // Render thumbnails, if:
1300  // - a thumbnail column exists
1301  // - there is content in it
1302  // - the thumbnail column is visible for the current type
1303  $type = 0;
1304  if (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['type'])) {
1305  $typeColumn = ‪$GLOBALS['TCA'][‪$table]['ctrl']['type'];
1306  $type = $row[$typeColumn];
1307  }
1308  // If current type doesn't exist, set it to 0 (or to 1 for historical reasons,
1309  // if 0 doesn't exist)
1310  if (!isset(‪$GLOBALS['TCA'][‪$table]['types'][$type])) {
1311  $type = isset(‪$GLOBALS['TCA'][‪$table]['types'][0]) ? 0 : 1;
1312  }
1313 
1314  $visibleColumns = $this->‪getVisibleColumns($GLOBALS['TCA'][‪$table], $type);
1315 
1316  if ($this->thumbs &&
1317  trim($row[$thumbsCol]) &&
1318  preg_match('/(^|(.*(;|,)?))' . $thumbsCol . '(((;|,).*)|$)/', $visibleColumns) === 1
1319  ) {
1320  $thumbCode = '<br />' . ‪BackendUtility::thumbCode($row, ‪$table, $thumbsCol);
1321  $theData[$fCol] .= $thumbCode;
1322  $theData['__label'] .= $thumbCode;
1323  }
1324  if (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'])
1325  && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']] != 0
1326  && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] != 0
1327  ) {
1328  // It's a translated record with a language parent
1329  $localizationMarkerClass = ' localization';
1330  }
1331  } elseif ($fCol === 'pid') {
1332  $theData[$fCol] = $row[$fCol];
1333  } elseif ($fCol === '_PATH_') {
1334  $theData[$fCol] = $this->‪recPath($row['pid']);
1335  } elseif ($fCol === '_REF_') {
1336  $theData[$fCol] = $this->‪generateReferenceToolTip($table, $row['uid']);
1337  } elseif ($fCol === '_CONTROL_') {
1338  $theData[$fCol] = $this->‪makeControl($table, $row);
1339  } elseif ($fCol === '_CLIPBOARD_') {
1340  $theData[$fCol] = $this->‪makeClip($table, $row);
1341  } elseif ($fCol === '_LOCALIZATION_') {
1342  [$lC1, $lC2] = $this->‪makeLocalizationPanel($table, $row);
1343  $theData[$fCol] = $lC1;
1344  $theData[$fCol . 'b'] = '<div class="btn-group">' . $lC2 . '</div>';
1345  } elseif ($fCol === '_LOCALIZATION_b') {
1346  // deliberately empty
1347  } else {
1348  $pageId = ‪$table === 'pages' ? $row['uid'] : $row['pid'];
1349  $tmpProc = ‪BackendUtility::getProcessedValueExtra(‪$table, $fCol, $row[$fCol], 100, $row['uid'], true, $pageId);
1350  $theData[$fCol] = $this->‪linkUrlMail(htmlspecialchars($tmpProc), $row[$fCol]);
1351  if ($this->csvOutput) {
1352  $row[$fCol] = ‪BackendUtility::getProcessedValueExtra(‪$table, $fCol, $row[$fCol], 0, $row['uid']);
1353  }
1354  }
1355  }
1356  // Reset the ID if it was overwritten
1357  if ((string)$this->searchString !== '') {
1358  $this->id = $id_orig;
1359  }
1360  // Add row to CSV list:
1361  if ($this->csvOutput) {
1362  $hooks = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][__CLASS__]['customizeCsvRow'] ?? [];
1363  if (!empty($hooks)) {
1364  $hookParameters = [
1365  'databaseRow' => &$row,
1366  'tableName' => ‪$table,
1367  'pageId' => ‪$this->id
1368  ];
1369  foreach ($hooks as $hookFunction) {
1370  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
1371  }
1372  }
1373  $this->‪addToCSV($row);
1374  }
1375  // Add classes to table cells
1376  $this->addElement_tdCssClass[$titleCol] = 'col-title col-responsive' . $localizationMarkerClass . $deletePlaceholderClass;
1377  $this->addElement_tdCssClass['__label'] = $this->addElement_tdCssClass[$titleCol];
1378  $this->addElement_tdCssClass['_CONTROL_'] = 'col-control';
1379  if ($this->moduleData['clipBoard']) {
1380  $this->addElement_tdCssClass['_CLIPBOARD_'] = 'col-clipboard';
1381  }
1382  $this->addElement_tdCssClass['_PATH_'] = 'col-path';
1383  $this->addElement_tdCssClass['_LOCALIZATION_'] = 'col-localizationa';
1384  $this->addElement_tdCssClass['_LOCALIZATION_b'] = 'col-localizationb';
1385  // Create element in table cells:
1386  $theData['uid'] = $row['uid'];
1387  if (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField'])
1388  && isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'])
1389  ) {
1390  $theData['_l10nparent_'] = $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']];
1391  }
1392 
1393  $tagAttributes = array_map(
1394  function ($attributeValue) {
1395  if (is_array($attributeValue)) {
1396  return implode(' ', $attributeValue);
1397  }
1398  return $attributeValue;
1399  },
1400  $tagAttributes
1401  );
1402 
1403  $rowOutput .= $this->‪addElement(1, $theIcon, $theData, GeneralUtility::implodeAttributes($tagAttributes, true));
1404  // Finally, return table row element:
1405  return $rowOutput;
1406  }
1407 
1416  protected function ‪getReferenceCount($tableName, $uid)
1417  {
1418  if (!isset($this->referenceCount[$tableName][$uid])) {
1419  $referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
1420  $numberOfReferences = $referenceIndex->getNumberOfReferencedRecords($tableName, $uid);
1421  $this->referenceCount[$tableName][$uid] = $numberOfReferences;
1422  }
1423  return $this->referenceCount[$tableName][$uid];
1424  }
1425 
1436  public function ‪renderListHeader(‪$table, $currentIdList)
1437  {
1438  $tsConfig = ‪BackendUtility::getPagesTSconfig($this->id);
1439  $tsConfigOfTable = is_array($tsConfig['TCEFORM.'][‪$table . '.']) ? $tsConfig['TCEFORM.'][‪$table . '.'] : null;
1440 
1441  $lang = $this->‪getLanguageService();
1442  // Init:
1443  $theData = [];
1444  $icon = '';
1445  // Traverse the fields:
1446  foreach ($this->fieldArray as $fCol) {
1447  // Calculate users permissions to edit records in the table:
1448  $permsEdit = $this->calcPerms & (‪$table === 'pages' ? 2 : 16) && $this->‪overlayEditLockPermissions($table);
1449  switch ((string)$fCol) {
1450  case '_PATH_':
1451  // Path
1452  $theData[$fCol] = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels._PATH_')) . ']</i>';
1453  break;
1454  case '_REF_':
1455  // References
1456  $theData[$fCol] = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels._REF_')) . ']</i>';
1457  break;
1458  case '_LOCALIZATION_':
1459  // Path
1460  $theData[$fCol] = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels._LOCALIZATION_')) . ']</i>';
1461  break;
1462  case '_LOCALIZATION_b':
1463  // Path
1464  $theData[$fCol] = htmlspecialchars($lang->getLL('Localize'));
1465  break;
1466  case '_CLIPBOARD_':
1467  if (!$this->moduleData['clipBoard'] || (‪$table === 'pages' && $this->‪showOnlyTranslatedRecords)) {
1468  break;
1469  }
1470  // Clipboard:
1471  $cells = [];
1472  // If there are elements on the clipboard for this table, and the parent page is not locked by editlock
1473  // then display the "paste into" icon:
1474  $elFromTable = $this->clipObj->elFromTable(‪$table);
1475  if (!empty($elFromTable) && $this->‪overlayEditLockPermissions($table)) {
1476  $href = htmlspecialchars($this->clipObj->pasteUrl(‪$table, $this->id));
1477  $confirmMessage = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable);
1478  $cells['pasteAfter'] = '<a class="btn btn-default t3js-modal-trigger"'
1479  . ' href="' . $href . '"'
1480  . ' title="' . htmlspecialchars($lang->getLL('clip_paste')) . '"'
1481  . ' data-title="' . htmlspecialchars($lang->getLL('clip_paste')) . '"'
1482  . ' data-content="' . htmlspecialchars($confirmMessage) . '"'
1483  . ' data-severity="warning">'
1484  . $this->iconFactory->getIcon('actions-document-paste-into', ‪Icon::SIZE_SMALL)->render()
1485  . '</a>';
1486  }
1487  // If the numeric clipboard pads are enabled, display the control icons for that:
1488  if ($this->clipObj->current !== 'normal') {
1489  // The "select" link:
1490  $spriteIcon = $this->iconFactory->getIcon('actions-edit-copy', ‪Icon::SIZE_SMALL)->render();
1491  $cells['copyMarked'] = $this->‪linkClipboardHeaderIcon($spriteIcon, ‪$table, 'setCB', '', $lang->getLL('clip_selectMarked'));
1492  // The "edit marked" link:
1493  $editUri = (string)$this->uriBuilder->buildUriFromRoute('record_edit')
1494  . '&edit[' . ‪$table . '][{entityIdentifiers:editList}]=edit'
1495  . '&returnUrl=' . rawurlencode($this->‪listURL());
1496  $cells['edit'] = '<a class="btn btn-default t3js-record-edit-multiple" href="#"'
1497  . ' data-uri="' . htmlspecialchars($editUri) . '"'
1498  . ' title="' . htmlspecialchars($lang->getLL('clip_editMarked')) . '">'
1499  . $this->iconFactory->getIcon('actions-document-open', ‪Icon::SIZE_SMALL)->render() . '</a>';
1500  // The "Delete marked" link:
1501  $cells['delete'] = $this->‪linkClipboardHeaderIcon(
1502  $this->iconFactory->getIcon('actions-edit-delete', ‪Icon::SIZE_SMALL)->render(),
1503  ‪$table,
1504  'delete',
1505  sprintf($lang->getLL('clip_deleteMarkedWarning'), $lang->sL(‪$GLOBALS['TCA'][‪$table]['ctrl']['title'])),
1506  $lang->getLL('clip_deleteMarked')
1507  );
1508  // The "Select all" link:
1509  $cells['markAll'] = '<a class="btn btn-default t3js-toggle-all-checkboxes" data-checkboxes-names="' . htmlspecialchars(implode(',', $this->CBnames)) . '" rel="" href="#" title="'
1510  . htmlspecialchars($lang->getLL('clip_markRecords')) . '">'
1511  . $this->iconFactory->getIcon('actions-document-select', ‪Icon::SIZE_SMALL)->render() . '</a>';
1512  } else {
1513  $cells['empty'] = '';
1514  }
1515  /*
1516  * hook: renderListHeaderActions: Allows to change the clipboard icons of the Web>List table headers
1517  * usage: Above each listed table in Web>List a header row is shown.
1518  * This hook allows to modify the icons responsible for the clipboard functions
1519  * (shown above the clipboard checkboxes when a clipboard other than "Normal" is selected),
1520  * or other "Action" functions which perform operations on the listed records.
1521  */
1522  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? [] as $className) {
1523  $hookObject = GeneralUtility::makeInstance($className);
1524  if (!$hookObject instanceof RecordListHookInterface) {
1525  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567850);
1526  }
1527  $cells = $hookObject->renderListHeaderActions(‪$table, $currentIdList, $cells, $this);
1528  }
1529  $theData[$fCol] = '';
1530  if (isset($cells['edit']) && isset($cells['delete'])) {
1531  $theData[$fCol] .= '<div class="btn-group" role="group">' . $cells['edit'] . $cells['delete'] . '</div>';
1532  unset($cells['edit'], $cells['delete']);
1533  }
1534  $theData[$fCol] .= '<div class="btn-group" role="group">' . implode('', $cells) . '</div>';
1535  break;
1536  case '_CONTROL_':
1537  // Control panel:
1538  if ($this->‪isEditable($table)) {
1539  // If new records can be created on this page, add links:
1540  $permsAdditional = (‪$table === 'pages' ? 8 : 16);
1541  if ($this->calcPerms & $permsAdditional && $this->‪showNewRecLink($table)) {
1542  $spriteIcon = ‪$table === 'pages'
1543  ? $this->iconFactory->getIcon('actions-page-new', ‪Icon::SIZE_SMALL)
1544  : $this->iconFactory->getIcon('actions-add', ‪Icon::SIZE_SMALL);
1545  if (‪$table === 'tt_content') {
1546  // If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
1547  $newContentElementWizard = $tsConfig['mod.']['newContentElementWizard.']['override']
1548  ?? 'new_content_element_wizard';
1549  $url = (string)$this->uriBuilder->buildUriFromRoute(
1550  $newContentElementWizard,
1551  [
1552  'id' => $this->id,
1553  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
1554  ]
1555  );
1556  $title = htmlspecialchars($lang->getLL('new'));
1557  $icon = '<a href="' . htmlspecialchars($url) . '" '
1558  . 'title="' . $title . '"'
1559  . 'data-title="' . $title . '"'
1560  . 'class="btn btn-default t3js-toggle-new-content-element-wizard disabled">'
1561  . $spriteIcon->render()
1562  . '</a>';
1563  } elseif (‪$table === 'pages') {
1564  $parameters = ['id' => ‪$this->id, 'pagesOnly' => 1, 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')];
1565  $href = (string)$this->uriBuilder->buildUriFromRoute('db_new', $parameters);
1566  $icon = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="' . htmlspecialchars($lang->getLL('new')) . '">'
1567  . $spriteIcon->render() . '</a>';
1568  } else {
1569  $params = '&edit[' . ‪$table . '][' . $this->id . ']=new';
1570  if ($table === 'pages') {
1571  $params .= '&overrideVals[pages][doktype]=' . (int)$this->pageRow['doktype'];
1572  }
1573  $newLink = $this->uriBuilder->buildUriFromRoute('record_edit') . $params . $this->‪makeReturnUrl();
1574  $icon = '<a class="btn btn-default" href="' . htmlspecialchars($newLink) . '" title="' . htmlspecialchars($lang->getLL('new')) . '">' . $spriteIcon->render() . '</a>';
1575  }
1576  }
1577  // If the table can be edited, add link for editing ALL SHOWN fields for all listed records:
1578  if ($permsEdit && $this->table && is_array($currentIdList)) {
1579  $entityIdentifiers = 'entityIdentifiers';
1580  if ($this->‪clipNumPane()) {
1581  $entityIdentifiers .= ':editList';
1582  }
1583  $editUri = (string)$this->uriBuilder->buildUriFromRoute('record_edit')
1584  . '&edit[' . ‪$table . '][{' . $entityIdentifiers . '}]=edit'
1585  . '&columnsOnly=' . implode(',', $this->fieldArray)
1586  . '&returnUrl=' . rawurlencode($this->‪listURL());
1587  $icon .= '<a class="btn btn-default t3js-record-edit-multiple" href="#"'
1588  . ' data-uri="' . htmlspecialchars($editUri) . '"'
1589  . ' title="' . htmlspecialchars($lang->getLL('editShownColumns')) . '">'
1590  . $this->iconFactory->getIcon('actions-document-open', ‪Icon::SIZE_SMALL)->render() . '</a>';
1591  $icon = '<div class="btn-group" role="group">' . $icon . '</div>';
1592  }
1593  // Add an empty entry, so column count fits again after moving this into $icon
1594  $theData[$fCol] = '&nbsp;';
1595  } else {
1596  $icon = ‪$this->spaceIcon;
1597  }
1598  break;
1599  default:
1600  // Regular fields header:
1601  $theData[$fCol] = '';
1602 
1603  // Check if $fCol is really a field and get the label and remove the colons
1604  // at the end
1605  $sortLabel = ‪BackendUtility::getItemLabel(‪$table, $fCol);
1606  if ($sortLabel !== null) {
1607  $sortLabel = rtrim(trim($lang->sL($sortLabel)), ':');
1609  // Field label
1610  $fieldTSConfig = [];
1611  if (isset($tsConfigOfTable[$fCol . '.'])
1612  && is_array($tsConfigOfTable[$fCol . '.'])
1613  ) {
1614  $fieldTSConfig = $tsConfigOfTable[$fCol . '.'];
1615  }
1616  if (!empty($fieldTSConfig['label'])) {
1617  $sortLabel = $lang->sL($fieldTSConfig['label']);
1618  }
1619  if (!empty($fieldTSConfig['label.'][$lang->lang])) {
1620  $sortLabel = $lang->sL($fieldTSConfig['label.'][$lang->lang]);
1621  }
1622  $sortLabel = htmlspecialchars($sortLabel);
1623  } else {
1624  // No TCA field, only output the $fCol variable with square brackets []
1625  $sortLabel = htmlspecialchars($fCol);
1626  $sortLabel = '<i>[' . rtrim(trim($sortLabel), ':') . ']</i>';
1627  }
1628 
1629  if ($this->table && is_array($currentIdList)) {
1630  // If the numeric clipboard pads are selected, show duplicate sorting link:
1631  if ($this->‪clipNumPane()) {
1632  $theData[$fCol] .= '<a class="btn btn-default" href="' . htmlspecialchars($this->‪listURL('', '-1') . '&duplicateField=' . $fCol)
1633  . '" title="' . htmlspecialchars($lang->getLL('clip_duplicates')) . '">'
1634  . $this->iconFactory->getIcon('actions-document-duplicates-select', ‪Icon::SIZE_SMALL)->render() . '</a>';
1635  }
1636  // If the table can be edited, add link for editing THIS field for all
1637  // listed records:
1638  if ($this->‪isEditable($table) && $permsEdit && ‪$GLOBALS['TCA'][‪$table]['columns'][$fCol]) {
1639  $entityIdentifiers = 'entityIdentifiers';
1640  if ($this->‪clipNumPane()) {
1641  $entityIdentifiers .= ':editList';
1642  }
1643  $editUri = (string)$this->uriBuilder->buildUriFromRoute('record_edit')
1644  . '&edit[' . ‪$table . '][{' . $entityIdentifiers . '}]=edit'
1645  . '&columnsOnly=' . $fCol
1646  . '&returnUrl=' . rawurlencode($this->‪listURL());
1647  $iTitle = sprintf($lang->getLL('editThisColumn'), $sortLabel);
1648  $theData[$fCol] .= '<a class="btn btn-default t3js-record-edit-multiple" href="#"'
1649  . ' data-uri="' . htmlspecialchars($editUri) . '"'
1650  . ' title="' . htmlspecialchars($iTitle) . '">'
1651  . $this->iconFactory->getIcon('actions-document-open', ‪Icon::SIZE_SMALL)->render() . '</a>';
1652  }
1653  if (strlen($theData[$fCol]) > 0) {
1654  $theData[$fCol] = '<div class="btn-group" role="group">' . $theData[$fCol] . '</div> ';
1655  }
1656  }
1657  $theData[$fCol] .= $this->‪addSortLink($sortLabel, $fCol, ‪$table);
1658  }
1659  }
1660  /*
1661  * hook: renderListHeader: Allows to change the contents of columns/cells of the Web>List table headers
1662  * usage: Above each listed table in Web>List a header row is shown.
1663  * Containing the labels of all shown fields and additional icons to create new records for this
1664  * table or perform special clipboard tasks like mark and copy all listed records to clipboard, etc.
1665  */
1666  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? [] as $className) {
1667  $hookObject = GeneralUtility::makeInstance($className);
1668  if (!$hookObject instanceof RecordListHookInterface) {
1669  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567855);
1670  }
1671  $theData = $hookObject->renderListHeader(‪$table, $currentIdList, $theData, $this);
1672  }
1673 
1674  // Create and return header table row:
1675  return '<thead>' . $this->‪addElement(1, $icon, $theData, '', '', '', 'th') . '</thead>';
1676  }
1677 
1684  protected function ‪getPointerForPage($page)
1685  {
1686  return ($page - 1) * ‪$this->iLimit;
1687  }
1688 
1695  protected function ‪renderListNavigation($renderPart = 'top')
1696  {
1697  $totalPages = (int)ceil($this->totalItems / $this->iLimit);
1698  // Show page selector if not all records fit into one page
1699  if ($totalPages <= 1) {
1700  return '';
1701  }
1702  $content = '';
1703  $listURL = $this->‪listURL('', $this->table, 'firstElementNumber');
1704  // 1 = first page
1705  // 0 = first element
1706  $currentPage = (int)floor($this->firstElementNumber / $this->iLimit) + 1;
1707  // Compile first, previous, next, last and refresh buttons
1708  if ($currentPage > 1) {
1709  $labelFirst = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:first'));
1710  $labelPrevious = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:previous'));
1711  $first = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage(1) . '" title="' . $labelFirst . '">'
1712  . $this->iconFactory->getIcon('actions-view-paging-first', ‪Icon::SIZE_SMALL)->render() . '</a></li>';
1713  $previous = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage($currentPage - 1) . '" title="' . $labelPrevious . '">'
1714  . $this->iconFactory->getIcon('actions-view-paging-previous', ‪Icon::SIZE_SMALL)->render() . '</a></li>';
1715  } else {
1716  $first = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-first', ‪Icon::SIZE_SMALL)->render() . '</span></li>';
1717  $previous = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-previous', ‪Icon::SIZE_SMALL)->render() . '</span></li>';
1718  }
1719  if ($currentPage < $totalPages) {
1720  $labelNext = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:next'));
1721  $labelLast = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:last'));
1722  $next = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage($currentPage + 1) . '" title="' . $labelNext . '">'
1723  . $this->iconFactory->getIcon('actions-view-paging-next', ‪Icon::SIZE_SMALL)->render() . '</a></li>';
1724  $last = '<li><a href="' . $listURL . '&pointer=' . $this->‪getPointerForPage($totalPages) . '" title="' . $labelLast . '">'
1725  . $this->iconFactory->getIcon('actions-view-paging-last', ‪Icon::SIZE_SMALL)->render() . '</a></li>';
1726  } else {
1727  $next = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-next', ‪Icon::SIZE_SMALL)->render() . '</span></li>';
1728  $last = '<li class="disabled"><span>' . $this->iconFactory->getIcon('actions-view-paging-last', ‪Icon::SIZE_SMALL)->render() . '</span></li>';
1729  }
1730  $reload = '<li><a href="#" onclick="document.dblistForm.action=' . GeneralUtility::quoteJSvalue($listURL
1731  . '&pointer=') . '+calculatePointer(document.getElementById(' . GeneralUtility::quoteJSvalue('jumpPage-' . $renderPart)
1732  . ').value); document.dblistForm.submit(); return true;" title="'
1733  . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:reload')) . '">'
1734  . $this->iconFactory->getIcon('actions-refresh', ‪Icon::SIZE_SMALL)->render() . '</a></li>';
1735  if ($renderPart === 'top') {
1736  // Add js to traverse a page select input to a pointer value
1737  $content = '
1738 <script>
1739 /*<![CDATA[*/
1740  function calculatePointer(page) {
1741  if (page > ' . $totalPages . ') {
1742  page = ' . $totalPages . ';
1743  }
1744  if (page < 1) {
1745  page = 1;
1746  }
1747  return (page - 1) * ' . $this->iLimit . ';
1748  }
1749 /*]]>*/
1750 </script>
1751 ';
1752  }
1753  $pageNumberInput = '
1754  <input type="number" min="1" max="' . $totalPages . '" value="' . $currentPage . '" size="3" class="form-control input-sm paginator-input" id="jumpPage-' . $renderPart . '" name="jumpPage-'
1755  . $renderPart . '" onkeyup="if (event.keyCode == 13) { document.dblistForm.action=' . htmlspecialchars(GeneralUtility::quoteJSvalue($listURL . '&pointer='))
1756  . '+calculatePointer(this.value); document.dblistForm.submit(); } return true;" />
1757  ';
1758  $pageIndicatorText = sprintf(
1759  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:pageIndicator'),
1760  $pageNumberInput,
1761  $totalPages
1762  );
1763  $pageIndicator = '<li><span>' . $pageIndicatorText . '</span></li>';
1764  if ($this->totalItems > $this->firstElementNumber + $this->iLimit) {
1765  $lastElementNumber = $this->firstElementNumber + ‪$this->iLimit;
1766  } else {
1767  $lastElementNumber = ‪$this->totalItems;
1768  }
1769  $rangeIndicator = '<li><span>' . sprintf(
1770  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:rangeIndicator'),
1771  $this->firstElementNumber + 1,
1772  $lastElementNumber
1773  ) . '</span></li>';
1774 
1775  $titleColumn = $this->fieldArray[0];
1776  $data = [
1777  $titleColumn => $content . '
1778  <nav class="pagination-wrap">
1779  <ul class="pagination pagination-block">
1780  ' . $first . '
1781  ' . $previous . '
1782  ' . $rangeIndicator . '
1783  ' . $pageIndicator . '
1784  ' . $next . '
1785  ' . $last . '
1786  ' . $reload . '
1787  </ul>
1788  </nav>
1789  '
1790  ];
1791  return $this->‪addElement(1, '', $data);
1792  }
1793 
1794  /*********************************
1795  *
1796  * Rendering of various elements
1797  *
1798  *********************************/
1799 
1808  public function ‪makeControl(‪$table, $row)
1809  {
1810  $backendUser = $this->‪getBackendUserAuthentication();
1811  $userTsConfig = $backendUser->getTSConfig();
1812  $rowUid = $row['uid'];
1813  if (‪ExtensionManagementUtility::isLoaded('workspaces') && isset($row['_ORIG_uid'])) {
1814  $rowUid = $row['_ORIG_uid'];
1815  }
1816  $isDeletePlaceHolder = $this->‪isRecordDeletePlaceholder($row);
1817  $cells = [
1818  'primary' => [],
1819  'secondary' => []
1820  ];
1821 
1822  // Enables to hide the move elements for localized records - doesn't make much sense to perform these options for them
1823  $isL10nOverlay = $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] != 0;
1824  if (‪$table === 'pages') {
1825  // If the listed table is 'pages' we have to request the permission settings for each page.
1826  $localCalcPerms = $backendUser->calcPerms(‪BackendUtility::getRecord('pages', $row['uid']));
1827  } else {
1828  // If the listed table is not 'pages' we have to request the permission settings from the parent page
1829  $localCalcPerms = $backendUser->calcPerms(‪BackendUtility::getRecord('pages', $row['pid']));
1830  }
1831  $permsEdit = ‪$table === 'pages'
1832  && $backendUser->checkLanguageAccess((int)$row[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']])
1833  && $localCalcPerms & ‪Permission::PAGE_EDIT
1834  || ‪$table !== 'pages'
1835  && $localCalcPerms & ‪Permission::CONTENT_EDIT
1836  && $backendUser->recordEditAccessInternals(‪$table, $row);
1837  $permsEdit = $this->‪overlayEditLockPermissions($table, $row, $permsEdit);
1838 
1839  // "Show" link (only pages and tt_content elements)
1840  $tsConfig = ‪BackendUtility::getPagesTSconfig($this->id)['mod.']['web_list.'] ?? [];
1841  if ((
1842  $table === 'pages'
1843  && isset($row['doktype'])
1844  && !in_array((int)$row['doktype'], $this->‪getNoViewWithDokTypes($tsConfig), true)
1845  )
1846  || (
1847  ‪$table === 'tt_content'
1848  && isset($this->pageRow['doktype'])
1849  && !in_array((int)$this->pageRow['doktype'], $this->‪getNoViewWithDokTypes($tsConfig), true)
1850  )
1851  ) {
1852  if (!$isDeletePlaceHolder) {
1853  $onClick = $this->‪getOnClickForRow($table, $row);
1854  $viewAction = '<a class="btn btn-default" href="#" onclick="'
1855  . htmlspecialchars(
1856  $onClick
1857  ) . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage')) . '">';
1858  if (‪$table === 'pages') {
1859  $viewAction .= $this->iconFactory->getIcon('actions-view-page', ‪Icon::SIZE_SMALL)->render();
1860  } else {
1861  $viewAction .= $this->iconFactory->getIcon('actions-view', ‪Icon::SIZE_SMALL)->render();
1862  }
1863  $viewAction .= '</a>';
1864  $this->‪addActionToCellGroup($cells, $viewAction, 'view');
1865  } else {
1866  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'view');
1867  }
1868  } else {
1869  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'view');
1870  }
1871 
1872  // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
1873  if ($permsEdit && !$isDeletePlaceHolder && $this->‪isEditable($table)) {
1874  $params = '&edit[' . ‪$table . '][' . $row['uid'] . ']=edit';
1875  $iconIdentifier = 'actions-open';
1876  if (‪$table === 'pages') {
1877  // Disallow manual adjustment of the language field for pages
1878  $params .= '&overrideVals[pages][sys_language_uid]=' . (int)$row[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']];
1879  $iconIdentifier = 'actions-page-open';
1880  }
1881  $editLink = $this->uriBuilder->buildUriFromRoute('record_edit') . $params . $this->‪makeReturnUrl();
1882  $editAction = '<a class="btn btn-default" href="' . htmlspecialchars($editLink) . '"'
1883  . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('edit')) . '">' . $this->iconFactory->getIcon($iconIdentifier, ‪Icon::SIZE_SMALL)->render() . '</a>';
1884  } else {
1885  $editAction = ‪$this->spaceIcon;
1886  }
1887  $this->‪addActionToCellGroup($cells, $editAction, 'edit');
1888 
1889  // "Info"
1890  if (!$isDeletePlaceHolder) {
1891  $viewBigAction = '<a class="btn btn-default" href="#" ' . $this->‪createShowItemTagAttributes($table . ',' . (int)$row['uid']) . ' title="' . htmlspecialchars($this->‪getLanguageService()->getLL('showInfo')) . '">'
1892  . $this->iconFactory->getIcon('actions-document-info', ‪Icon::SIZE_SMALL)->render() . '</a>';
1893  $this->‪addActionToCellGroup($cells, $viewBigAction, 'viewBig');
1894  } else {
1895  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'viewBig');
1896  }
1897 
1898  // "Move" wizard link for pages/tt_content elements:
1899  if ($permsEdit && (‪$table === 'tt_content' || ‪$table === 'pages') && $this->‪isEditable($table)) {
1900  if ($isL10nOverlay || $isDeletePlaceHolder) {
1901  $moveAction = ‪$this->spaceIcon;
1902  } else {
1903  $linkTitleLL = htmlspecialchars($this->‪getLanguageService()->getLL('move_' . (‪$table === 'tt_content' ? 'record' : 'page')));
1904  $icon = (‪$table === 'pages' ? $this->iconFactory->getIcon('actions-page-move', ‪Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-document-move', ‪Icon::SIZE_SMALL));
1905  $url = (string)$this->uriBuilder->buildUriFromRoute('move_element', [
1906  'table' => ‪$table,
1907  'uid' => $row['uid'],
1908  'returnUrl' => $this->listURL(),
1909  ]);
1910  $moveAction = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . $linkTitleLL . '">' . $icon->render() . '</a>';
1911  }
1912  $this->‪addActionToCellGroup($cells, $moveAction, 'move');
1913  }
1914 
1915  // If the table is NOT a read-only table, then show these links:
1916  if ($this->‪isEditable($table)) {
1917  // "Revert" link (history/undo)
1918  if ((bool)\trim($userTsConfig['options.']['showHistory.'][‪$table] ?? $userTsConfig['options.']['showHistory'] ?? '1')) {
1919  if (!$isDeletePlaceHolder) {
1920  $moduleUrl = $this->uriBuilder->buildUriFromRoute('record_history', [
1921  'element' => ‪$table . ':' . $row['uid'],
1922  'returnUrl' => $this->‪listURL(),
1923  ]) . '#latest';
1924  $historyAction = '<a class="btn btn-default" href="' . htmlspecialchars($moduleUrl) . '" title="'
1925  . htmlspecialchars($this->‪getLanguageService()->getLL('history')) . '">'
1926  . $this->iconFactory->getIcon('actions-document-history-open', ‪Icon::SIZE_SMALL)->render() . '</a>';
1927  $this->‪addActionToCellGroup($cells, $historyAction, 'history');
1928  } else {
1929  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'history');
1930  }
1931  }
1932 
1933  // "Edit Perms" link:
1934  if (‪$table === 'pages' && $backendUser->check('modules', 'system_BeuserTxPermission') && ‪ExtensionManagementUtility::isLoaded('beuser')) {
1935  if ($isL10nOverlay || $isDeletePlaceHolder) {
1936  $permsAction = ‪$this->spaceIcon;
1937  } else {
1938  $href = (string)$this->uriBuilder->buildUriFromRoute('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&tx_beuser_system_beusertxpermission[action]=edit' . $this->‪makeReturnUrl();
1939  $permsAction = '<a class="btn btn-default" href="' . htmlspecialchars($href) . '" title="'
1940  . htmlspecialchars($this->‪getLanguageService()->getLL('permissions')) . '">'
1941  . $this->iconFactory->getIcon('actions-lock', ‪Icon::SIZE_SMALL)->render() . '</a>';
1942  }
1943  $this->‪addActionToCellGroup($cells, $permsAction, 'perms');
1944  }
1945 
1946  // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row
1947  // or if default values can depend on previous record):
1948  if ((‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] || ‪$GLOBALS['TCA'][‪$table]['ctrl']['useColumnsForDefaultValues']) && $permsEdit) {
1949  if (‪$table !== 'pages' && $this->calcPerms & ‪Permission::CONTENT_EDIT || ‪$table === 'pages' && $this->calcPerms & ‪Permission::PAGE_NEW) {
1950  if ($isL10nOverlay || $isDeletePlaceHolder) {
1951  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'new');
1952  } elseif ($this->‪showNewRecLink($table)) {
1953  $params = '&edit[' . ‪$table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
1954  $icon = (‪$table === 'pages' ? $this->iconFactory->getIcon('actions-page-new', ‪Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-add', ‪Icon::SIZE_SMALL));
1955  $titleLabel = 'new';
1956  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby']) {
1957  $titleLabel .= (‪$table === 'pages' ? 'Page' : 'Record');
1958  }
1959  $newLink = $this->uriBuilder->buildUriFromRoute('record_edit') . $params . $this->‪makeReturnUrl();
1960  $newAction = '<a class="btn btn-default" href="' . htmlspecialchars($newLink) . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL($titleLabel)) . '">'
1961  . $icon->render() . '</a>';
1962  $this->‪addActionToCellGroup($cells, $newAction, 'new');
1963  }
1964  }
1965  }
1966 
1967  // "Up/Down" links
1968  if ($permsEdit && ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) {
1969  if (!$isL10nOverlay && !$isDeletePlaceHolder && isset($this->currentTable['prev'][$row['uid']])) {
1970  // Up
1971  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']];
1973  $moveUpAction = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('moveUp')) . '">'
1974  . $this->iconFactory->getIcon('actions-move-up', ‪Icon::SIZE_SMALL)->render() . '</a>';
1975  } else {
1976  $moveUpAction = ‪$this->spaceIcon;
1977  }
1978  $this->‪addActionToCellGroup($cells, $moveUpAction, 'moveUp');
1979 
1980  if (!$isL10nOverlay && !$isDeletePlaceHolder && $this->currentTable['next'][$row['uid']]) {
1981  // Down
1982  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']];
1984  $moveDownAction = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('moveDown')) . '">'
1985  . $this->iconFactory->getIcon('actions-move-down', ‪Icon::SIZE_SMALL)->render() . '</a>';
1986  } else {
1987  $moveDownAction = ‪$this->spaceIcon;
1988  }
1989  $this->‪addActionToCellGroup($cells, $moveDownAction, 'moveDown');
1990  }
1991 
1992  // "Hide/Unhide" links:
1993  $hiddenField = ‪$GLOBALS['TCA'][‪$table]['ctrl']['enablecolumns']['disabled'];
1994  if (!empty(‪$GLOBALS['TCA'][‪$table]['columns'][$hiddenField])
1995  && (empty(‪$GLOBALS['TCA'][‪$table]['columns'][$hiddenField]['exclude']) || $backendUser->check('non_exclude_fields', ‪$table . ':' . $hiddenField))
1996  ) {
1997  if (!$permsEdit || $isDeletePlaceHolder || $this->‪isRecordCurrentBackendUser($table, $row)) {
1998  $hideAction = ‪$this->spaceIcon;
1999  } else {
2000  $hideTitle = htmlspecialchars($this->‪getLanguageService()->getLL('hide' . (‪$table === 'pages' ? 'Page' : '')));
2001  $unhideTitle = htmlspecialchars($this->‪getLanguageService()->getLL('unHide' . (‪$table === 'pages' ? 'Page' : '')));
2002  if ($row[$hiddenField]) {
2003  $params = 'data[' . ‪$table . '][' . $rowUid . '][' . $hiddenField . ']=0';
2004  $hideAction = '<a class="btn btn-default t3js-record-hide" data-state="hidden" href="#"'
2005  . ' data-params="' . htmlspecialchars($params) . '"'
2006  . ' title="' . $unhideTitle . '"'
2007  . ' data-toggle-title="' . $hideTitle . '">'
2008  . $this->iconFactory->getIcon('actions-edit-unhide', ‪Icon::SIZE_SMALL)->render() . '</a>';
2009  } else {
2010  $params = 'data[' . ‪$table . '][' . $rowUid . '][' . $hiddenField . ']=1';
2011  $hideAction = '<a class="btn btn-default t3js-record-hide" data-state="visible" href="#"'
2012  . ' data-params="' . htmlspecialchars($params) . '"'
2013  . ' title="' . $hideTitle . '"'
2014  . ' data-toggle-title="' . $unhideTitle . '">'
2015  . $this->iconFactory->getIcon('actions-edit-hide', ‪Icon::SIZE_SMALL)->render() . '</a>';
2016  }
2017  }
2018  $this->‪addActionToCellGroup($cells, $hideAction, 'hide');
2019  }
2020 
2021  // "Delete" link:
2022  $disableDelete = (bool)\trim($userTsConfig['options.']['disableDelete.'][‪$table] ?? $userTsConfig['options.']['disableDelete'] ?? '0');
2023  if ($permsEdit
2024  && !$disableDelete
2025  && (‪$table === 'pages' && $localCalcPerms & ‪Permission::PAGE_DELETE || ‪$table !== 'pages' && $this->calcPerms & ‪Permission::CONTENT_EDIT)
2026  && !$this->‪isRecordCurrentBackendUser($table, $row)
2027  && !$isDeletePlaceHolder
2028  ) {
2029  $actionName = 'delete';
2030  $refCountMsg = ‪BackendUtility::referenceCount(
2031  ‪$table,
2032  $row['uid'],
2033  ' ' . $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.referencesToRecord'),
2034  (string)$this->‪getReferenceCount($table, $row['uid'])
2036  ‪$table,
2037  $row['uid'],
2038  ' ' . $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.translationsOfRecord')
2039  );
2041  $warningText = $this->‪getLanguageService()->‪getLL($actionName . 'Warning') . ' "' . $title . '" [' . ‪$table . ':' . $row['uid'] . ']' . $refCountMsg;
2042  $params = 'cmd[' . ‪$table . '][' . $row['uid'] . '][delete]=1';
2043  $icon = $this->iconFactory->getIcon('actions-edit-' . $actionName, ‪Icon::SIZE_SMALL)->render();
2044  $linkTitle = htmlspecialchars($this->‪getLanguageService()->getLL($actionName));
2045  $l10nParentField = ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'] ?? '';
2046  $deleteAction = '<a class="btn btn-default t3js-record-delete" href="#" '
2047  . ' data-button-ok-text="' . htmlspecialchars($linkTitle) . '"'
2048  . ' data-l10parent="' . ($l10nParentField ? htmlspecialchars($row[$l10nParentField]) : '') . '"'
2049  . ' data-params="' . htmlspecialchars($params) . '" data-title="' . htmlspecialchars($title) . '"'
2050  . ' data-message="' . htmlspecialchars($warningText) . '" title="' . $linkTitle . '"'
2051  . '>' . $icon . '</a>';
2052  } else {
2053  $deleteAction = ‪$this->spaceIcon;
2054  }
2055  $this->‪addActionToCellGroup($cells, $deleteAction, 'delete');
2056 
2057  // "Levels" links: Moving pages into new levels...
2058  if ($permsEdit && ‪$table === 'pages' && !$this->searchLevels) {
2059  // Up (Paste as the page right after the current parent page)
2060  if ($this->calcPerms & ‪Permission::PAGE_NEW) {
2061  if (!$isDeletePlaceHolder && !$isL10nOverlay) {
2062  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . -‪$this->id;
2064  $moveLeftAction = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('prevLevel')) . '">'
2065  . $this->iconFactory->getIcon('actions-move-left', ‪Icon::SIZE_SMALL)->render() . '</a>';
2066  $this->‪addActionToCellGroup($cells, $moveLeftAction, 'moveLeft');
2067  } else {
2068  $this->‪addActionToCellGroup($cells, $this->spaceIcon, 'moveLeft');
2069  }
2070  }
2071  // Down (Paste as subpage to the page right above)
2072  if (!$isL10nOverlay && !$isDeletePlaceHolder && $this->currentTable['prevUid'][$row['uid']]) {
2073  $localCalcPerms = $backendUser->calcPerms(‪BackendUtility::getRecord('pages', $this->currentTable['prevUid'][$row['uid']]));
2074  if ($localCalcPerms & ‪Permission::PAGE_NEW) {
2075  $params = '&cmd[' . ‪$table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']];
2077  $moveRightAction = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('nextLevel')) . '">'
2078  . $this->iconFactory->getIcon('actions-move-right', ‪Icon::SIZE_SMALL)->render() . '</a>';
2079  } else {
2080  $moveRightAction = ‪$this->spaceIcon;
2081  }
2082  } else {
2083  $moveRightAction = ‪$this->spaceIcon;
2084  }
2085  $this->‪addActionToCellGroup($cells, $moveRightAction, 'moveRight');
2086  }
2087  }
2088 
2089  /*
2090  * hook: recStatInfoHooks: Allows to insert HTML before record icons on various places
2091  */
2092  $hooks = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] ?? [];
2093  if (!empty($hooks)) {
2094  $stat = '';
2095  $_params = [‪$table, $row['uid']];
2096  foreach ($hooks as $_funcRef) {
2097  $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2098  }
2099  $this->‪addActionToCellGroup($cells, $stat, 'stat');
2100  }
2101 
2102  /*
2103  * hook: makeControl: Allows to change control icons of records in list-module
2104  * usage: This hook method gets passed the current $cells array as third parameter.
2105  * This array contains values for the icons/actions generated for each record in Web>List.
2106  * Each array entry is accessible by an index-key.
2107  * The order of the icons is depending on the order of those array entries.
2108  */
2109  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? false)) {
2110  // for compatibility reason, we move all icons to the rootlevel
2111  // before calling the hooks
2112  foreach ($cells as $section => $actions) {
2113  foreach ($actions as $actionKey => $action) {
2114  $cells[$actionKey] = $action;
2115  }
2116  }
2117  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $className) {
2118  $hookObject = GeneralUtility::makeInstance($className);
2119  if (!$hookObject instanceof RecordListHookInterface) {
2120  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567840);
2121  }
2122  $cells = $hookObject->makeControl(‪$table, $row, $cells, $this);
2123  }
2124  // now sort icons again into primary and secondary sections
2125  // after all hooks are processed
2126  $hookCells = $cells;
2127  foreach ($hookCells as $key => $value) {
2128  if ($key === 'primary' || $key === 'secondary') {
2129  continue;
2130  }
2131  $this->‪addActionToCellGroup($cells, $value, $key);
2132  }
2133  }
2134 
2135  ‪$output = '<!-- CONTROL PANEL: ' . ‪$table . ':' . $row['uid'] . ' -->';
2136  foreach ($cells as $classification => $actions) {
2137  $visibilityClass = ($classification !== 'primary' && !$this->moduleData['bigControlPanel'] ? 'collapsed' : 'expanded');
2138  if ($visibilityClass === 'collapsed') {
2139  $cellOutput = '';
2140  foreach ($actions as $action) {
2141  $cellOutput .= $action;
2142  }
2143  ‪$output .= ' <div class="btn-group">' .
2144  '<span id="actions_' . ‪$table . '_' . $row['uid'] . '" class="btn-group collapse collapse-horizontal width">' . $cellOutput . '</span>' .
2145  '<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>' .
2146  '</div>';
2147  } else {
2148  ‪$output .= ' <div class="btn-group" role="group">' . implode('', $actions) . '</div>';
2149  }
2150  }
2151 
2152  return ‪$output;
2153  }
2154 
2163  public function ‪makeClip(‪$table, $row)
2164  {
2165  // Return blank, if disabled:
2166  if (!$this->moduleData['clipBoard']
2167  || (‪$table === 'pages' && $this->‪showOnlyTranslatedRecords)
2168  || !$this->‪isEditable($table)
2169  || $this->‪isRecordDeletePlaceholder($row)
2170  ) {
2171  return '';
2172  }
2173  $cells = [];
2174  $cells['pasteAfter'] = ($cells['pasteInto'] = ‪$this->spaceIcon);
2175  // Enables to hide the copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them
2176  $isL10nOverlay = $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] != 0;
2177  $isRecordDeletePlaceholder = $this->‪isRecordDeletePlaceholder($row);
2178  // Return blank, if disabled:
2179  // Whether a numeric clipboard pad is active or the normal pad we will see different content of the panel:
2180  // For the "Normal" pad:
2181  if ($this->clipObj->current === 'normal') {
2182  // Show copy/cut icons:
2183  $isSel = (string)$this->clipObj->isSelected(‪$table, $row['uid']);
2184  if ($isL10nOverlay || !$this->‪overlayEditLockPermissions($table, $row) || $isRecordDeletePlaceholder) {
2185  $cells['copy'] = ‪$this->spaceIcon;
2186  $cells['cut'] = ‪$this->spaceIcon;
2187  } else {
2188  $copyIcon = $this->iconFactory->getIcon('actions-edit-copy', ‪Icon::SIZE_SMALL);
2189  $cutIcon = $this->iconFactory->getIcon('actions-edit-cut', ‪Icon::SIZE_SMALL);
2190 
2191  if ($isSel === 'copy') {
2192  $copyIcon = $this->iconFactory->getIcon('actions-edit-copy-release', ‪Icon::SIZE_SMALL);
2193  } elseif ($isSel === 'cut') {
2194  $cutIcon = $this->iconFactory->getIcon('actions-edit-cut-release', ‪Icon::SIZE_SMALL);
2195  }
2196 
2197  $cells['copy'] = '<a class="btn btn-default" href="'
2198  . htmlspecialchars($this->clipObj->selUrlDB(
2199  ‪$table,
2200  $row['uid'],
2201  1,
2202  $isSel === 'copy',
2203  ['returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]
2204  ))
2205  . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.copy')) . '">'
2206  . $copyIcon->render() . '</a>';
2207 
2208  // Check permission to cut page or content
2209  if (‪$table === 'pages') {
2210  $localCalcPerms = $this->‪getBackendUserAuthentication()->‪calcPerms(‪BackendUtility::getRecord('pages', $row['uid']));
2211  $permsEdit = ($localCalcPerms & ‪Permission::PAGE_EDIT) !== 0;
2212  } else {
2213  $permsEdit = ($this->calcPerms & ‪Permission::CONTENT_EDIT) !== 0;
2214  }
2215  $permsEdit = $this->‪overlayEditLockPermissions($table, $row, $permsEdit);
2216 
2217  // If the listed table is 'pages' we have to request the permission settings for each page:
2218  if (‪$table === 'pages') {
2219  if ($permsEdit) {
2220  $cells['cut'] = '<a class="btn btn-default" href="'
2221  . htmlspecialchars($this->clipObj->selUrlDB(
2222  ‪$table,
2223  $row['uid'],
2224  0,
2225  $isSel === 'cut',
2226  ['returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]
2227  ))
2228  . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.cut')) . '">'
2229  . $cutIcon->render() . '</a>';
2230  } else {
2231  $cells['cut'] = ‪$this->spaceIcon;
2232  }
2233  } elseif ($this->calcPerms & ‪Permission::CONTENT_EDIT) {
2234  $cells['cut'] = '<a class="btn btn-default" href="'
2235  . htmlspecialchars($this->clipObj->selUrlDB(
2236  ‪$table,
2237  $row['uid'],
2238  0,
2239  $isSel === 'cut',
2240  ['returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]
2241  ))
2242  . '" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.cut')) . '">'
2243  . $cutIcon->render() . '</a>';
2244  } else {
2245  $cells['cut'] = ‪$this->spaceIcon;
2246  }
2247  }
2248  } else {
2249  // For the numeric clipboard pads (showing checkboxes where one can select elements on/off)
2250  // Setting name of the element in ->CBnames array:
2251  $n = ‪$table . '|' . $row['uid'];
2252  $this->CBnames[] = $n;
2253  // Check if the current element is selected and if so, prepare to set the checkbox as selected:
2254  $checked = $this->clipObj->isSelected(‪$table, $row['uid']) ? 'checked="checked" ' : '';
2255  // If the "duplicateField" value is set then select all elements which are duplicates...
2256  if ($this->duplicateField && isset($row[$this->duplicateField])) {
2257  $checked = '';
2258  if (in_array($row[$this->duplicateField], $this->duplicateStack)) {
2259  $checked = 'checked="checked" ';
2260  }
2261  $this->duplicateStack[] = $row[‪$this->duplicateField];
2262  }
2263  // Adding the checkbox to the panel:
2264  $cells['select'] = $isL10nOverlay
2265  ? $this->spaceIcon
2266  : '<input type="hidden" name="CBH[' . $n . ']" value="0" /><label class="btn btn-default btn-checkbox"><input type="checkbox"'
2267  . ' name="CBC[' . $n . ']" value="1" ' . $checked . '/><span class="t3-icon fa"></span></label>';
2268  }
2269  // Now, looking for selected elements from the current table:
2270  $elFromTable = $this->clipObj->elFromTable(‪$table);
2271  if (!empty($elFromTable) && ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] && !$isRecordDeletePlaceholder) {
2272  // IF elements are found, they can be individually ordered and are not locked by editlock, then add a "paste after" icon:
2273  $cells['pasteAfter'] = $isL10nOverlay || !$this->‪overlayEditLockPermissions($table, $row)
2274  ? $this->spaceIcon
2275  : '<a class="btn btn-default t3js-modal-trigger"'
2276  . ' href="' . htmlspecialchars($this->clipObj->pasteUrl(‪$table, -$row['uid'])) . '"'
2277  . ' title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteAfter')) . '"'
2278  . ' data-title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteAfter')) . '"'
2279  . ' data-content="' . htmlspecialchars($this->clipObj->confirmMsgText(‪$table, $row, 'after', $elFromTable)) . '"'
2280  . ' data-severity="warning">'
2281  . $this->iconFactory->getIcon('actions-document-paste-after', ‪Icon::SIZE_SMALL)->render() . '</a>';
2282  }
2283  // Now, looking for elements in general:
2284  $elFromTable = $this->clipObj->elFromTable('');
2285  if (‪$table === 'pages' && !$isL10nOverlay && !empty($elFromTable) && !$isRecordDeletePlaceholder) {
2286  $cells['pasteInto'] = '<a class="btn btn-default t3js-modal-trigger"'
2287  . ' href="' . htmlspecialchars($this->clipObj->pasteUrl('', $row['uid'])) . '"'
2288  . ' title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteInto')) . '"'
2289  . ' data-title="' . htmlspecialchars($this->‪getLanguageService()->getLL('clip_pasteInto')) . '"'
2290  . ' data-content="' . htmlspecialchars($this->clipObj->confirmMsgText(‪$table, $row, 'into', $elFromTable)) . '"'
2291  . ' data-severity="warning">'
2292  . $this->iconFactory->getIcon('actions-document-paste-into', ‪Icon::SIZE_SMALL)->render() . '</a>';
2293  }
2294  /*
2295  * hook: makeClip: Allows to change clip-icons of records in list-module
2296  * usage: This hook method gets passed the current $cells array as third parameter.
2297  * This array contains values for the clipboard icons generated for each record in Web>List.
2298  * Each array entry is accessible by an index-key.
2299  * The order of the icons is depending on the order of those array entries.
2300  */
2301  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] ?? [] as $className) {
2302  $hookObject = GeneralUtility::makeInstance($className);
2303  if (!$hookObject instanceof RecordListHookInterface) {
2304  throw new \UnexpectedValueException($className . ' must implement interface ' . RecordListHookInterface::class, 1195567845);
2305  }
2306  $cells = $hookObject->makeClip(‪$table, $row, $cells, $this);
2307  }
2308  return '<div class="btn-group" role="group">' . implode('', $cells) . '</div>';
2309  }
2310 
2318  public function ‪makeLocalizationPanel(‪$table, $row)
2319  {
2320  $out = [
2321  0 => '',
2322  1 => ''
2323  ];
2324  // Reset translations
2325  $this->translations = [];
2326 
2327  // Language title and icon:
2328  $out[0] = $this->‪languageFlag($row[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']]);
2329  // Guard clause so we can quickly return if a record is localized to "all languages"
2330  // It should only be possible to localize a record off default (uid 0)
2331  // Reasoning: The Parent is for ALL languages... why overlay with a localization?
2332  if ((int)$row[‪$GLOBALS['TCA'][‪$table]['ctrl']['languageField']] === -1) {
2333  return $out;
2334  }
2335  ‪$translations = $this->translateTools->translationInfo(‪$table, $row['uid'], 0, $row, $this->selFieldList);
2336  $pageId = (int)(‪$table === 'pages' ? $row['uid'] : $row['pid']);
2337  $languageInformation = $this->translateTools->getSystemLanguages($pageId);
2338  if (is_array(‪$translations)) {
2339  $this->translations = ‪$translations['translations'];
2340  // Traverse page translations and add icon for each language that does NOT yet exist and is included in site configuration:
2341  $lNew = '';
2342  foreach ($this->pageOverlays as $lUid_OnPage => $lsysRec) {
2343  if (isset($this->systemLanguagesOnPage[$lUid_OnPage])
2344  && $this->‪isEditable($table)
2345  && !$this->‪isRecordDeletePlaceholder($row)
2346  && !isset(‪$translations['translations'][$lUid_OnPage])
2347  && $this->‪getBackendUserAuthentication()->‪checkLanguageAccess($lUid_OnPage)
2348  ) {
2349  $redirectUrl = (string)$this->uriBuilder->buildUriFromRoute(
2350  'record_edit',
2351  [
2352  'justLocalized' => ‪$table . ':' . $row['uid'] . ':' . $lUid_OnPage,
2353  'returnUrl' => $this->listURL()
2354  ]
2355  );
2357  '&cmd[' . ‪$table . '][' . $row['uid'] . '][localize]=' . $lUid_OnPage,
2358  $redirectUrl
2359  );
2360  if ($languageInformation[$lUid_OnPage]['flagIcon']) {
2361  $lC = $this->iconFactory->getIcon($languageInformation[$lUid_OnPage]['flagIcon'], ‪Icon::SIZE_SMALL)->render();
2362  } else {
2363  $lC = htmlspecialchars($languageInformation[$lUid_OnPage]['title'] ?? '');
2364  }
2365  $lC = '<a href="' . htmlspecialchars($href) . '" title="'
2366  . htmlspecialchars($languageInformation[$lUid_OnPage]['title'] ?? '') . '" class="btn btn-default t3js-action-localize">'
2367  . $lC . '</a> ';
2368  $lNew .= $lC;
2369  }
2370  }
2371  if ($lNew) {
2372  $out[1] .= $lNew;
2373  }
2374  } elseif (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'])
2375  && (bool)($row[‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']] ?? false)
2376  ) {
2377  $out[0] = '&nbsp;&nbsp;&nbsp;&nbsp;' . $out[0];
2378  }
2379  return $out;
2380  }
2381 
2389  public function ‪fieldSelectBox(‪$table, $formFields = true)
2390  {
2391  $lang = $this->‪getLanguageService();
2392  // Init:
2393  $formElements = ['', ''];
2394  if ($formFields) {
2395  $formElements = ['<form action="' . htmlspecialchars($this->‪listURL()) . '" method="post" name="fieldSelectBox">', '</form>'];
2396  }
2397  // Load already selected fields, if any:
2398  ‪$setFields = is_array($this->setFields[‪$table]) ? $this->setFields[‪$table] : [];
2399  // Request fields from table:
2400  ‪$fields = $this->‪makeFieldList($table, false, true);
2401  // Add pseudo "control" fields
2402  ‪$fields[] = '_PATH_';
2403  ‪$fields[] = '_REF_';
2404  // Create a checkbox for each field:
2405  $checkboxes = [];
2406  $checkAllChecked = true;
2407  $tsConfig = ‪BackendUtility::getPagesTSconfig($this->id);
2408  $tsConfigOfTable = is_array($tsConfig['TCEFORM.'][‪$table . '.']) ? $tsConfig['TCEFORM.'][‪$table . '.'] : null;
2409  foreach (‪$fields as $fieldName) {
2410  // Hide field if hidden
2411  if ($tsConfigOfTable && is_array($tsConfigOfTable[$fieldName . '.']) && isset($tsConfigOfTable[$fieldName . '.']['disabled']) && (int)$tsConfigOfTable[$fieldName . '.']['disabled'] === 1) {
2412  continue;
2413  }
2414  // Determine, if checkbox should be checked
2415  if (in_array($fieldName, ‪$setFields, true) || $fieldName === $this->fieldArray[0]) {
2416  $checked = ' checked="checked"';
2417  } else {
2418  $checkAllChecked = false;
2419  $checked = '';
2420  }
2421 
2422  // Field label
2423  $fieldTSConfig = [];
2424  $fieldLabel = '';
2425  if (isset($tsConfigOfTable[$fieldName . '.'])
2426  && is_array($tsConfigOfTable[$fieldName . '.'])
2427  ) {
2428  $fieldTSConfig = $tsConfigOfTable[$fieldName . '.'];
2429  }
2430  if (!empty($fieldTSConfig['label'])) {
2431  $fieldLabel = $fieldTSConfig['label'];
2432  }
2433  if (!empty($fieldTSConfig['label.'][$lang->lang])) {
2434  $fieldLabel = $fieldTSConfig['label.'][$lang->lang];
2435  }
2436 
2437  $fieldLabel = $fieldLabel ?: ‪BackendUtility::getItemLabel(‪$table, $fieldName);
2438 
2439  $checkboxes[] = '<tr><td class="col-checkbox"><input type="checkbox" id="check-' . $fieldName . '" name="displayFields['
2440  . ‪$table . '][]" value="' . $fieldName . '" ' . $checked
2441  . ($fieldName === $this->fieldArray[0] ? ' disabled="disabled"' : '') . '></td><td class="col-title">'
2442  . '<label class="label-block" for="check-' . $fieldName . '">' . htmlspecialchars($lang->sL($fieldLabel)) . ' <span class="text-muted text-monospace">[' . htmlspecialchars($fieldName) . ']</span></label></td></tr>';
2443  }
2444  // Table with the field selector::
2445  $content = $formElements[0] . '
2446  <input type="hidden" name="displayFields[' . ‪$table . '][]" value="">
2447  <div class="table-fit table-scrollable">
2448  <table border="0" cellpadding="0" cellspacing="0" class="table table-transparent table-hover">
2449  <thead>
2450  <tr>
2451  <th class="col-checkbox checkbox" colspan="2">
2452  <label><input type="checkbox" class="checkbox checkAll" ' . ($checkAllChecked ? ' checked="checked"' : '') . '>
2453  ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleall')) . '</label>
2454  </th>
2455  </tr>
2456  </thead>
2457  <tbody>
2458  ' . implode('', $checkboxes) . '
2459  </tbody>
2460  </table>
2461  </div>
2462  <input type="submit" name="search" class="btn btn-default" value="'
2463  . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.setFields')) . '"/>
2464  ' . $formElements[1];
2465  return '<div class="fieldSelectBox">' . $content . '</div>';
2466  }
2467 
2468  /*********************************
2469  *
2470  * Helper functions
2471  *
2472  *********************************/
2485  public function ‪linkClipboardHeaderIcon($string, ‪$table, $cmd, $warning = '', $title = '')
2486  {
2487  $jsCode = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue($cmd)
2488  . ';document.dblistForm.cmd_table.value='
2489  . GeneralUtility::quoteJSvalue(‪$table)
2490  . ';document.dblistForm.submit();';
2491 
2492  $attributes = [];
2493  if ($title !== '') {
2494  $attributes['title'] = $title;
2495  }
2496  if ($warning) {
2497  $attributes['class'] = 'btn btn-default t3js-modal-trigger';
2498  $attributes['data-href'] = 'javascript:' . $jsCode;
2499  $attributes['data-severity'] = 'warning';
2500  $attributes['data-title'] = $title;
2501  $attributes['data-content'] = $warning;
2502  } else {
2503  $attributes['class'] = 'btn btn-default';
2504  $attributes['onclick'] = $jsCode . 'return false;';
2505  }
2506 
2507  $attributesString = '';
2508  foreach ($attributes as $key => $value) {
2509  $attributesString .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
2510  }
2511  return '<a href="#" ' . $attributesString . '>' . $string . '</a>';
2512  }
2513 
2519  public function ‪clipNumPane()
2520  {
2521  return in_array('_CLIPBOARD_', $this->fieldArray) && $this->clipObj->current !== 'normal';
2522  }
2523 
2534  public function ‪addSortLink($code, $field, ‪$table)
2535  {
2536  // Certain circumstances just return string right away (no links):
2537  if ($field === '_CONTROL_' || $field === '_LOCALIZATION_' || $field === '_CLIPBOARD_' || $field === '_REF_' || $this->disableSingleTableView) {
2538  return $code;
2539  }
2540  // If "_PATH_" (showing record path) is selected, force sorting by pid field (will at least group the records!)
2541  if ($field === '_PATH_') {
2542  $field = 'pid';
2543  }
2544  // Create the sort link:
2545  $sortUrl = $this->‪listURL('', '-1', 'sortField,sortRev,table,firstElementNumber') . '&table=' . $table
2546  . '&sortField=' . $field . '&sortRev=' . ($this->sortRev || $this->sortField != $field ? 0 : 1);
2547  $sortArrow = $this->sortField === $field
2548  ? $this->iconFactory->getIcon('status-status-sorting-' . ($this->sortRev ? 'desc' : 'asc'), ‪Icon::SIZE_SMALL)->render()
2549  : '';
2550  // Return linked field:
2551  return '<a href="' . htmlspecialchars($sortUrl) . '">' . $code . $sortArrow . '</a>';
2552  }
2553 
2562  public function ‪recPath($pid)
2563  {
2564  if (!isset($this->recPath_cache[$pid])) {
2565  $this->recPath_cache[$pid] = ‪BackendUtility::getRecordPath($pid, $this->perms_clause, 20);
2566  }
2567  return $this->recPath_cache[$pid];
2568  }
2569 
2576  public function ‪showNewRecLink(‪$table)
2577  {
2578  // No deny/allow tables are set:
2579  if (empty($this->allowedNewTables) && empty($this->deniedNewTables)) {
2580  return true;
2581  }
2582  return !in_array(‪$table, $this->deniedNewTables)
2583  && (empty($this->allowedNewTables) || in_array(‪$table, $this->allowedNewTables));
2584  }
2585 
2593  public function ‪makeReturnUrl()
2594  {
2595  return '&returnUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'));
2596  }
2597 
2598  /************************************
2599  *
2600  * CSV related functions
2601  *
2602  ************************************/
2606  protected function ‪initCSV()
2607  {
2608  $this->‪addHeaderRowToCSV();
2609  }
2610 
2614  protected function ‪addHeaderRowToCSV()
2615  {
2616  ‪$fieldArray = array_combine($this->fieldArray, $this->fieldArray);
2617  ‪$fieldArray = is_array(‪$fieldArray) ? ‪$fieldArray : [];
2618  $hooks = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][__CLASS__]['customizeCsvHeader'] ?? [];
2619  if (!empty($hooks)) {
2620  $hookParameters = [
2621  'fields' => &‪$fieldArray
2622  ];
2623  foreach ($hooks as $hookFunction) {
2624  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
2625  }
2626  }
2627  // Add header row, control fields will be reduced inside addToCSV()
2628  $this->‪addToCSV(‪$fieldArray);
2629  }
2630 
2636  protected function ‪addToCSV(array $row = [])
2637  {
2638  $rowReducedByControlFields = ‪self::removeControlFieldsFromFieldRow($row);
2639  // Get a field array without control fields but in the expected order
2640  ‪$fieldArray = array_intersect_key(array_flip($this->fieldArray), $rowReducedByControlFields);
2641  // Overwrite fieldArray to keep the order with an array of needed fields
2642  $rowReducedToSelectedColumns = array_replace(‪$fieldArray, array_intersect_key($rowReducedByControlFields, ‪$fieldArray));
2643  $this->‪setCsvRow($rowReducedToSelectedColumns);
2644  }
2645 
2652  protected static function ‪removeControlFieldsFromFieldRow(array $row = [])
2653  {
2654  // Possible control fields in a list row
2655  $controlFields = [
2656  '_PATH_',
2657  '_REF_',
2658  '_CONTROL_',
2659  '_CLIPBOARD_',
2660  '_LOCALIZATION_',
2661  '_LOCALIZATION_b'
2662  ];
2663  return array_diff_key($row, array_flip($controlFields));
2664  }
2665 
2671  public function ‪setCsvRow($csvRow)
2672  {
2673  $csvDelimiter = $this->modTSconfig['properties']['csvDelimiter'] ?? ',';
2674  $csvQuote = $this->modTSconfig['properties']['csvQuote'] ?? '"';
2675 
2676  $this->csvLines[] = ‪CsvUtility::csvValues($csvRow, $csvDelimiter, $csvQuote);
2677  }
2678 
2685  public function ‪outputCSV($prefix)
2686  {
2687  // Setting filename:
2688  $filename = $prefix . '_' . date('dmy-Hi') . '.csv';
2689  // Creating output header:
2690  header('Content-Type: application/octet-stream');
2691  header('Content-Disposition: attachment; filename=' . $filename);
2692  // Cache-Control header is needed here to solve an issue with browser IE and
2693  // versions lower than 9. See for more information: http://support.microsoft.com/kb/323308
2694  header("Cache-Control: ''");
2695  // Printing the content of the CSV lines:
2696  echo implode(CRLF, $this->csvLines);
2697  // Exits:
2698  die;
2699  }
2708  public function ‪addActionToCellGroup(&$cells, $action, $actionKey)
2709  {
2710  $cellsMap = [
2711  'primary' => [
2712  'view', 'edit', 'hide', 'delete', 'stat'
2713  ],
2714  'secondary' => [
2715  'viewBig', 'history', 'perms', 'new', 'move', 'moveUp', 'moveDown', 'moveLeft', 'moveRight', 'version'
2716  ]
2717  ];
2718  $classification = in_array($actionKey, $cellsMap['primary']) ? 'primary' : 'secondary';
2719  $cells[$classification][$actionKey] = $action;
2720  unset($cells[$actionKey]);
2721  }
2730  protected function ‪isRecordCurrentBackendUser(‪$table, $row)
2731  {
2732  return ‪$table === 'be_users' && (int)$row['uid'] === $this->‪getBackendUserAuthentication()->user['uid'];
2733  }
2738  protected function ‪isRecordDeletePlaceholder(array $row): bool
2739  {
2740  return $this->‪getBackendUserAuthentication()->workspace > 0
2741  && isset($row['t3ver_state'])
2742  && ‪VersionState::cast($row['t3ver_state'])->equals(‪VersionState::DELETE_PLACEHOLDER);
2743  }
2744 
2748  public function ‪setIsEditable(bool $isEditable): void
2749  {
2750  $this->editable = $isEditable;
2751  }
2752 
2758  public function ‪isEditable(string ‪$table): bool
2759  {
2760  $backendUser = $this->‪getBackendUserAuthentication();
2761  return !$GLOBALS['TCA'][‪$table]['ctrl']['readOnly']
2762  && $this->editable
2763  && ($backendUser->isAdmin() || $backendUser->check('tables_modify', ‪$table));
2764  }
2765 
2776  protected function ‪overlayEditLockPermissions(‪$table, $row = [], $editPermission = true)
2777  {
2778  if ($editPermission && !$this->‪getBackendUserAuthentication()->isAdmin()) {
2779  // If no $row is submitted we only check for general edit lock of current page (except for table "pages")
2780  if (empty($row)) {
2781  return ‪$table === 'pages' ? true : !$this->pageRow['editlock'];
2782  }
2783  if ((‪$table === 'pages' && $row['editlock']) || (‪$table !== 'pages' && $this->pageRow['editlock'])) {
2784  $editPermission = false;
2785  } elseif (isset(‪$GLOBALS['TCA'][‪$table]['ctrl']['editlock']) && $row[‪$GLOBALS['TCA'][‪$table]['ctrl']['editlock']]) {
2786  $editPermission = false;
2787  }
2788  }
2789  return $editPermission;
2790  }
2791 
2798  protected function ‪editLockPermissions()
2799  {
2800  return $this->‪getBackendUserAuthentication()->‪isAdmin() || !$this->pageRow['editlock'];
2801  }
2802 
2810  public function ‪setModuleData(array ‪$moduleData = []): void
2811  {
2812  $this->moduleData = ‪$moduleData;
2813  }
2814 
2825  public function ‪start(‪$id, ‪$table, $pointer, $search = '', $levels = 0, ‪$showLimit = 0)
2826  {
2827  $backendUser = $this->‪getBackendUserAuthentication();
2828  // Setting internal variables:
2829  // sets the parent id
2830  $this->id = (int)‪$id;
2831  // Store languages that are included in the site configuration for the current page.
2832  $this->systemLanguagesOnPage = $this->translateTools->getSystemLanguages($this->id);
2833  if ($GLOBALS['TCA'][‪$table]) {
2834  // Setting single table mode, if table exists:
2835  $this->table = ‪$table;
2836  }
2837  $this->firstElementNumber = $pointer;
2838  $this->searchString = trim($search);
2839  $this->searchLevels = (int)$levels;
2840  $this->showLimit = ‪MathUtility::forceIntegerInRange(‪$showLimit, 0, 10000);
2841  // Setting GPvars:
2842  $this->csvOutput = (bool)GeneralUtility::_GP('csv');
2843  $this->sortField = GeneralUtility::_GP('sortField');
2844  $this->sortRev = GeneralUtility::_GP('sortRev');
2845  $this->displayFields = GeneralUtility::_GP('displayFields');
2846  $this->duplicateField = GeneralUtility::_GP('duplicateField');
2847  // Init dynamic vars:
2848  $this->counter = 0;
2849  $this->HTMLcode = '';
2850  // Limits
2851  if (isset($this->modTSconfig['properties']['itemsLimitPerTable'])) {
2852  $this->itemsLimitPerTable = ‪MathUtility::forceIntegerInRange(
2853  (int)$this->modTSconfig['properties']['itemsLimitPerTable'],
2854  1,
2855  10000
2856  );
2857  }
2858  if (isset($this->modTSconfig['properties']['itemsLimitSingleTable'])) {
2859  $this->itemsLimitSingleTable = ‪MathUtility::forceIntegerInRange(
2860  (int)$this->modTSconfig['properties']['itemsLimitSingleTable'],
2861  1,
2862  10000
2863  );
2864  }
2865 
2866  // If there is a current link to a record, set the current link uid and get the table name from the link handler configuration
2867  $currentLinkValue = isset($this->overrideUrlParameters['P']['currentValue']) ? trim($this->overrideUrlParameters['P']['currentValue']) : '';
2868  if ($currentLinkValue) {
2869  $linkService = GeneralUtility::makeInstance(LinkService::class);
2870  try {
2871  $currentLinkParts = $linkService->resolve($currentLinkValue);
2872  if ($currentLinkParts['type'] === 'record' && isset($currentLinkParts['identifier'])) {
2873  $this->currentLink['tableNames'] = ‪$this->tableList;
2874  $this->currentLink['uid'] = (int)$currentLinkParts['uid'];
2875  }
2876  } catch (UnknownLinkHandlerException $e) {
2877  }
2878  }
2879 
2880  // $table might be NULL at this point in the code. As the expressionBuilder
2881  // is used to limit returned records based on the page permissions and the
2882  // uid field of the pages it can hardcoded to work on the pages table.
2883  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
2884  ->getQueryBuilderForTable('pages')
2885  ->expr();
2886  $permsClause = $expressionBuilder->andX($backendUser->getPagePermsClause(‪Permission::PAGE_SHOW));
2887  // This will hide records from display - it has nothing to do with user rights!!
2888  $pidList = ‪GeneralUtility::intExplode(',', $backendUser->getTSConfig()['options.']['hideRecords.']['pages'] ?? '', true);
2889  if (!empty($pidList)) {
2890  $permsClause->add($expressionBuilder->notIn('pages.uid', $pidList));
2891  }
2892  $this->perms_clause = (string)$permsClause;
2893 
2894  // Get configuration of collapsed tables from user uc and merge with sanitized GP vars
2895  $this->tablesCollapsed = is_array($backendUser->uc['moduleData']['list'])
2896  ? $backendUser->uc['moduleData']['list']
2897  : [];
2898  $this->‪initializeLanguages();
2899  }
2900 
2906  public function ‪generateList()
2907  {
2908  // Set page record in header
2909  $this->pageRecord = ‪BackendUtility::getRecordWSOL('pages', $this->id);
2910  $hideTablesArray = ‪GeneralUtility::trimExplode(',', $this->hideTables);
2911 
2912  $backendUser = $this->‪getBackendUserAuthentication();
2913 
2914  // pre-process tables and add sorting instructions
2915  $tableNames = array_flip(array_keys(‪$GLOBALS['TCA']));
2916  foreach ($tableNames as $tableName => &$config) {
2917  $hideTable = false;
2918 
2919  // Checking if the table should be rendered:
2920  // Checks that we see only permitted/requested tables:
2921  if ($this->table && $tableName !== $this->table
2922  || $this->tableList && !GeneralUtility::inList($this->tableList, $tableName)
2923  || !$backendUser->check('tables_select', $tableName)
2924  ) {
2925  $hideTable = true;
2926  }
2927 
2928  if (!$hideTable) {
2929  // Don't show table if hidden by TCA ctrl section
2930  // Don't show table if hidden by pageTSconfig mod.web_list.hideTables
2931  $hideTable = $hideTable
2932  || !empty(‪$GLOBALS['TCA'][$tableName]['ctrl']['hideTable'])
2933  || in_array($tableName, $hideTablesArray, true)
2934  || in_array('*', $hideTablesArray, true);
2935  // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table
2936  if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) {
2937  $hideTable = (bool)$this->tableTSconfigOverTCA[$tableName . '.']['hideTable'];
2938  }
2939  }
2940  if ($hideTable) {
2941  unset($tableNames[$tableName]);
2942  } else {
2943  if (isset($this->tableDisplayOrder[$tableName])) {
2944  // Copy display order information
2945  $tableNames[$tableName] = $this->tableDisplayOrder[$tableName];
2946  } else {
2947  $tableNames[$tableName] = [];
2948  }
2949  }
2950  }
2951  unset($config);
2952 
2953  $orderedTableNames = GeneralUtility::makeInstance(DependencyOrderingService::class)
2954  ->orderByDependencies($tableNames);
2955 
2956  foreach ($orderedTableNames as $tableName => $_) {
2957  // check if we are in single- or multi-table mode
2958  if ($this->table) {
2959  $this->iLimit = isset(‪$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems'])
2960  ? (int)‪$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']
2961  : $this->itemsLimitSingleTable;
2962  } else {
2963  // if there are no records in table continue current foreach
2964  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
2965  ->getQueryBuilderForTable($tableName);
2966  $queryBuilder->getRestrictions()
2967  ->removeAll()
2968  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
2969  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUserAuthentication()->workspace));
2970  $queryBuilder = $this->‪addPageIdConstraint($tableName, $queryBuilder);
2971  $firstRow = $queryBuilder->select('uid')
2972  ->from($tableName)
2973  ->setMaxResults(1)
2974  ->execute()
2975  ->fetch();
2976  if (!is_array($firstRow)) {
2977  continue;
2978  }
2979  $this->iLimit = isset(‪$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems'])
2980  ? (int)‪$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']
2981  : $this->itemsLimitPerTable;
2982  }
2983  if ($this->showLimit) {
2984  $this->iLimit = ‪$this->showLimit;
2985  }
2986  // Setting fields to select:
2987  if ($this->allFields) {
2988  ‪$fields = $this->‪makeFieldList($tableName, false, true);
2989  ‪$fields[] = '_PATH_';
2990  ‪$fields[] = '_REF_';
2991  if (is_array($this->setFields[$tableName])) {
2992  ‪$fields = array_intersect(‪$fields, $this->setFields[$tableName]);
2993  } else {
2994  ‪$fields = [];
2995  }
2996  } else {
2997  ‪$fields = [];
2998  }
2999  // Finally, render the list:
3000  $this->HTMLcode .= $this->‪getTable($tableName, $this->id, implode(',', ‪$fields));
3001  }
3002  }
3003 
3010  public function ‪getSearchBox($formFields = true)
3011  {
3013  ‪$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
3014  $lang = $this->‪getLanguageService();
3015  // Setting form-elements, if applicable:
3016  $formElements = ['', ''];
3017  if ($formFields) {
3018  $formElements = [
3019  '<form action="' . htmlspecialchars(
3020  $this->‪listURL('', '-1', 'firstElementNumber,search_field')
3021  ) . '" method="post">',
3022  '</form>'
3023  ];
3024  }
3025  // Make level selector:
3026  $opt = [];
3027 
3028  // "New" generation of search levels ... based on TS config
3029  $config = ‪BackendUtility::getPagesTSconfig($this->id);
3030  $searchLevelsFromTSconfig = $config['mod.']['web_list.']['searchLevel.']['items.'];
3031  $searchLevelItems = [];
3032 
3033  // get translated labels for search levels from pageTS
3034  foreach ($searchLevelsFromTSconfig as $keySearchLevel => $labelConfigured) {
3035  $label = $lang->sL('LLL:' . $labelConfigured);
3036  if ($label === '') {
3037  $label = $labelConfigured;
3038  }
3039  $searchLevelItems[$keySearchLevel] = $label;
3040  }
3041 
3042  foreach ($searchLevelItems as $kv => $label) {
3043  $opt[] = '<option value="' . $kv . '"' . ($kv === $this->searchLevels ? ' selected="selected"' : '') . '>' . htmlspecialchars(
3044  $label
3045  ) . '</option>';
3046  }
3047  $lMenu = '<select class="form-control" name="search_levels" title="' . htmlspecialchars(
3048  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search_levels')
3049  ) . '" id="search_levels">' . implode('', $opt) . '</select>';
3050  // Table with the search box:
3051  $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') . ';">
3052  ' . $formElements[0] . '
3053  <div id="typo3-dblist-search">
3054  <div class="panel panel-default">
3055  <div class="panel-body">
3056  <div class="row">
3057  <div class="col-sm-6 col-xs-12">
3058  <label for="search_field">' . htmlspecialchars(
3059  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.searchString')
3060  ) . '</label>
3061  <input class="form-control" type="search" placeholder="' . htmlspecialchars(
3062  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enterSearchString')
3063  ) . '" title="' . htmlspecialchars(
3064  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchString')
3065  ) . '" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '" />
3066  </div>
3067  <div class="col-xs-12 col-sm-3">
3068  <label for="search_levels">' . htmlspecialchars(
3069  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.search_levels')
3070  ) . '</label>
3071  ' . $lMenu . '
3072  </div>
3073  <div class="col-xs-12 col-sm-3">
3074  <label for="showLimit">' . htmlspecialchars(
3075  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.limit')
3076  ) . '</label>
3077  <input class="form-control" type="number" min="0" max="10000" placeholder="10" title="' . htmlspecialchars(
3078  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.limit')
3079  ) . '" name="showLimit" id="showLimit" value="' . htmlspecialchars(
3080  (string)($this->showLimit ?: '')
3081  ) . '" />
3082  </div>
3083  <div class="col-xs-12">
3084  <div class="form-control-wrap">
3085  <button type="submit" class="btn btn-default" name="search" title="' . htmlspecialchars(
3086  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search')
3087  ) . '">
3088  ' . ‪$iconFactory->‪getIcon('actions-search', ‪Icon::SIZE_SMALL)->‪render(
3089  ) . ' ' . htmlspecialchars(
3090  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.search')
3091  ) . '
3092  </button>
3093  </div>
3094  </div>
3095  </div>
3096  </div>
3097  </div>
3098  </div>
3099  ' . $formElements[1] . '</div>';
3100  return $content;
3101  }
3102 
3107  public function ‪setDispFields()
3108  {
3109  $backendUser = $this->‪getBackendUserAuthentication();
3110  // Getting from session:
3111  $dispFields = $backendUser->getModuleData('list/displayFields');
3112  // If fields has been inputted, then set those as the value and push it to session variable:
3113  if (is_array($this->displayFields)) {
3114  reset($this->displayFields);
3115  $tKey = key($this->displayFields);
3116  $dispFields[$tKey] = $this->displayFields[$tKey];
3117  $backendUser->pushModuleData('list/displayFields', $dispFields);
3118  }
3119  // Setting result:
3120  $this->setFields = $dispFields;
3121  }
3122 
3133  public function ‪getQueryBuilder(
3134  string ‪$table,
3135  int $pageId,
3136  array $additionalConstraints = [],
3137  array ‪$fields = ['*']
3138  ): QueryBuilder {
3139  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3140  ->getQueryBuilderForTable(‪$table);
3141  $queryBuilder->getRestrictions()
3142  ->removeAll()
3143  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3144  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUserAuthentication()->workspace));
3145  $queryBuilder
3146  ->select(...‪$fields)
3147  ->from(‪$table);
3148 
3149  if (!empty($additionalConstraints)) {
3150  $queryBuilder->andWhere(...$additionalConstraints);
3151  }
3152 
3153  $queryBuilder = $this->‪prepareQueryBuilder($table, $pageId, ‪$fields, $additionalConstraints, $queryBuilder);
3154 
3155  return $queryBuilder;
3156  }
3157 
3170  protected function ‪prepareQueryBuilder(
3171  string ‪$table,
3172  int $pageId,
3173  array $fieldList = ['*'],
3174  array $additionalConstraints = [],
3175  QueryBuilder $queryBuilder,
3176  bool $addSorting = true
3177  ): QueryBuilder {
3178  $parameters = [
3179  'table' => ‪$table,
3180  'fields' => $fieldList,
3181  'groupBy' => null,
3182  'orderBy' => null,
3183  'firstResult' => $this->firstElementNumber ?: null,
3184  'maxResults' => $this->iLimit ?: null
3185  ];
3186 
3187  if ($this->iLimit > 0) {
3188  $queryBuilder->setMaxResults($this->iLimit);
3189  }
3190 
3191  if ($this->firstElementNumber > 0) {
3192  $queryBuilder->setFirstResult($this->firstElementNumber);
3193  }
3194 
3195  if ($addSorting) {
3196  if ($this->sortField && in_array($this->sortField, $this->‪makeFieldList($table, true))) {
3197  $queryBuilder->orderBy($this->sortField, $this->sortRev ? 'DESC' : 'ASC');
3198  } else {
3199  $orderBy = ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'] ?: ‪$GLOBALS['TCA'][‪$table]['ctrl']['default_sortby'];
3200  $orderBys = ‪QueryHelper::parseOrderBy((string)$orderBy);
3201  foreach ($orderBys as $orderBy) {
3202  $queryBuilder->addOrderBy($orderBy[0], $orderBy[1]);
3203  }
3204  }
3205  }
3206 
3207  // Build the query constraints
3208  $queryBuilder = $this->‪addPageIdConstraint($table, $queryBuilder);
3209  $searchWhere = $this->‪makeSearchString($table, $pageId);
3210  if (!empty($searchWhere)) {
3211  $queryBuilder->andWhere($searchWhere);
3212  }
3213 
3214  // Filtering on displayable pages (permissions):
3215  if (‪$table === 'pages' && $this->perms_clause) {
3216  $queryBuilder->andWhere($this->perms_clause);
3217  }
3218 
3219  // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set
3220  if (!empty(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'])
3221  && (GeneralUtility::inList($this->hideTranslations, ‪$table) || $this->hideTranslations === '*')
3222  ) {
3223  $queryBuilder->andWhere(
3224  $queryBuilder->expr()->eq(
3225  ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'],
3226  0
3227  )
3228  );
3229  } elseif (!empty(‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField']) && $this->‪showOnlyTranslatedRecords) {
3230  // When only translated records should be shown, it is necessary to use l10n_parent=pageId, instead of
3231  // a check to the PID
3232  $queryBuilder->andWhere(
3233  $queryBuilder->expr()->eq(
3234  ‪$GLOBALS['TCA'][‪$table]['ctrl']['transOrigPointerField'],
3235  $queryBuilder->createNamedParameter(
3236  $this->id,
3237  \PDO::PARAM_INT
3238  )
3239  )
3240  );
3241  }
3242 
3243  $hookName = DatabaseRecordList::class;
3244  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['modifyQuery'] ?? [] as $className) {
3245  $hookObject = GeneralUtility::makeInstance($className);
3246  if (method_exists($hookObject, 'modifyQuery')) {
3247  $hookObject->modifyQuery(
3248  $parameters,
3249  ‪$table,
3250  $pageId,
3251  $additionalConstraints,
3252  $fieldList,
3253  $queryBuilder
3254  );
3255  }
3256  }
3257 
3258  return $queryBuilder;
3259  }
3260 
3269  public function ‪setTotalItems(string ‪$table, int $pageId, array $constraints)
3270  {
3271  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3272  ->getQueryBuilderForTable(‪$table);
3273 
3274  $queryBuilder->getRestrictions()
3275  ->removeAll()
3276  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3277  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUserAuthentication()->workspace));
3278  $queryBuilder
3279  ->from(‪$table);
3280 
3281  if (!empty($constraints)) {
3282  $queryBuilder->andWhere(...$constraints);
3283  }
3284 
3285  $queryBuilder = $this->‪prepareQueryBuilder($table, $pageId, ['*'], $constraints, $queryBuilder, false);
3286  // Reset limit and offset for full count query
3287  $queryBuilder->setFirstResult(0);
3288  $queryBuilder->setMaxResults(1);
3289 
3290  $this->totalItems = (int)$queryBuilder->count('*')
3291  ->execute()
3292  ->fetchColumn();
3293  }
3294 
3303  public function ‪makeSearchString(‪$table, $currentPid = -1)
3304  {
3305  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(‪$table);
3306  $expressionBuilder = $queryBuilder->expr();
3307  $constraints = [];
3308  $currentPid = (int)$currentPid;
3309  $tablePidField = ‪$table === 'pages' ? 'uid' : 'pid';
3310  // Make query only if table is valid and a search string is actually defined
3311  if (empty($this->searchString)) {
3312  return '';
3313  }
3314 
3315  $searchableFields = $this->‪getSearchFields($table);
3316  if (‪MathUtility::canBeInterpretedAsInteger($this->searchString)) {
3317  $constraints[] = $expressionBuilder->eq('uid', (int)$this->searchString);
3318  foreach ($searchableFields as $fieldName) {
3319  if (!isset(‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName])) {
3320  continue;
3321  }
3322  $fieldConfig = ‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName]['config'];
3323  $fieldType = $fieldConfig['type'];
3324  $evalRules = $fieldConfig['eval'] ?: '';
3325  if ($fieldType === 'input' && $evalRules && GeneralUtility::inList($evalRules, 'int')) {
3326  if (!isset($fieldConfig['search']['pidonly'])
3327  || ($fieldConfig['search']['pidonly'] && $currentPid > 0)
3328  ) {
3329  $constraints[] = $expressionBuilder->andX(
3330  $expressionBuilder->eq($fieldName, (int)$this->searchString),
3331  $expressionBuilder->eq($tablePidField, (int)$currentPid)
3332  );
3333  }
3334  } elseif ($fieldType === 'text'
3335  || $fieldType === 'flex'
3336  || $fieldType === 'slug'
3337  || ($fieldType === 'input' && (!$evalRules || !preg_match('/\b(?:date|time|int)\b/', $evalRules)))
3338  ) {
3339  $constraints[] = $expressionBuilder->like(
3340  $fieldName,
3341  $queryBuilder->quote('%' . (int)$this->searchString . '%')
3342  );
3343  }
3344  }
3345  } elseif (!empty($searchableFields)) {
3346  $like = $queryBuilder->quote('%' . $queryBuilder->escapeLikeWildcards($this->searchString) . '%');
3347  foreach ($searchableFields as $fieldName) {
3348  if (!isset(‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName])) {
3349  continue;
3350  }
3351  $fieldConfig = ‪$GLOBALS['TCA'][‪$table]['columns'][$fieldName]['config'];
3352  $fieldType = $fieldConfig['type'];
3353  $evalRules = $fieldConfig['eval'] ?: '';
3354  $searchConstraint = $expressionBuilder->andX(
3355  $expressionBuilder->comparison(
3356  'LOWER(' . $queryBuilder->castFieldToTextType($fieldName) . ')',
3357  'LIKE',
3358  'LOWER(' . $like . ')'
3359  )
3360  );
3361  if (is_array($fieldConfig['search'])) {
3362  $searchConfig = $fieldConfig['search'];
3363  if (in_array('case', $searchConfig)) {
3364  // Replace case insensitive default constraint
3365  $searchConstraint = $expressionBuilder->andX($expressionBuilder->like($fieldName, $like));
3366  }
3367  if (in_array('pidonly', $searchConfig) && $currentPid > 0) {
3368  $searchConstraint->add($expressionBuilder->eq($tablePidField, (int)$currentPid));
3369  }
3370  if ($searchConfig['andWhere']) {
3371  $searchConstraint->add(
3372  ‪QueryHelper::stripLogicalOperatorPrefix($fieldConfig['search']['andWhere'])
3373  );
3374  }
3375  }
3376  if ($fieldType === 'text'
3377  || $fieldType === 'flex'
3378  || $fieldType === 'slug'
3379  || $fieldType === 'input' && (!$evalRules || !preg_match('/\b(?:date|time|int)\b/', $evalRules))
3380  ) {
3381  if ($searchConstraint->count() !== 0) {
3382  $constraints[] = $searchConstraint;
3383  }
3384  }
3385  }
3386  }
3387  // Call hook to add or change the list
3388  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][DatabaseRecordList::class]['makeSearchStringConstraints'] ?? [] as $className) {
3389  $hookObject = GeneralUtility::makeInstance($className);
3390  if (method_exists($hookObject, 'makeSearchStringConstraints')) {
3391  $constraints = $hookObject->makeSearchStringConstraints(
3392  $queryBuilder,
3393  $constraints,
3394  $this->searchString,
3395  ‪$table,
3396  $currentPid
3397  );
3398  }
3399  }
3400  // If no search field conditions have been built ensure no results are returned
3401  if (empty($constraints)) {
3402  return '0=1';
3403  }
3404 
3405  return $expressionBuilder->orX(...$constraints);
3406  }
3407 
3414  protected function ‪getSearchFields($tableName)
3415  {
3416  ‪$fieldArray = [];
3417  $fieldListWasSet = false;
3418  // Get fields from ctrl section of TCA first
3419  if (isset(‪$GLOBALS['TCA'][$tableName]['ctrl']['searchFields'])) {
3420  ‪$fieldArray = ‪GeneralUtility::trimExplode(',', ‪$GLOBALS['TCA'][$tableName]['ctrl']['searchFields'], true);
3421  $fieldListWasSet = true;
3422  }
3423  // Call hook to add or change the list
3424  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'])) {
3425  $hookParameters = [
3426  'tableHasSearchConfiguration' => $fieldListWasSet,
3427  'tableName' => $tableName,
3428  'searchFields' => &‪$fieldArray,
3429  'searchString' => ‪$this->searchString
3430  ];
3431  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'] as $hookFunction) {
3432  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
3433  }
3434  }
3435  return ‪$fieldArray;
3436  }
3437 
3446  public function ‪linkWrapTable(‪$table, $code)
3447  {
3448  if ($this->table !== ‪$table) {
3449  return '<a href="' . htmlspecialchars(
3450  $this->‪listURL('', $table, 'firstElementNumber')
3451  ) . '">' . $code . '</a>';
3452  }
3453  return '<a href="' . htmlspecialchars(
3454  $this->‪listURL('', '', 'sortField,sortRev,table,firstElementNumber')
3455  ) . '">' . $code . '</a>';
3456  }
3457 
3467  public function ‪linkWrapItems(‪$table, $uid, $code, $row)
3468  {
3469  $lang = $this->‪getLanguageService();
3470  $origCode = $code;
3471  // If the title is blank, make a "no title" label:
3472  if ((string)$code === '') {
3473  $code = '<i>[' . htmlspecialchars(
3474  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title')
3475  ) . ']</i> - '
3476  . htmlspecialchars(‪BackendUtility::getRecordTitle(‪$table, $row));
3477  } else {
3478  $code = htmlspecialchars($code, ENT_QUOTES, 'UTF-8', false);
3479  if ($code != htmlspecialchars($origCode)) {
3480  $code = '<span title="' . htmlspecialchars(
3481  $origCode,
3482  ENT_QUOTES,
3483  'UTF-8',
3484  false
3485  ) . '">' . $code . '</span>';
3486  } else {
3487  $code = '<span title="' . $code . '">' . $code . '</span>';
3488  }
3489  }
3490  switch ((string)$this->clickTitleMode) {
3491  case 'edit':
3492  // If the listed table is 'pages' we have to request the permission settings for each page:
3493  if (‪$table === 'pages') {
3494  $localCalcPerms = $this->‪getBackendUserAuthentication()->‪calcPerms(
3495  ‪BackendUtility::getRecord('pages', $row['uid'])
3496  );
3497  $permsEdit = $localCalcPerms & ‪Permission::PAGE_EDIT;
3498  } else {
3499  $backendUser = $this->‪getBackendUserAuthentication();
3500  $permsEdit = $this->calcPerms & ‪Permission::CONTENT_EDIT && $backendUser->recordEditAccessInternals(‪$table, $row);
3501  }
3502  // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
3503  if ($permsEdit && $this->‪isEditable($table)) {
3504  $params = '&edit[' . ‪$table . '][' . $row['uid'] . ']=edit';
3505  $editLink = $this->uriBuilder->buildUriFromRoute('record_edit') . $params . $this->‪makeReturnUrl();
3506  $code = '<a href="' . htmlspecialchars($editLink) . '" title="' . htmlspecialchars($lang->getLL('edit')) . '">' . $code . '</a>';
3507  }
3508  break;
3509  case 'show':
3510  // "Show" link (only pages and tt_content elements)
3511  if (‪$table === 'pages' || ‪$table === 'tt_content') {
3512  $onClick = $this->‪getOnClickForRow($table, $row);
3513  $code = '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . htmlspecialchars(
3514  $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage')
3515  ) . '">' . $code . '</a>';
3516  }
3517  break;
3518  case 'info':
3519  // "Info": (All records)
3520  $code = '<a href="#" ' . $this->‪createShowItemTagAttributes($table . ',' . (int)$row['uid'])
3521  . ' title="' . htmlspecialchars($lang->getLL('showInfo')) . '">' . $code . '</a>';
3522  break;
3523  default:
3524  // Output the label now:
3525  if (‪$table === 'pages') {
3526  $code = '<a href="' . htmlspecialchars(
3527  $this->‪listURL((string)$uid, '', 'firstElementNumber')
3528  ) . '" onclick="setHighlight(' . (int)$uid . ')">' . $code . '</a>';
3529  } else {
3530  $code = $this->‪linkUrlMail($code, $origCode);
3531  }
3532  }
3533  return $code;
3534  }
3535 
3543  public function ‪linkUrlMail($code, $testString)
3544  {
3545  // Check for URL:
3546  $scheme = parse_url($testString, PHP_URL_SCHEME);
3547  if ($scheme === 'http' || $scheme === 'https' || $scheme === 'ftp') {
3548  return '<a href="' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
3549  }
3550  // Check for email:
3551  if (GeneralUtility::validEmail($testString)) {
3552  return '<a href="mailto:' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
3553  }
3554  // Return if nothing else...
3555  return $code;
3556  }
3557 
3568  public function ‪listURL($altId = '', ‪$table = '-1', $exclList = '')
3569  {
3570  $urlParameters = [];
3571  if ((string)$altId !== '') {
3572  $urlParameters['id'] = $altId;
3573  } else {
3574  $urlParameters['id'] = ‪$this->id;
3575  }
3576  if (‪$table === '-1') {
3577  $urlParameters['table'] = ‪$this->table;
3578  } else {
3579  $urlParameters['table'] = ‪$table;
3580  }
3581  if ($this->thumbs) {
3582  $urlParameters['imagemode'] = ‪$this->thumbs;
3583  }
3584  if ($this->returnUrl) {
3585  $urlParameters['returnUrl'] = ‪$this->returnUrl;
3586  }
3587  if ((!$exclList || !GeneralUtility::inList($exclList, 'search_field')) && $this->searchString) {
3588  $urlParameters['search_field'] = ‪$this->searchString;
3589  }
3590  if ($this->searchLevels) {
3591  $urlParameters['search_levels'] = ‪$this->searchLevels;
3592  }
3593  if ($this->showLimit) {
3594  $urlParameters['showLimit'] = ‪$this->showLimit;
3595  }
3596  if ((!$exclList || !GeneralUtility::inList($exclList, 'firstElementNumber')) && $this->firstElementNumber) {
3597  $urlParameters['pointer'] = ‪$this->firstElementNumber;
3598  }
3599  if ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField) {
3600  $urlParameters['sortField'] = ‪$this->sortField;
3601  }
3602  if ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev) {
3603  $urlParameters['sortRev'] = ‪$this->sortRev;
3604  }
3605 
3606  $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters);
3607 
3608  if ($routePath = GeneralUtility::_GP('route')) {
3609  $url = (string)$this->uriBuilder->buildUriFromRoutePath($routePath, $urlParameters);
3610  } else {
3611  $url = GeneralUtility::getIndpEnv('SCRIPT_NAME') . ‪HttpUtility::buildQueryString($urlParameters, '?');
3612  }
3613  return $url;
3614  }
3615 
3624  public function ‪makeFieldList(‪$table, $dontCheckUser = false, $addDateFields = false)
3625  {
3626  $backendUser = $this->‪getBackendUserAuthentication();
3627  // Init fieldlist array:
3628  $fieldListArr = [];
3629  // Check table:
3630  if (is_array(‪$GLOBALS['TCA'][‪$table]) && isset(‪$GLOBALS['TCA'][‪$table]['columns']) && is_array(
3631  ‪$GLOBALS['TCA'][‪$table]['columns']
3632  )) {
3633  if (isset(‪$GLOBALS['TCA'][‪$table]['columns']) && is_array(‪$GLOBALS['TCA'][‪$table]['columns'])) {
3634  // Traverse configured columns and add them to field array, if available for user.
3635  foreach (‪$GLOBALS['TCA'][‪$table]['columns'] as $fN => $fieldValue) {
3636  if ($fieldValue['config']['type'] === 'none') {
3637  // Never render or fetch type=none fields from db
3638  continue;
3639  }
3640  if ($dontCheckUser
3641  || (!$fieldValue['exclude'] || $backendUser->check('non_exclude_fields', ‪$table . ':' . $fN)) && $fieldValue['config']['type'] !== 'passthrough'
3642  ) {
3643  $fieldListArr[] = $fN;
3644  }
3645  }
3646 
3647  $fieldListArr[] = 'uid';
3648  $fieldListArr[] = 'pid';
3649 
3650  // Add date fields
3651  if ($dontCheckUser || $backendUser->isAdmin() || $addDateFields) {
3652  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['tstamp']) {
3653  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['tstamp'];
3654  }
3655  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['crdate']) {
3656  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['crdate'];
3657  }
3658  }
3659  // Add more special fields:
3660  if ($dontCheckUser || $backendUser->isAdmin()) {
3661  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['cruser_id']) {
3662  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['cruser_id'];
3663  }
3664  if (‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby']) {
3665  $fieldListArr[] = ‪$GLOBALS['TCA'][‪$table]['ctrl']['sortby'];
3666  }
3668  $fieldListArr[] = 't3ver_state';
3669  $fieldListArr[] = 't3ver_wsid';
3670  $fieldListArr[] = 't3ver_oid';
3671  }
3672  }
3673  } else {
3674  GeneralUtility::makeInstance(LogManager::class)
3675  ->getLogger(__CLASS__)
3676  ->error('TCA is broken for the table "' . ‪$table . '": no required "columns" entry in TCA.');
3677  }
3678  }
3679  return $fieldListArr;
3680  }
3681 
3687  public function ‪setOverrideUrlParameters(array $urlParameters)
3688  {
3689  $currentUrlParameter = GeneralUtility::_GP('curUrl');
3690  if (isset($currentUrlParameter['url'])) {
3691  $urlParameters['P']['currentValue'] = $currentUrlParameter['url'];
3692  }
3693  $this->overrideUrlParameters = $urlParameters;
3694  }
3695 
3708  public function ‪setTableDisplayOrder(array $orderInformation)
3709  {
3710  foreach ($orderInformation as $tableName => &$configuration) {
3711  if (isset($configuration['before'])) {
3712  if (is_string($configuration['before'])) {
3713  $configuration['before'] = ‪GeneralUtility::trimExplode(',', $configuration['before'], true);
3714  } elseif (!is_array($configuration['before'])) {
3715  throw new \UnexpectedValueException(
3716  'The specified "before" order configuration for table "' . $tableName . '" is invalid.',
3717  1504793406
3718  );
3719  }
3720  }
3721  if (isset($configuration['after'])) {
3722  if (is_string($configuration['after'])) {
3723  $configuration['after'] = ‪GeneralUtility::trimExplode(',', $configuration['after'], true);
3724  } elseif (!is_array($configuration['after'])) {
3725  throw new \UnexpectedValueException(
3726  'The specified "after" order configuration for table "' . $tableName . '" is invalid.',
3727  1504793407
3728  );
3729  }
3730  }
3731  }
3732  $this->tableDisplayOrder = $orderInformation;
3733  }
3734 
3738  public function ‪getOverridePageIdList(): array
3739  {
3741  }
3742 
3746  public function ‪setOverridePageIdList(array ‪$overridePageIdList)
3747  {
3748  $this->overridePageIdList = array_map('intval', ‪$overridePageIdList);
3749  }
3750 
3759  protected function ‪getSearchableWebmounts(‪$id, $depth, ‪$perms_clause)
3760  {
3761  $runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
3762  $hash = 'webmounts_list' . md5(‪$id . '-' . $depth . '-' . ‪$perms_clause);
3763  $idList = $runtimeCache->get($hash);
3764  if ($idList === false) {
3765  $backendUser = $this->‪getBackendUserAuthentication();
3767  $tree = GeneralUtility::makeInstance(PageTreeView::class);
3768  $tree->init('AND ' . ‪$perms_clause);
3769  $tree->makeHTML = 0;
3770  $tree->fieldArray = ['uid', 'php_tree_stop'];
3771  $idList = [];
3772 
3773  $allowedMounts = !$backendUser->isAdmin() && ‪$id === 0
3774  ? $backendUser->returnWebmounts()
3775  : [‪$id];
3776 
3777  foreach ($allowedMounts as $allowedMount) {
3778  $idList[] = $allowedMount;
3779  if ($depth) {
3780  $tree->getTree($allowedMount, $depth, '');
3781  }
3782  $idList = array_merge($idList, $tree->ids);
3783  }
3784  $runtimeCache->set($hash, $idList);
3785  }
3786 
3787  return $idList;
3788  }
3789 
3798  protected function ‪addPageIdConstraint(string $tableName, QueryBuilder $queryBuilder): QueryBuilder
3799  {
3800  // Set search levels:
3802 
3803  // Set search levels to 999 instead of -1 as the following methods
3804  // do not support -1 as valid value for infinite search.
3805  if (‪$searchLevels === -1) {
3806  ‪$searchLevels = 999;
3807  }
3808 
3809  // When querying translated pages, the PID of the translated pages should be the same as the
3810  // the PID of the current page
3811  if ($tableName === 'pages' && $this->‪showOnlyTranslatedRecords) {
3812  $queryBuilder->andWhere(
3813  $queryBuilder->expr()->eq(
3814  $tableName . '.pid',
3815  $queryBuilder->createNamedParameter($this->pageRecord['pid'], \PDO::PARAM_INT)
3816  )
3817  );
3818  } elseif (‪$searchLevels === 0) {
3819  $queryBuilder->andWhere(
3820  $queryBuilder->expr()->eq(
3821  $tableName . '.pid',
3822  $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
3823  )
3824  );
3825  } elseif (‪$searchLevels > 0) {
3826  $allowedMounts = $this->‪getSearchableWebmounts($this->id, ‪$searchLevels, $this->perms_clause);
3827  $queryBuilder->andWhere(
3828  $queryBuilder->expr()->in(
3829  $tableName . '.pid',
3830  $queryBuilder->createNamedParameter($allowedMounts, Connection::PARAM_INT_ARRAY)
3831  )
3832  );
3833  }
3834 
3835  if (!empty($this->‪getOverridePageIdList())) {
3836  $queryBuilder->andWhere(
3837  $queryBuilder->expr()->in(
3838  $tableName . '.pid',
3839  $queryBuilder->createNamedParameter($this->getOverridePageIdList(), Connection::PARAM_INT_ARRAY)
3840  )
3841  );
3842  }
3843 
3844  return $queryBuilder;
3845  }
3846 
3850  protected function ‪getBackendUserAuthentication()
3851  {
3852  return ‪$GLOBALS['BE_USER'];
3853  }
3854 
3869  public function ‪addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $colType = 'td')
3870  {
3871  $colType = ($colType === 'th') ? 'th' : 'td';
3872  // Start up:
3873  $l10nParent = isset($data['_l10nparent_']) ? (int)$data['_l10nparent_'] : 0;
3874  $out = '
3875  <!-- Element, begin: -->
3876  <tr ' . $rowParams . ' data-uid="' . (int)$data['uid'] . '" data-l10nparent="' . $l10nParent . '">';
3877  // Show icon and lines
3878  if ($this->showIcon) {
3879  $out .= '
3880  <' . $colType . ' class="col-icon nowrap">';
3881  if (!$h) {
3882  $out .= '&nbsp;';
3883  } else {
3884  for ($a = 0; $a < $h; $a++) {
3885  if (!$a) {
3886  if ($icon) {
3887  $out .= $icon;
3888  }
3889  }
3890  }
3891  }
3892  $out .= '</' . $colType . '>
3893  ';
3894  }
3895  // Init rendering.
3896  $colsp = '';
3897  $lastKey = '';
3898  $c = 0;
3899  $ccount = 0;
3900  // __label is used as the label key to circumvent problems with uid used as label (see #67756)
3901  // as it was introduced later on, check if it really exists before using it
3903  if ($colType === 'td' && array_key_exists('__label', $data)) {
3904  ‪$fields[0] = '__label';
3905  }
3906  // Traverse field array which contains the data to present:
3907  foreach (‪$fields as $vKey) {
3908  if (isset($data[$vKey])) {
3909  if ($lastKey) {
3910  $cssClass = $this->addElement_tdCssClass[$lastKey];
3911  if ($this->oddColumnsCssClass && $ccount % 2 == 0) {
3912  $cssClass = implode(' ', [$this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass]);
3913  }
3914  $out .= '
3915  <' . $colType . ' class="' . $cssClass . ' nowrap' . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
3916  }
3917  $lastKey = $vKey;
3918  $c = 1;
3919  $ccount++;
3920  } else {
3921  if (!$lastKey) {
3922  $lastKey = $vKey;
3923  }
3924  $c++;
3925  }
3926  if ($c > 1) {
3927  $colsp = ' colspan="' . $c . '"';
3928  } else {
3929  $colsp = '';
3930  }
3931  }
3932  if ($lastKey) {
3933  $cssClass = $this->addElement_tdCssClass[$lastKey];
3934  if ($this->oddColumnsCssClass) {
3935  $cssClass = implode(' ', [$this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass]);
3936  }
3937  $out .= '
3938  <' . $colType . ' class="' . $cssClass . ' nowrap' . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
3939  }
3940  // End row
3941  $out .= '
3942  </tr>';
3943  // Return row.
3944  return $out;
3945  }
3946 
3950  public function ‪initializeLanguages()
3951  {
3952  // Look up page overlays:
3953  $localizationParentField = ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
3954  $languageField = ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'];
3955  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
3956  ->getQueryBuilderForTable('pages');
3957  $queryBuilder->getRestrictions()
3958  ->removeAll()
3959  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
3960  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUserAuthentication()->workspace));
3961  $result = $queryBuilder
3962  ->select('*')
3963  ->from('pages')
3964  ->where(
3965  $queryBuilder->expr()->andX(
3966  $queryBuilder->expr()->eq($localizationParentField, $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
3967  $queryBuilder->expr()->gt(
3968  $languageField,
3969  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
3970  )
3971  )
3972  )
3973  ->execute();
3974 
3975  $this->pageOverlays = [];
3976  while ($row = $result->fetch()) {
3977  $this->pageOverlays[$row[$languageField]] = $row;
3978  }
3979 
3980  $this->languageIconTitles = $this->‪getTranslateTools()->‪getSystemLanguages($this->id);
3981  }
3982 
3990  public function ‪languageFlag($sys_language_uid, $addAsAdditionalText = true)
3991  {
3992  $out = '';
3993  $languageInformation = $this->‪getTranslateTools()->‪getSystemLanguages($this->id);
3994  $title = htmlspecialchars($languageInformation[$sys_language_uid]['title']);
3995  if ($languageInformation[$sys_language_uid]['flagIcon']) {
3996  $out .= '<span title="' . $title . '">' . $this->iconFactory->getIcon(
3997  $languageInformation[$sys_language_uid]['flagIcon'],
3999  )->render() . '</span>';
4000  if (!$addAsAdditionalText) {
4001  return $out;
4002  }
4003  $out .= '&nbsp;';
4004  }
4005  $out .= $title;
4006  return $out;
4007  }
4008 
4012  protected function ‪determineScriptUrl()
4013  {
4014  if ($routePath = GeneralUtility::_GP('route')) {
4015  $this->thisScript = (string)$this->uriBuilder->buildUriFromRoutePath($routePath);
4016  } else {
4017  $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
4018  }
4019  }
4020 
4024  protected function ‪getThisScript()
4025  {
4026  return strpos($this->thisScript, '?') === false ? $this->thisScript . '?' : $this->thisScript . '&';
4027  }
4028 
4034  protected function ‪getTranslateTools()
4035  {
4036  if (!isset($this->translateTools)) {
4037  $this->translateTools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
4038  }
4039  return ‪$this->translateTools;
4040  }
4041 
4046  protected function ‪generateReferenceToolTip(string ‪$table, int $uid): string
4047  {
4048  $numberOfReferences = $this->‪getReferenceCount($table, $uid);
4049  if (!$numberOfReferences) {
4050  $htmlCode = '-';
4051  } else {
4052  $htmlCode = '<a href="#"';
4053  $htmlCode .= ' ' . $this->‪createShowItemTagAttributes($table . ',' . $uid);
4054 
4055  $htmlCode .= ' title="' . htmlspecialchars(
4056  $this->‪getLanguageService()->sL(
4057  'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references'
4058  ) . ' (' . $numberOfReferences . ')'
4059  ) . '">';
4060  $htmlCode .= $numberOfReferences;
4061  $htmlCode .= '</a>';
4062  }
4063  return $htmlCode;
4064  }
4065 
4073  {
4075  }
4076 
4083  protected function ‪createShowItemTagAttributes(string $arguments): string
4084  {
4085  return GeneralUtility::implodeAttributes([
4086  'data-dispatch-action' => 'TYPO3.InfoWindow.showItem',
4087  'data-dispatch-args-list' => $arguments,
4088  ], true);
4089  }
4090 
4101  protected function ‪getVisibleColumns(array $tableTCA, string $type)
4102  {
4103  $visibleColumns = $tableTCA['types'][$type]['showitem'] ?? '';
4104 
4105  if (strpos($visibleColumns, '--palette--') !== false) {
4106  $matches = [];
4107  preg_match_all('/--palette--\s*;[^;]*;\s*(\w+)/', $visibleColumns, $matches, PREG_SET_ORDER);
4108  if (!empty($matches)) {
4109  foreach ($matches as $palette) {
4110  $paletteColumns = $tableTCA['palettes'][$palette[1]]['showitem'] ?? '';
4111  $paletteColumns = rtrim($paletteColumns, ", \t\r\n");
4112  $visibleColumns = str_replace($palette[0], $paletteColumns, $visibleColumns);
4113  }
4114  }
4115  }
4116 
4117  return $visibleColumns;
4118  }
4119 
4124  protected function ‪getLanguageService()
4125  {
4126  return ‪$GLOBALS['LANG'];
4127  }
4128 
4133  public function ‪setLanguagesAllowedForUser(array ‪$languagesAllowedForUser): DatabaseRecordList
4134  {
4135  $this->languagesAllowedForUser = ‪$languagesAllowedForUser;
4136  return $this;
4137  }
4138 
4146  protected function ‪getNoViewWithDokTypes(array $tsConfig): array
4147  {
4148  if (isset($tsConfig['noViewWithDokTypes'])) {
4149  $noViewDokTypes = ‪GeneralUtility::intExplode(',', $tsConfig['noViewWithDokTypes'], true);
4150  } else {
4151  $noViewDokTypes = [
4155  ];
4156  }
4157 
4158  return $noViewDokTypes;
4159  }
4160 }
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$sortField
‪string $sortField
Definition: DatabaseRecordList.php:162
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\clipNumPane
‪bool clipNumPane()
Definition: DatabaseRecordList.php:2443
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$uriBuilder
‪UriBuilder $uriBuilder
Definition: DatabaseRecordList.php:471
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$hideTables
‪string $hideTables
Definition: DatabaseRecordList.php:279
‪TYPO3\CMS\Core\Database\Query\QueryHelper\parseOrderBy
‪static array array[] parseOrderBy(string $input)
Definition: QueryHelper.php:44
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$selFieldList
‪string $selFieldList
Definition: DatabaseRecordList.php:447
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageOverlays
‪array $pageOverlays
Definition: DatabaseRecordList.php:132
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setLanguagesAllowedForUser
‪DatabaseRecordList setLanguagesAllowedForUser(array $languagesAllowedForUser)
Definition: DatabaseRecordList.php:4057
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$clickTitleMode
‪string $clickTitleMode
Definition: DatabaseRecordList.php:328
‪TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface
Definition: RecordListGetTableHookInterface.php:23
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\renderListNavigation
‪string renderListNavigation($renderPart='top')
Definition: DatabaseRecordList.php:1619
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$duplicateField
‪string $duplicateField
Definition: DatabaseRecordList.php:404
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\outputCSV
‪outputCSV($prefix)
Definition: DatabaseRecordList.php:2609
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$recPath_cache
‪mixed[] $recPath_cache
Definition: DatabaseRecordList.php:156
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$itemsLimitPerTable
‪int $itemsLimitPerTable
Definition: DatabaseRecordList.php:168
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\__construct
‪__construct()
Definition: DatabaseRecordList.php:524
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showOnlyTranslatedRecords
‪bool $showOnlyTranslatedRecords
Definition: DatabaseRecordList.php:505
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_LEFT
‪const BUTTON_POSITION_LEFT
Definition: ButtonBar.php:36
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:32
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getQueryBuilder
‪TYPO3 CMS Core Database Query QueryBuilder getQueryBuilder(string $table, int $pageId, array $additionalConstraints=[], array $fields=[' *'])
Definition: DatabaseRecordList.php:3057
‪TYPO3\CMS\Backend\Utility\BackendUtility\getLinkToDataHandlerAction
‪static string getLinkToDataHandlerAction($parameters, $redirectUrl='')
Definition: BackendUtility.php:2539
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$perms_clause
‪string $perms_clause
Definition: DatabaseRecordList.php:304
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getDocHeaderButtons
‪getDocHeaderButtons(ModuleTemplate $moduleTemplate)
Definition: DatabaseRecordList.php:542
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$moduleData
‪array $moduleData
Definition: DatabaseRecordList.php:175
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$CBnames
‪string[] $CBnames
Definition: DatabaseRecordList.php:428
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tablesCollapsed
‪int[][] $tablesCollapsed
Definition: DatabaseRecordList.php:227
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_NEW
‪const PAGE_NEW
Definition: Permission.php:48
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addToCSV
‪addToCSV(array $row=[])
Definition: DatabaseRecordList.php:2560
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getLanguageService
‪LanguageService getLanguageService()
Definition: DatabaseRecordList.php:4048
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getThisScript
‪string getThisScript()
Definition: DatabaseRecordList.php:3948
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$noControlPanels
‪bool $noControlPanels
Definition: DatabaseRecordList.php:92
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$duplicateStack
‪string[] $duplicateStack
Definition: DatabaseRecordList.php:193
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\generateReferenceToolTip
‪generateReferenceToolTip(string $table, int $uid)
Definition: DatabaseRecordList.php:3970
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\eq
‪string eq(string $fieldName, $value)
Definition: ExpressionBuilder.php:109
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Core\Imaging\Icon\render
‪string render($alternativeMarkupIdentifier=null)
Definition: Icon.php:232
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addSortLink
‪string addSortLink($code, $field, $table)
Definition: DatabaseRecordList.php:2458
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\calcPerms
‪int calcPerms($row)
Definition: BackendUserAuthentication.php:568
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\listURL
‪string listURL($altId='', $table='-1', $exclList='')
Definition: DatabaseRecordList.php:3492
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$iconFactory
‪IconFactory $iconFactory
Definition: DatabaseRecordList.php:467
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$hideTranslations
‪string $hideTranslations
Definition: DatabaseRecordList.php:144
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$disableSingleTableView
‪bool $disableSingleTableView
Definition: DatabaseRecordList.php:116
‪TYPO3\CMS\Core\Database\ReferenceIndex
Definition: ReferenceIndex.php:48
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$MOD_MENU
‪string[] $MOD_MENU
Definition: DatabaseRecordList.php:457
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getTable
‪string getTable($table, $id, $rowList='')
Definition: DatabaseRecordList.php:688
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$searchLevels
‪int $searchLevels
Definition: DatabaseRecordList.php:338
‪TYPO3\CMS\Core\Utility\CsvUtility\csvValues
‪static string csvValues(array $row, string $delim=',', string $quote='"', int $type = self::TYPE_REMOVE_CONTROLS)
Definition: CsvUtility.php:100
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showIcon
‪int $showIcon
Definition: DatabaseRecordList.php:332
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\createNamedParameter
‪string createNamedParameter($value, int $type=\PDO::PARAM_STR, string $placeHolder=null)
Definition: QueryBuilder.php:941
‪TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface\removeAll
‪QueryRestrictionContainerInterface removeAll()
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tableTSconfigOverTCA
‪mixed[][] $tableTSconfigOverTCA
Definition: DatabaseRecordList.php:356
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$overrideUrlParameters
‪mixed[] $overrideUrlParameters
Definition: DatabaseRecordList.php:493
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\isAdmin
‪bool isAdmin()
Definition: BackendUserAuthentication.php:292
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isRecordCurrentBackendUser
‪bool isRecordCurrentBackendUser($table, $row)
Definition: DatabaseRecordList.php:2654
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$dontShowClipControlPanels
‪bool $dontShowClipControlPanels
Definition: DatabaseRecordList.php:80
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\languageFlag
‪string languageFlag($sys_language_uid, $addAsAdditionalText=true)
Definition: DatabaseRecordList.php:3914
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\orderBy
‪QueryBuilder orderBy(string $fieldName, string $order=null)
Definition: QueryBuilder.php:841
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkUrlMail
‪string linkUrlMail($code, $testString)
Definition: DatabaseRecordList.php:3467
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$totalRowCount
‪int $totalRowCount
Definition: DatabaseRecordList.php:104
‪TYPO3\CMS\Backend\Utility\BackendUtility\getItemLabel
‪static string getItemLabel($table, $col)
Definition: BackendUtility.php:1521
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isRowListingConditionFulfilled
‪bool isRowListingConditionFulfilled($table, $row)
Definition: DatabaseRecordList.php:1129
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isRecordDeletePlaceholder
‪isRecordDeletePlaceholder(array $row)
Definition: DatabaseRecordList.php:2662
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$overridePageIdList
‪array $overridePageIdList
Definition: DatabaseRecordList.php:488
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\getRestrictions
‪QueryRestrictionContainerInterface getRestrictions()
Definition: QueryBuilder.php:104
‪TYPO3\CMS\Backend\Utility\BackendUtility\thumbCode
‪static string thumbCode( $row, $table, $field, $backPath='', $thumbScript='', $uploaddir=null, $abs=0, $tparams='', $size='', $linkInfoPopup=true)
Definition: BackendUtility.php:1137
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:33
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$setFields
‪string[] $setFields
Definition: DatabaseRecordList.php:368
‪TYPO3\CMS\Core\Versioning\VersionState\DELETE_PLACEHOLDER
‪const DELETE_PLACEHOLDER
Definition: VersionState.php:55
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$addElement_tdCssClass
‪array $addElement_tdCssClass
Definition: DatabaseRecordList.php:243
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$translations
‪string[] $translations
Definition: DatabaseRecordList.php:440
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$fieldArray
‪array $fieldArray
Definition: DatabaseRecordList.php:273
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getSearchBox
‪string getSearchBox($formFields=true)
Definition: DatabaseRecordList.php:2934
‪TYPO3\CMS\Backend\Utility\BackendUtility\BEgetRootLine
‪static array BEgetRootLine($uid, $clause='', $workspaceOL=false, array $additionalFields=[])
Definition: BackendUtility.php:343
‪TYPO3\CMS\Backend\Tree\View\PageTreeView
Definition: PageTreeView.php:24
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$listOnlyInSingleTableMode
‪bool $listOnlyInSingleTableMode
Definition: DatabaseRecordList.php:205
‪TYPO3\CMS\Backend\Utility\BackendUtility\wrapInHelp
‪static string wrapInHelp($table, $field, $text='', array $overloadHelpText=[])
Definition: BackendUtility.php:2260
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$table
‪string $table
Definition: DatabaseRecordList.php:316
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\initCSV
‪initCSV()
Definition: DatabaseRecordList.php:2530
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:43
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$calcPerms
‪int $calcPerms
Definition: DatabaseRecordList.php:322
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\showNewRecLink
‪bool showNewRecLink($table)
Definition: DatabaseRecordList.php:2500
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showLimit
‪int $showLimit
Definition: DatabaseRecordList.php:267
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:24
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$currentTable
‪int[][] $currentTable
Definition: DatabaseRecordList.php:255
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tableList
‪string $tableList
Definition: DatabaseRecordList.php:410
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setDispFields
‪setDispFields()
Definition: DatabaseRecordList.php:3031
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$script
‪string $script
Definition: DatabaseRecordList.php:199
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\initializeLanguages
‪initializeLanguages()
Definition: DatabaseRecordList.php:3874
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setTableDisplayOrder
‪setTableDisplayOrder(array $orderInformation)
Definition: DatabaseRecordList.php:3632
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:52
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$itemsLimitSingleTable
‪int $itemsLimitSingleTable
Definition: DatabaseRecordList.php:221
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:43
‪TYPO3\CMS\Backend\Utility\BackendUtility\isTableWorkspaceEnabled
‪static bool isTableWorkspaceEnabled($table)
Definition: BackendUtility.php:4021
‪TYPO3\CMS\Backend\Utility\BackendUtility\translationCount
‪static string translationCount($table, $ref, $msg='')
Definition: BackendUtility.php:3361
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList
Definition: DatabaseRecordList.php:57
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getSearchFields
‪string[] getSearchFields($tableName)
Definition: DatabaseRecordList.php:3338
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$tableDisplayOrder
‪array[] $tableDisplayOrder
Definition: DatabaseRecordList.php:482
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$HTMLcode
‪string $HTMLcode
Definition: DatabaseRecordList.php:237
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\renderListHeader
‪string renderListHeader($table, $currentIdList)
Definition: DatabaseRecordList.php:1360
‪TYPO3\CMS\Backend\Utility\BackendUtility\wrapClickMenuOnIcon
‪static string wrapClickMenuOnIcon( $content, $table, $uid=0, $context='', $_addParams='', $_enDisItems='', $returnTagParameters=false)
Definition: BackendUtility.php:2510
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageRow
‪string[] $pageRow
Definition: DatabaseRecordList.php:126
‪TYPO3\CMS\Core\Type\Enumeration\cast
‪static static cast($value)
Definition: Enumeration.php:186
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$oddColumnsCssClass
‪string $oddColumnsCssClass
Definition: DatabaseRecordList.php:291
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getTranslateTools
‪TranslationConfigurationProvider getTranslateTools()
Definition: DatabaseRecordList.php:3958
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$allowedNewTables
‪string[] $allowedNewTables
Definition: DatabaseRecordList.php:67
‪TYPO3\CMS\Recordlist\RecordList
Definition: DatabaseRecordList.php:16
‪TYPO3\CMS\Core\Messaging\AbstractMessage\WARNING
‪const WARNING
Definition: AbstractMessage.php:30
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$displayFields
‪string[] $displayFields
Definition: DatabaseRecordList.php:285
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$currentLink
‪array $currentLink
Definition: DatabaseRecordList.php:499
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getPointerForPage
‪int getPointerForPage($page)
Definition: DatabaseRecordList.php:1608
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$thumbs
‪bool $thumbs
Definition: DatabaseRecordList.php:249
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\in
‪string in(string $fieldName, $value)
Definition: ExpressionBuilder.php:244
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$clipObj
‪TYPO3 CMS Backend Clipboard Clipboard $clipObj
Definition: DatabaseRecordList.php:422
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\fieldSelectBox
‪string fieldSelectBox($table, $formFields=true)
Definition: DatabaseRecordList.php:2313
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\removeControlFieldsFromFieldRow
‪static mixed[] removeControlFieldsFromFieldRow(array $row=[])
Definition: DatabaseRecordList.php:2576
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeReturnUrl
‪string makeReturnUrl()
Definition: DatabaseRecordList.php:2517
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\andWhere
‪QueryBuilder andWhere(... $where)
Definition: QueryBuilder.php:694
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$deniedNewTables
‪string[] $deniedNewTables
Definition: DatabaseRecordList.php:74
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setOverrideUrlParameters
‪setOverrideUrlParameters(array $urlParameters)
Definition: DatabaseRecordList.php:3611
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getSearchableWebmounts
‪int[] getSearchableWebmounts($id, $depth, $perms_clause)
Definition: DatabaseRecordList.php:3683
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setCsvRow
‪setCsvRow($csvRow)
Definition: DatabaseRecordList.php:2595
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$clickMenuEnabled
‪bool $clickMenuEnabled
Definition: DatabaseRecordList.php:98
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:38
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\generateList
‪generateList()
Definition: DatabaseRecordList.php:2830
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeLocalizationPanel
‪string[] makeLocalizationPanel($table, $row)
Definition: DatabaseRecordList.php:2242
‪TYPO3\CMS\Core\Utility\HttpUtility\buildQueryString
‪static string buildQueryString(array $parameters, string $prependCharacter='', bool $skipEmptyParameters=false)
Definition: HttpUtility.php:163
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkWrapTable
‪string linkWrapTable($table, $code)
Definition: DatabaseRecordList.php:3370
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$id
‪int $id
Definition: DatabaseRecordList.php:187
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$fixedL
‪int $fixedL
Definition: DatabaseRecordList.php:298
‪TYPO3\CMS\Backend\Utility\BackendUtility\getPagesTSconfig
‪static array getPagesTSconfig($id)
Definition: BackendUtility.php:698
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordToolTip
‪static string getRecordToolTip(array $row, $table='pages')
Definition: BackendUtility.php:1339
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordTitle
‪static string getRecordTitle($table, $row, $prep=false, $forceResult=true)
Definition: BackendUtility.php:1541
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$systemLanguagesOnPage
‪array $systemLanguagesOnPage
Definition: DatabaseRecordList.php:513
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:108
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\editLockPermissions
‪bool editLockPermissions()
Definition: DatabaseRecordList.php:2722
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setTotalItems
‪setTotalItems(string $table, int $pageId, array $constraints)
Definition: DatabaseRecordList.php:3193
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getReferenceCount
‪int getReferenceCount($tableName, $uid)
Definition: DatabaseRecordList.php:1340
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Core\Service\DependencyOrderingService
Definition: DependencyOrderingService.php:32
‪TYPO3\CMS\Core\Utility\CsvUtility
Definition: CsvUtility.php:24
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$searchString
‪string $searchString
Definition: DatabaseRecordList.php:392
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageRecord
‪string[] $pageRecord
Definition: DatabaseRecordList.php:362
‪TYPO3\CMS\Backend\Utility\BackendUtility\getProcessedValueExtra
‪static string getProcessedValueExtra( $table, $fN, $fV, $fixed_lgd_chars=0, $uid=0, $forceResult=true, $pid=0)
Definition: BackendUtility.php:2100
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\checkLanguageAccess
‪bool checkLanguageAccess($langValue)
Definition: BackendUserAuthentication.php:709
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$thisScript
‪string $thisScript
Definition: DatabaseRecordList.php:211
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:33
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:109
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeControl
‪string makeControl($table, $row)
Definition: DatabaseRecordList.php:1732
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getOnClickForRow
‪string getOnClickForRow(string $table, array $row)
Definition: DatabaseRecordList.php:1086
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setOverridePageIdList
‪setOverridePageIdList(array $overridePageIdList)
Definition: DatabaseRecordList.php:3670
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordWSOL
‪static array getRecordWSOL( $table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
Definition: BackendUtility.php:139
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkClipboardHeaderIcon
‪string linkClipboardHeaderIcon($string, $table, $cmd, $warning='', $title='')
Definition: DatabaseRecordList.php:2409
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$iLimit
‪int $iLimit
Definition: DatabaseRecordList.php:344
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$showClipboard
‪bool $showClipboard
Definition: DatabaseRecordList.php:86
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecord
‪static array null getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
Definition: BackendUtility.php:95
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addActionToCellGroup
‪addActionToCellGroup(&$cells, $action, $actionKey)
Definition: DatabaseRecordList.php:2632
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$returnUrl
‪string $returnUrl
Definition: DatabaseRecordList.php:310
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\setMaxResults
‪QueryBuilder setMaxResults(int $maxResults)
Definition: QueryBuilder.php:355
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface
Definition: RecordListHookInterface.php:22
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$referenceCount
‪int[][] $referenceCount
Definition: DatabaseRecordList.php:434
‪TYPO3\CMS\Backend\Template\Components\DocHeaderComponent\getButtonBar
‪ButtonBar getButtonBar()
Definition: DocHeaderComponent.php:82
‪$output
‪$output
Definition: annotationChecker.php:119
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\overlayEditLockPermissions
‪bool overlayEditLockPermissions($table, $row=[], $editPermission=true)
Definition: DatabaseRecordList.php:2700
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:36
‪TYPO3\CMS\Backend\Utility\BackendUtility\viewOnClick
‪static string viewOnClick( $pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
Definition: BackendUtility.php:2359
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$modTSconfig
‪array[] $modTSconfig
Definition: DatabaseRecordList.php:231
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$editable
‪bool $editable
Definition: DatabaseRecordList.php:463
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
Definition: TranslationConfigurationProvider.php:35
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider\getSystemLanguages
‪array getSystemLanguages($pageId=0)
Definition: TranslationConfigurationProvider.php:47
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:24
‪TYPO3\CMS\Core\Type\Bitmask\Permission\CONTENT_EDIT
‪const CONTENT_EDIT
Definition: Permission.php:53
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:165
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\prepareQueryBuilder
‪QueryBuilder prepareQueryBuilder(string $table, int $pageId, array $fieldList=[' *'], array $additionalConstraints=[], QueryBuilder $queryBuilder, bool $addSorting=true)
Definition: DatabaseRecordList.php:3094
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeSearchString
‪string makeSearchString($table, $currentPid=-1)
Definition: DatabaseRecordList.php:3227
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\createShowItemTagAttributes
‪string createShowItemTagAttributes(string $arguments)
Definition: DatabaseRecordList.php:4007
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\renderListRow
‪string renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent=0)
Definition: DatabaseRecordList.php:1147
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\recPath
‪mixed[] recPath($pid)
Definition: DatabaseRecordList.php:2486
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Backend\Utility\BackendUtility\workspaceOL
‪static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
Definition: BackendUtility.php:3586
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\setFirstResult
‪QueryBuilder setFirstResult(int $firstResult)
Definition: QueryBuilder.php:330
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\isEditable
‪bool isEditable(string $table)
Definition: DatabaseRecordList.php:2682
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setIsEditable
‪setIsEditable(bool $isEditable)
Definition: DatabaseRecordList.php:2672
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeClip
‪string makeClip($table, $row)
Definition: DatabaseRecordList.php:2087
‪TYPO3\CMS\Core\Log\LogManager
Definition: LogManager.php:30
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_EDIT
‪const PAGE_EDIT
Definition: Permission.php:38
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\linkWrapItems
‪string linkWrapItems($table, $uid, $code, $row)
Definition: DatabaseRecordList.php:3391
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_DELETE
‪const PAGE_DELETE
Definition: Permission.php:43
‪TYPO3\CMS\Backend\Template\ModuleTemplate\getDocHeaderComponent
‪DocHeaderComponent getDocHeaderComponent()
Definition: ModuleTemplate.php:340
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:988
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$counter
‪int $counter
Definition: DatabaseRecordList.php:374
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getVisibleColumns
‪string getVisibleColumns(array $tableTCA, string $type)
Definition: DatabaseRecordList.php:4025
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\determineScriptUrl
‪determineScriptUrl()
Definition: DatabaseRecordList.php:3936
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$csvOutput
‪bool $csvOutput
Definition: DatabaseRecordList.php:150
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\start
‪start($id, $table, $pointer, $search='', $levels=0, $showLimit=0)
Definition: DatabaseRecordList.php:2749
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addElement
‪string addElement($h, $icon, $data, $rowParams='', $_='', $_2='', $colType='td')
Definition: DatabaseRecordList.php:3793
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$spaceIcon
‪string $spaceIcon
Definition: DatabaseRecordList.php:110
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:24
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\showOnlyTranslatedRecords
‪showOnlyTranslatedRecords(bool $showOnlyTranslatedRecords)
Definition: DatabaseRecordList.php:3996
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$csvLines
‪string[] $csvLines
Definition: DatabaseRecordList.php:416
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getBackendUserAuthentication
‪BackendUserAuthentication getBackendUserAuthentication()
Definition: DatabaseRecordList.php:3774
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getNoViewWithDokTypes
‪array getNoViewWithDokTypes(array $tsConfig)
Definition: DatabaseRecordList.php:4070
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$pageinfo
‪mixed[] $pageinfo
Definition: DatabaseRecordList.php:451
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:52
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\addOrderBy
‪QueryBuilder addOrderBy(string $fieldName, string $order=null)
Definition: QueryBuilder.php:856
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface\add
‪QueryRestrictionContainerInterface add(QueryRestrictionInterface $restriction)
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$eCounter
‪int $eCounter
Definition: DatabaseRecordList.php:386
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$languageIconTitles
‪array $languageIconTitles
Definition: DatabaseRecordList.php:138
‪TYPO3\CMS\Core\Localization\LanguageService\getLL
‪string getLL($index)
Definition: LanguageService.php:154
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$languagesAllowedForUser
‪array $languagesAllowedForUser
Definition: DatabaseRecordList.php:519
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordPath
‪static mixed getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
Definition: BackendUtility.php:546
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$addElement_tdParams
‪array $addElement_tdParams
Definition: DatabaseRecordList.php:181
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_RIGHT
‪const BUTTON_POSITION_RIGHT
Definition: ButtonBar.php:41
‪TYPO3\CMS\Core\Imaging\IconFactory\getIcon
‪Icon getIcon($identifier, $size=Icon::SIZE_DEFAULT, $overlayIdentifier=null, IconState $state=null)
Definition: IconFactory.php:81
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\isLoaded
‪static bool isLoaded($key)
Definition: ExtensionManagementUtility.php:114
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$translateTools
‪TranslationConfigurationProvider $translateTools
Definition: DatabaseRecordList.php:215
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addPageIdConstraint
‪QueryBuilder addPageIdConstraint(string $tableName, QueryBuilder $queryBuilder)
Definition: DatabaseRecordList.php:3722
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$sortRev
‪bool $sortRev
Definition: DatabaseRecordList.php:398
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\addHeaderRowToCSV
‪addHeaderRowToCSV()
Definition: DatabaseRecordList.php:2538
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\getOverridePageIdList
‪array getOverridePageIdList()
Definition: DatabaseRecordList.php:3662
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_RECYCLER
‪const DOKTYPE_RECYCLER
Definition: PageRepository.php:110
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\expr
‪ExpressionBuilder expr()
Definition: QueryBuilder.php:151
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$allFields
‪int $allFields
Definition: DatabaseRecordList.php:261
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\setModuleData
‪setModuleData(array $moduleData=[])
Definition: DatabaseRecordList.php:2734
‪TYPO3\CMS\Backend\Utility\BackendUtility\referenceCount
‪static string int referenceCount($table, $ref, $msg='', $count=null)
Definition: BackendUtility.php:3311
‪TYPO3\CMS\Backend\Utility\BackendUtility\isRecordLocked
‪static array bool isRecordLocked($table, $uid)
Definition: BackendUtility.php:3011
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$totalItems
‪string $totalItems
Definition: DatabaseRecordList.php:350
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\makeFieldList
‪string[] makeFieldList($table, $dontCheckUser=false, $addDateFields=false)
Definition: DatabaseRecordList.php:3548
‪TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList\$firstElementNumber
‪int $firstElementNumber
Definition: DatabaseRecordList.php:380
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39