‪TYPO3CMS  11.5
FileList.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 
16 namespace ‪TYPO3\CMS\Filelist;
17 
18 use Psr\EventDispatcher\EventDispatcherInterface;
19 use Psr\Http\Message\ServerRequestInterface;
24 use TYPO3\CMS\Backend\Utility\BackendUtility;
49 
56 {
62  public ‪$iLimit = 40;
63 
69  public ‪$thumbs = false;
70 
76  public ‪$spaceIcon;
77 
83  public ‪$fixedL = 30;
84 
90  public ‪$sort = '';
91 
97  public ‪$sortRev = true;
98 
102  public ‪$firstElementNumber = 0;
103 
107  public ‪$totalbytes = 0;
108 
114  public ‪$totalItems = 0;
115 
121  public ‪$fieldArray = [];
122 
128  public ‪$counter = 0;
129 
133  public ‪$translateTools;
134 
141  '_CONTROL_' => 'col-control',
142  '_SELECTOR_' => 'col-selector',
143  'icon' => 'col-icon',
144  'name' => 'col-title col-responsive',
145  ];
146 
150  protected ‪$folderObject;
151 
155  public ‪$CBnames = [];
156 
160  public ‪$clipObj;
161 
165  protected ‪$resourceFactory;
166 
170  protected ‪$iconFactory;
171 
175  protected ‪$id = 0;
176 
180  protected ‪$uriBuilder;
181 
182  protected ?‪FileSearchDemand ‪$searchDemand = null;
184 
189  protected array ‪$backendUserCache = [];
190 
191  protected EventDispatcherInterface ‪$eventDispatcher;
192 
193  public function ‪__construct(?ServerRequestInterface $request = null)
194  {
195  // Setting the maximum length of the filenames to the user's settings or minimum 30 (= $this->fixedL)
196  $this->fixedL = max($this->fixedL, $this->‪getBackendUser()->uc['titleLen'] ?? 1);
197  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
198  $this->eventDispatcher = GeneralUtility::makeInstance(EventDispatcherInterface::class);
199  $this->translateTools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
200  $this->iLimit = ‪MathUtility::forceIntegerInRange(
201  $this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['filesPerPage'] ?? $this->iLimit,
202  1
203  );
204  // Create clipboard object and initialize that
205  $this->clipObj = GeneralUtility::makeInstance(Clipboard::class);
206  $this->clipObj->initializeClipboard($request);
207  $this->resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
208  $this->‪getLanguageService()->‪includeLLFile('EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf');
209  $this->‪getLanguageService()->‪includeLLFile('EXT:core/Resources/Private/Language/locallang_common.xlf');
210  $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
211  $this->spaceIcon = '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', ‪Icon::SIZE_SMALL)->render() . '</span>';
212  // Initialize file extension filter, if configured
213  $fileDownloadConfiguration = (array)($this->‪getBackendUser()->‪getTSConfig()['options.']['file_list.']['fileDownload.'] ?? []);
214  if ($fileDownloadConfiguration !== []) {
215  $this->fileExtensionFilter = GeneralUtility::makeInstance(FileExtensionFilter::class);
216  $this->fileExtensionFilter->setAllowedFileExtensions(
217  ‪GeneralUtility::trimExplode(',', (string)($fileDownloadConfiguration['allowedFileExtensions'] ?? ''), true)
218  );
219  $this->fileExtensionFilter->setDisallowedFileExtensions(
220  ‪GeneralUtility::trimExplode(',', (string)($fileDownloadConfiguration['disallowedFileExtensions'] ?? ''), true)
221  );
222  }
223  }
224 
233  public function ‪start(Folder ‪$folderObject, $pointer, ‪$sort, ‪$sortRev)
234  {
235  $this->folderObject = ‪$folderObject;
236  $this->counter = 0;
237  $this->totalbytes = 0;
238  $this->sort = ‪$sort;
239  $this->sortRev = ‪$sortRev;
240  $this->firstElementNumber = $pointer;
241  $this->fieldArray = [
242  '_SELECTOR_', 'icon', 'name', '_CONTROL_', 'record_type', 'size', 'rw', '_REF_',
243  ];
244  }
245 
246  public function ‪setColumnsToRender(array $additionalFields = []): void
247  {
248  $this->fieldArray = array_unique(array_merge($this->fieldArray, $additionalFields));
249  }
250 
257  public function ‪getTable(?FileSearchDemand ‪$searchDemand = null): string
258  {
259  if (‪$searchDemand !== null) {
260  // Store given search demand
261  $this->searchDemand = ‪$searchDemand;
262  // Search currently only works for files
263  $folders = [];
264  // Find files by the given search demand
265  $files = iterator_to_array($this->folderObject->searchFiles($this->searchDemand));
266  // @todo Currently files, which got deleted in the file system, are still found.
267  // Therefore we have to ask their parent folder if it still contains the file.
268  $files = array_filter($files, static function (FileInterface $file): bool {
269  try {
270  if ($file->getParentFolder()->hasFile($file->getName())) {
271  return true;
272  }
273  } catch (ResourceDoesNotExistException $e) {
274  // Nothing to do, file does not longer exist in folder
275  }
276  return false;
277  });
278 
279  // @todo We have to manually slice the search result, since it may
280  // contain invalid files, which were manually filtered out above.
281  // This should be fixed, so we can use the $firstResult and $maxResults
282  // properties of the search demand directly.
283  $this->totalItems = count($files);
284  if (trim($this->sort) !== '') {
285  // Sort the files before applying the pagination
286  $files = $this->‪sortFiles($files);
287  }
288  $filesNum = $this->firstElementNumber + $this->iLimit > $this->totalItems
289  ? $this->totalItems - $this->firstElementNumber
291  $files = array_slice($files, $this->firstElementNumber, $filesNum);
292 
293  // Add special "Path" field for the search result
294  array_splice($this->fieldArray, 3, 0, '_PATH_');
295  } else {
296  // @todo use folder methods directly when they support filters
297  $storage = $this->folderObject->getStorage();
298  $storage->resetFileAndFolderNameFiltersToDefault();
299 
300  // Only render the contents of a browsable storage
301  if (!$this->folderObject->getStorage()->isBrowsable()) {
302  return '';
303  }
304  try {
305  $foldersCount = $storage->countFoldersInFolder($this->folderObject);
306  $filesCount = $storage->countFilesInFolder($this->folderObject);
307  } catch (InsufficientFolderAccessPermissionsException $e) {
308  $foldersCount = 0;
309  $filesCount = 0;
310  }
311 
312  if ($foldersCount <= $this->firstElementNumber) {
313  $foldersFrom = false;
314  $foldersNum = false;
315  } else {
316  $foldersFrom = ‪$this->firstElementNumber;
317  if ($this->firstElementNumber + $this->iLimit > $foldersCount) {
318  $foldersNum = $foldersCount - ‪$this->firstElementNumber;
319  } else {
320  $foldersNum = ‪$this->iLimit;
321  }
322  }
323  if ($foldersCount >= $this->firstElementNumber + $this->iLimit) {
324  $filesFrom = false;
325  $filesNum = false;
326  } elseif ($this->firstElementNumber <= $foldersCount) {
327  $filesFrom = 0;
328  $filesNum = $this->iLimit - $foldersNum;
329  } else {
330  $filesFrom = $this->firstElementNumber - $foldersCount;
331  if ($filesFrom + $this->iLimit > $filesCount) {
332  $filesNum = $filesCount - $filesFrom;
333  } else {
334  $filesNum = ‪$this->iLimit;
335  }
336  }
337 
338  // Initialize files and folders
339  $files = [];
340  $folders = [];
341 
342  if (trim($this->sort) !== '') {
343  // Note: In case sorting is requested, this can not be done by the driver because
344  // the sorting field might be a metadata field, which is not known to the
345  // driver (see #97443). This therefore requires to fetch all files and folders
346  // first. They are then sorted and sliced to respect the current pagination.
347  if ($foldersNum) {
348  // Only perform find/sort/slice in case at least one folder is available
349  $folders = $this->‪sortFolders($storage->getFoldersInFolder($this->folderObject));
350  $folders = array_slice($folders, $foldersFrom, $foldersNum);
351  }
352  if ($filesNum) {
353  // Only perform find/sort/slice in case at least one file is available
354  $files = $this->‪sortFiles($this->folderObject->getFiles());
355  $files = array_slice($files, $filesFrom, $filesNum);
356  }
357  } else {
358  $folders = $storage->getFoldersInFolder($this->folderObject, $foldersFrom, $foldersNum);
359  $files = $this->folderObject->getFiles($filesFrom, $filesNum, ‪Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, false);
360  }
361 
362  $this->totalItems = $foldersCount + $filesCount;
363  }
364 
365  $iOut = '';
366  // Directories are added
367  $iOut .= $this->‪fwd_rwd_nav($this->firstElementNumber);
368 
369  $iOut .= $this->‪formatDirList($folders);
370  // Files are added
371  $iOut .= $this->‪formatFileList($files);
372 
373  $amountOfItemsShownOnCurrentPage = $this->firstElementNumber + $this->iLimit < $this->totalItems
374  ? $this->firstElementNumber + $this->iLimit
375  : -1;
376  $iOut .= $this->‪fwd_rwd_nav($amountOfItemsShownOnCurrentPage);
377 
378  // Header line is drawn
379  $theData = [];
380  foreach ($this->fieldArray as $fieldName) {
381  if ($fieldName === '_SELECTOR_') {
382  $theData[$fieldName] = $this->‪renderCheckboxActions();
383  } elseif ($fieldName === '_CONTROL_') {
384  // Special case: The control column header should not be wrapped into a sort link
385  $theData[$fieldName] = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels._CONTROL_');
386  } elseif ($specialLabel = $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.' . $fieldName)) {
387  $theData[$fieldName] = $this->‪linkWrapSort($fieldName, $specialLabel);
388  } elseif ($customLabel = $this->‪getLanguageService()->getLL('c_' . $fieldName)) {
389  $theData[$fieldName] = $this->‪linkWrapSort($fieldName, $customLabel);
390  } elseif ($fieldName !== 'icon') {
391  // Normal database field
392  $theData[$fieldName] = $this->‪linkWrapSort($fieldName);
393  }
394  }
395 
396  return '
397  <div class="table-fit mb-4">
398  <table class="table table-striped table-hover" id="typo3-filelist">
399  <thead>' . $this->‪addElement($theData, [], true) . '</thead>
400  <tbody data-multi-record-selection-row-selection="true">' . $iOut . '</tbody>
401  </table>
402  </div>';
403  }
404 
415  public function ‪addElement(array $data, array $attributes = [], bool $isTableHeader = false): string
416  {
417  // Initialize rendering.
418  $cols = [];
419  $colType = $isTableHeader ? 'th' : 'td';
420  $colspan = '';
421  $colspanCounter = 0;
422  $lastField = '';
423  // Traverse field array which contains the data to present:
424  foreach ($this->fieldArray as $fieldName) {
425  if (isset($data[$fieldName])) {
426  if ($lastField && isset($data[$lastField])) {
427  $cssClass = $this->addElement_tdCssClass[$lastField] ?? '';
428  $cols[] = '<' . $colType . ' class="' . $cssClass . '"' . $colspan . '>' . $data[$lastField] . '</' . $colType . '>';
429  }
430  $lastField = $fieldName;
431  $colspanCounter = 1;
432  } else {
433  if (!$lastField) {
434  $lastField = $fieldName;
435  }
436  $colspanCounter++;
437  }
438  $colspan = ($colspanCounter > 1) ? ' colspan="' . $colspanCounter . '"' : '';
439  }
440  if ($lastField) {
441  $cssClass = $this->addElement_tdCssClass[$lastField] ?? '';
442  $cols[] = '<' . $colType . ' class="' . $cssClass . '"' . $colspan . '>' . $data[$lastField] . '</' . $colType . '>';
443  }
444 
445  // Add the the table row
446  return '
447  <tr ' . GeneralUtility::implodeAttributes($attributes, true) . '>
448  ' . implode(PHP_EOL, $cols) . '
449  </tr>';
450  }
451 
457  public function ‪fwd_rwd_nav(int $currentItemCount): string
458  {
459  $code = '';
460  if ($currentItemCount >= $this->firstElementNumber && $currentItemCount < $this->firstElementNumber + $this->iLimit) {
461  if ($this->firstElementNumber && $currentItemCount == $this->firstElementNumber) {
462  // Reverse
463  $theData = [];
464  $href = $this->‪listURL(['pointer' => ($currentItemCount - $this->iLimit)]);
465  $theData['_SELECTOR_'] = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory->getIcon(
466  'actions-move-up',
468  )->render() . ' <i>[' . (max(0, $currentItemCount - $this->iLimit) + 1) . ' - ' . $currentItemCount . ']</i></a>';
469  $code = $this->‪addElement($theData);
470  }
471  return $code;
472  }
473  if ($currentItemCount === $this->firstElementNumber + $this->iLimit) {
474  // Forward
475  $theData = [];
476  $href = $this->‪listURL(['pointer' => $currentItemCount]);
477  $theData['_SELECTOR_'] = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory->getIcon(
478  'actions-move-down',
480  )->render() . ' <i>[' . ($currentItemCount + 1) . ' - ' . $this->totalItems . ']</i></a>';
481  $code = $this->‪addElement($theData);
482  }
483  return $code;
484  }
485 
491  public function ‪getFolderInfo()
492  {
493  if ($this->counter == 1) {
494  $fileLabel = htmlspecialchars($this->‪getLanguageService()->getLL('file'));
495  } else {
496  $fileLabel = htmlspecialchars($this->‪getLanguageService()->getLL('files'));
497  }
498  return $this->counter . ' ' . $fileLabel . ', ' . GeneralUtility::formatSize($this->totalbytes, htmlspecialchars($this->‪getLanguageService()->getLL('byteSizeUnits')));
499  }
500 
507  public function ‪formatDirList(array $folders)
508  {
509  $out = '';
510  foreach (ListUtility::resolveSpecialFolderNames($folders) as $folderName => ‪$folderObject) {
511  $role = ‪$folderObject->‪getRole();
512  if ($role === ‪FolderInterface::ROLE_PROCESSING) {
513  // don't show processing-folder
514  continue;
515  }
516  if ($role !== ‪FolderInterface::ROLE_DEFAULT) {
517  $displayName = '<strong>' . htmlspecialchars($folderName) . '</strong>';
518  } else {
519  $displayName = htmlspecialchars($folderName);
520  }
521 
522  $isLocked = ‪$folderObject instanceof InaccessibleFolder;
523  $isWritable = ‪$folderObject->‪checkActionPermission('write');
524 
525  // Initialization
526  $this->counter++;
527 
528  // The icon - will be linked later on, if not locked
529  $theIcon = $this->‪getFileOrFolderIcon($folderName, ‪$folderObject);
530 
531  // Preparing and getting the data-array
532  $theData = [];
533 
534  // Preparing table row attributes
535  $attributes = [
536  'data-type' => 'folder',
537  'data-folder-identifier' => ‪$folderObject->‪getIdentifier(),
538  'data-combined-identifier' => ‪$folderObject->‪getCombinedIdentifier(),
539  ];
540  if ($isLocked) {
541  foreach ($this->fieldArray as $field) {
542  $theData[$field] = '';
543  }
544  $theData['icon'] = $theIcon;
545  $theData['name'] = $displayName;
546  } else {
547  foreach ($this->fieldArray as $field) {
548  switch ($field) {
549  case 'size':
550  try {
551  $numFiles = ‪$folderObject->‪getFileCount();
552  } catch (InsufficientFolderAccessPermissionsException $e) {
553  $numFiles = 0;
554  }
555  $theData[$field] = $numFiles . ' ' . htmlspecialchars($this->‪getLanguageService()->getLL(($numFiles === 1 ? 'file' : 'files')));
556  break;
557  case 'rw':
558  $theData[$field] = '<strong class="text-danger">' . htmlspecialchars($this->‪getLanguageService()->getLL('read')) . '</strong>' . (!$isWritable ? '' : '<strong class="text-danger">' . htmlspecialchars($this->‪getLanguageService()->getLL('write')) . '</strong>');
559  break;
560  case 'record_type':
561  $theData[$field] = htmlspecialchars($this->‪getLanguageService()->getLL('folder'));
562  break;
563  case 'icon':
564  $theData[$field] = (string)BackendUtility::wrapClickMenuOnIcon($theIcon, 'sys_file', ‪$folderObject->‪getCombinedIdentifier());
565  break;
566  case 'name':
567  $theData[$field] = $this->‪linkWrapDir($displayName, ‪$folderObject);
568  break;
569  case '_CONTROL_':
570  $theData[$field] = $this->‪makeEdit($folderObject);
571  break;
572  case '_SELECTOR_':
573  $theData[$field] = $this->‪makeCheckbox($folderObject);
574  break;
575  case '_REF_':
576  $theData[$field] = '-';
577  break;
578  case '_PATH_':
579  $theData[$field] = $this->‪makePath($folderObject);
580  break;
581  default:
582  $theData[$field] = GeneralUtility::fixed_lgd_cs($theData[$field] ?? '', $this->fixedL);
583  }
584  }
585  }
586  $out .= $this->‪addElement($theData, $attributes);
587  }
588  return $out;
589  }
590 
598  public function ‪linkWrapDir($title, Folder ‪$folderObject)
599  {
600  $href = $this->‪listURL(['id' => $folderObject->getCombinedIdentifier(), 'searchTerm' => '', 'pointer' => 0]);
601  // Sometimes $code contains plain HTML tags. In such a case the string should not be modified!
602  if ((string)$title === strip_tags($title)) {
603  return '<a href="' . htmlspecialchars($href) . '" title="' . htmlspecialchars($title) . '">' . $title . '</a>';
604  }
605  return '<a href="' . htmlspecialchars($href) . '">' . $title . '</a>';
606  }
607 
615  public function ‪linkWrapFile($code, File $fileObject)
616  {
617  try {
618  if ($this->‪isEditMetadataAllowed($fileObject)
619  && ($metaDataUid = $fileObject->getMetaData()->offsetGet('uid'))
620  ) {
621  $urlParameters = [
622  'edit' => [
623  'sys_file_metadata' => [
624  $metaDataUid => 'edit',
625  ],
626  ],
627  'returnUrl' => $this->‪listURL(),
628  ];
629  $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
630  $title = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.editMetadata'));
631  $code = '<a class="responsive-title" href="' . htmlspecialchars($url) . '" title="' . $title . '">' . $code . '</a>';
632  }
633  } catch (\Exception $e) {
634  // intentional fall-through
635  }
636  return $code;
637  }
638 
644  public function ‪listURL(array $params = []): string
645  {
646  $params = array_replace_recursive([
647  'pointer' => $this->firstElementNumber,
648  'id' => $this->folderObject->getCombinedIdentifier(),
649  'searchTerm' => $this->searchDemand ? $this->searchDemand->getSearchTerm() : '',
650  ], $params);
651  $params = array_filter($params);
652  return (string)$this->uriBuilder->buildUriFromRoute('file_FilelistList', $params);
653  }
654 
661  public function ‪formatFileList(array $files)
662  {
663  $out = '';
664  foreach ($files as $fileObject) {
665  // Initialization
666  $this->counter++;
667  $this->totalbytes += $fileObject->getSize();
668  $ext = $fileObject->getExtension();
669  $fileUid = $fileObject->getUid();
670  $fileName = trim($fileObject->getName());
671  // Preparing and getting the data-array
672  $theData = [];
673  // Preparing table row attributes
674  $attributes = [
675  'data-type' => 'file',
676  'data-file-uid' => $fileUid,
677  ];
678  if ($this->‪isEditMetadataAllowed($fileObject)
679  && ($metaDataUid = $fileObject->getMetaData()->offsetGet('uid'))
680  ) {
681  $attributes['data-metadata-uid'] = (string)$metaDataUid;
682  }
683  foreach ($this->fieldArray as $field) {
684  switch ($field) {
685  case 'size':
686  $theData[$field] = GeneralUtility::formatSize((int)$fileObject->getSize(), htmlspecialchars($this->‪getLanguageService()->getLL('byteSizeUnits')));
687  break;
688  case 'rw':
689  $theData[$field] = '' . (!$fileObject->checkActionPermission('read') ? ' ' : '<strong class="text-danger">' . htmlspecialchars($this->‪getLanguageService()->getLL('read')) . '</strong>') . (!$fileObject->checkActionPermission('write') ? '' : '<strong class="text-danger">' . htmlspecialchars($this->‪getLanguageService()->getLL('write')) . '</strong>');
690  break;
691  case 'record_type':
692  $theData[$field] = htmlspecialchars($this->‪getLanguageService()->getLL('file') . ($ext ? ' (' . strtoupper($ext) . ')' : ''));
693  break;
694  case '_CONTROL_':
695  $theData[$field] = $this->‪makeEdit($fileObject);
696  break;
697  case '_SELECTOR_':
698  $theData[$field] = $this->‪makeCheckbox($fileObject);
699  break;
700  case '_REF_':
701  $theData[$field] = $this->‪makeRef($fileObject);
702  break;
703  case '_PATH_':
704  $theData[$field] = $this->‪makePath($fileObject);
705  break;
706  case 'icon':
707  $theData[$field] = (string)BackendUtility::wrapClickMenuOnIcon($this->‪getFileOrFolderIcon($fileName, $fileObject), 'sys_file', $fileObject->getCombinedIdentifier());
708  break;
709  case 'name':
710  // Edit metadata of file
711  $theData[$field] = $this->‪linkWrapFile(htmlspecialchars($fileName), $fileObject);
712 
713  if ($fileObject->isMissing()) {
714  $theData[$field] .= '<span class="label label-danger label-space-left">'
715  . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_missing'))
716  . '</span>';
717  // Thumbnails?
718  } elseif ($this->thumbs && ($fileObject->isImage() || $fileObject->isMediaFile())) {
719  $processedFile = $fileObject->process(
721  [
722  'width' => (int)($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['thumbnail.']['width'] ?? 64),
723  'height' => (int)($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['thumbnail.']['height'] ?? 64),
724  ]
725  );
726  $theData[$field] .= '<br /><img src="' . htmlspecialchars($processedFile->getPublicUrl() ?? '') . '" ' .
727  'width="' . htmlspecialchars($processedFile->getProperty('width')) . '" ' .
728  'height="' . htmlspecialchars($processedFile->getProperty('height')) . '" ' .
729  'title="' . htmlspecialchars($fileName) . '" alt="" />';
730  }
731  break;
732  case 'crdate':
733  $crdate = $fileObject->getCreationTime();
734  $theData[$field] = $crdate ? BackendUtility::datetime($crdate) : '-';
735  break;
736  case 'tstamp':
737  $tstamp = $fileObject->getModificationTime();
738  $theData[$field] = $tstamp ? BackendUtility::datetime($tstamp) : '-';
739  break;
740  default:
741  $theData[$field] = '';
742  if ($fileObject->hasProperty($field)) {
743  $concreteTableName = $this->‪getConcreteTableName($field);
744  if ($field === (‪$GLOBALS['TCA'][$concreteTableName]['ctrl']['cruser_id'] ?? '')) {
745  // Handle cruser_id by adding the avatar along with the username
746  $theData[$field] = $this->‪getBackendUserInformation((int)$fileObject->getProperty($field));
747  } elseif ($field === 'storage') {
748  // Fetch storage name of the current file
749  $storage = GeneralUtility::makeInstance(StorageRepository::class)->findByUid((int)$fileObject->getProperty($field));
750  if ($storage !== null) {
751  $theData[$field] = htmlspecialchars($storage->getName());
752  }
753  } else {
754  $theData[$field] = htmlspecialchars(
755  (string)BackendUtility::getProcessedValueExtra(
756  $this->‪getConcreteTableName($field),
757  $field,
758  $fileObject->getProperty($field),
759  $this->fixedL,
760  $fileObject->getMetaData()->offsetGet('uid')
761  )
762  );
763  }
764  }
765  }
766  }
767  $out .= $this->‪addElement($theData, $attributes);
768  }
769  return $out;
770  }
771 
778  protected function getTranslationsForMetaData($metaDataRecord)
779  {
780  $languageField = ‪$GLOBALS['TCA']['sys_file_metadata']['ctrl']['languageField'] ?? '';
781  $languageParentField = ‪$GLOBALS['TCA']['sys_file_metadata']['ctrl']['transOrigPointerField'] ?? '';
782 
783  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file_metadata');
784  $queryBuilder->getRestrictions()->removeAll();
785  ‪$translationRecords = $queryBuilder->select('*')
786  ->from('sys_file_metadata')
787  ->where(
788  $queryBuilder->expr()->eq(
789  $languageParentField,
790  $queryBuilder->createNamedParameter($metaDataRecord['uid'] ?? 0, ‪Connection::PARAM_INT)
791  ),
792  $queryBuilder->expr()->gt(
793  $languageField,
794  $queryBuilder->createNamedParameter(0, ‪Connection::PARAM_INT)
795  )
796  )
797  ->executeQuery()
798  ->fetchAllAssociative();
799 
800  ‪$translations = [];
801  foreach (‪$translationRecords as $record) {
802  $languageId = $record[$languageField];
803  ‪$translations[$languageId] = $record;
804  }
805  return ‪$translations;
806  }
807 
815  public function ‪linkWrapSort(string $fieldName, string $label = ''): string
816  {
817  // Determine label if not given
818  if ($label === '') {
819  $lang = $this->‪getLanguageService();
820  $concreteTableName = $this->‪getConcreteTableName($fieldName);
821  $label = $lang->sL(BackendUtility::getItemLabel($concreteTableName, $fieldName) ?? '');
822  if ($label !== '') {
823  // In case global TSconfig exists we have to check if the label is overridden there
824  $tsConfig = BackendUtility::getPagesTSconfig(0);
825  if (!empty($tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['label.'][$lang->lang])) {
826  $label = $tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['label.'][$lang->lang];
827  } elseif (!empty($tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['label'])) {
828  $label = $tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['label'];
829  }
830  }
831  }
832 
833  $params = ['SET' => ['sort' => $fieldName], 'pointer' => 0];
834 
835  if ($this->sort === $fieldName) {
836  // Check reverse sorting
837  $params['SET']['reverse'] = ($this->sortRev ? '0' : '1');
838  $sortArrow = $this->iconFactory->getIcon('status-status-sorting-' . ($this->sortRev ? 'desc' : 'asc'), ‪Icon::SIZE_SMALL)->render();
839  } else {
840  $params['SET']['reverse'] = 0;
841  $sortArrow = '';
842  }
843  $href = $this->‪listURL($params);
844 
845  return '<a href="' . htmlspecialchars($href) . '">' . htmlspecialchars($label) . ' ' . $sortArrow . '</a>';
846  }
847 
854  public function ‪makeClip($fileOrFolderObject): array
855  {
856  if (!$fileOrFolderObject->checkActionPermission('read')) {
857  return [];
858  }
859  $actions = [];
860  $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
861  $fullName = $fileOrFolderObject->getName();
862  $md5 = md5($fullIdentifier);
863 
864  // Add copy/cut buttons in "normal" mode:
865  if ($this->clipObj->current === 'normal') {
866  $isSel = $this->clipObj->isSelected('_FILE', $md5);
867 
868  if ($fileOrFolderObject->checkActionPermission('copy')) {
869  $copyTitle = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.' . ($isSel === 'copy' ? 'copyrelease' : 'copy'));
870  $copyUrl = $this->clipObj->selUrlFile($fullIdentifier, true, $isSel === 'copy');
871  $actions['copy'] = '
872  <a class="btn btn-default" href="' . htmlspecialchars($copyUrl) . '" title="' . htmlspecialchars($copyTitle) . '">
873  ' . $this->iconFactory->getIcon($isSel === 'copy' ? 'actions-edit-copy-release' : 'actions-edit-copy', ‪Icon::SIZE_SMALL)->render() . '
874  </a>';
875  }
876 
877  if ($fileOrFolderObject->checkActionPermission('move')) {
878  $cutTitle = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.' . ($isSel === 'cut' ? 'cutrelease' : 'cut'));
879  $cutUrl = $this->clipObj->selUrlFile($fullIdentifier, false, $isSel === 'cut');
880  $actions['cut'] = '
881  <a class="btn btn-default" href="' . htmlspecialchars($cutUrl) . '" title="' . htmlspecialchars($cutTitle) . '">
882  ' . $this->iconFactory->getIcon($isSel === 'cut' ? 'actions-edit-cut-release' : 'actions-edit-cut', ‪Icon::SIZE_SMALL)->render() . '
883  </a>';
884  }
885  }
886 
887  $elFromTable = $this->clipObj->elFromTable('_FILE');
888  $addPasteButton = $this->folderObject->checkActionPermission(
889  ($this->clipObj->clipData[$this->clipObj->current]['mode'] ?? '') === 'copy' ? 'copy' : 'move'
890  );
891  if (!$fileOrFolderObject instanceof Folder
892  || $elFromTable === []
893  || !$addPasteButton
894  || !$fileOrFolderObject->checkActionPermission('write')
895  ) {
896  //early return actions, in case paste should not be displayed
897  return $actions;
898  }
899 
900  $elToConfirm = [];
901  foreach ($elFromTable as $key => $element) {
902  $clipBoardElement = $this->resourceFactory->retrieveFileOrFolderObject($element);
903  if ($clipBoardElement instanceof Folder
904  && $clipBoardElement->getStorage()->isWithinFolder($clipBoardElement, $fileOrFolderObject)
905  ) {
906  // In case folder is already present in the target folder, return actions without paste button
907  return $actions;
908  }
909  $elToConfirm[$key] = $clipBoardElement->getName();
910  }
911 
912  $pasteUrl = $this->clipObj->pasteUrl('_FILE', $fullIdentifier);
913  $pasteTitle = $this->‪getLanguageService()->‪getLL('clip_pasteInto');
914  $pasteContent = $this->clipObj->confirmMsgText('_FILE', $fullName, 'into', $elToConfirm);
915  $actions[] = '
916  <a class="btn btn-default t3js-modal-trigger" data-severity="warning" href="' . htmlspecialchars($pasteUrl) . '" data-bs-content="' . htmlspecialchars($pasteContent) . '" data-title="' . htmlspecialchars($pasteTitle) . '" title="' . htmlspecialchars($pasteTitle) . '">
917  ' . $this->iconFactory->getIcon('actions-document-paste-into', ‪Icon::SIZE_SMALL)->render() . '
918  </a>';
919 
920  return $actions;
921  }
922 
929  protected function ‪makeCheckbox($fileOrFolderObject): string
930  {
931  if (!$fileOrFolderObject->checkActionPermission('read')) {
932  return '';
933  }
934 
935  $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
936  $md5 = md5($fullIdentifier);
937  $identifier = '_FILE|' . $md5;
938  $this->CBnames[] = $identifier;
939 
940  return '
941  <span class="form-check form-toggle">
942  <input class="form-check-input t3js-multi-record-selection-check" type="checkbox" name="CBC[' . $identifier . ']" value="' . htmlspecialchars($fullIdentifier) . '"/>
943  </span>';
944  }
945 
952  public function ‪makeEdit($fileOrFolderObject)
953  {
954  $cells = [];
955  $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
956 
957  // Edit file content (if editable)
958  if ($fileOrFolderObject instanceof File && $fileOrFolderObject->checkActionPermission('write') && $fileOrFolderObject->isTextFile()) {
959  $attributes = [
960  'href' => (string)$this->uriBuilder->buildUriFromRoute('file_edit', ['target' => $fullIdentifier, 'returnUrl' => $this->listURL()]),
961  'title' => $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.editcontent'),
962  ];
963  $cells['edit'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>'
964  . $this->iconFactory->getIcon('actions-page-open', ‪Icon::SIZE_SMALL)->render()
965  . '</a>';
966  } else {
967  $cells['edit'] = ‪$this->spaceIcon;
968  }
969 
970  // Edit metadata of file
971  if ($fileOrFolderObject instanceof File
972  && $this->‪isEditMetadataAllowed($fileOrFolderObject)
973  && ($metaDataUid = $fileOrFolderObject->getMetaData()->offsetGet('uid'))
974  ) {
975  $urlParameters = [
976  'edit' => [
977  'sys_file_metadata' => [
978  $metaDataUid => 'edit',
979  ],
980  ],
981  'returnUrl' => $this->‪listURL(),
982  ];
983  $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
984  $title = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.editMetadata'));
985  $cells['metadata'] = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . $title . '">' . $this->iconFactory->getIcon('actions-open', ‪Icon::SIZE_SMALL)->render() . '</a>';
986  }
987 
988  // Get translation actions
989  if ($fileOrFolderObject instanceof File && (‪$translations = $this->‪makeTranslations($fileOrFolderObject))) {
990  $cells['translations'] = ‪$translations;
991  }
992 
993  // document view
994  if ($fileOrFolderObject instanceof File) {
995  $fileUrl = $fileOrFolderObject->getPublicUrl();
996  if ($fileUrl) {
997  $cells['view'] = '<a href="' . htmlspecialchars($fileUrl) . '" target="_blank" class="btn btn-default" title="' . $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.view') . '">' . $this->iconFactory->getIcon('actions-document-view', ‪Icon::SIZE_SMALL)->render() . '</a>';
998  } else {
999  $cells['view'] = ‪$this->spaceIcon;
1000  }
1001  } else {
1002  $cells['view'] = ‪$this->spaceIcon;
1003  }
1004 
1005  // replace file
1006  if ($fileOrFolderObject instanceof File && $fileOrFolderObject->checkActionPermission('replace')) {
1007  $attributes = [
1008  'href' => (string)$this->uriBuilder->buildUriFromRoute('file_replace', ['target' => $fullIdentifier, 'uid' => $fileOrFolderObject->getUid(), 'returnUrl' => $this->‪listURL()]),
1009  'title' => $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.replace'),
1010  ];
1011  $cells['replace'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-edit-replace', ‪Icon::SIZE_SMALL)->render() . '</a>';
1012  }
1013 
1014  // rename the file
1015  if ($fileOrFolderObject->checkActionPermission('rename')) {
1016  $attributes = [
1017  'href' => (string)$this->uriBuilder->buildUriFromRoute('file_rename', ['target' => $fullIdentifier, 'returnUrl' => $this->listURL()]),
1018  'title' => $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.rename'),
1019  ];
1020  $cells['rename'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-edit-rename', ‪Icon::SIZE_SMALL)->render() . '</a>';
1021  } else {
1022  $cells['rename'] = ‪$this->spaceIcon;
1023  }
1024 
1025  // file download
1026  if ($fileOrFolderObject->checkActionPermission('read') && $this->fileDownloadEnabled()) {
1027  if ($fileOrFolderObject instanceof File
1028  && ($this->fileExtensionFilter === null || $this->fileExtensionFilter->isAllowed($fileOrFolderObject->getExtension()))
1029  ) {
1030  $fileUrl = $fileOrFolderObject->getPublicUrl();
1031  if ($fileUrl) {
1032  $cells['download'] = '<a href="' . htmlspecialchars($fileUrl) . '" download="' . htmlspecialchars($fileOrFolderObject->getName()) . '" class="btn btn-default" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:download')) . '">' . $this->iconFactory->getIcon('actions-download', ‪Icon::SIZE_SMALL)->render() . '</a>';
1033  }
1034  // Folder download
1035  } elseif ($fileOrFolderObject instanceof Folder) {
1036  $cells['download'] = '<button type="button" data-folder-download="' . htmlspecialchars($this->uriBuilder->buildUriFromRoute('file_download')) . '" data-folder-identifier="' . htmlspecialchars($fileOrFolderObject->getCombinedIdentifier()) . '" class="btn btn-default" title="' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:download')) . '">' . $this->iconFactory->getIcon('actions-download', ‪Icon::SIZE_SMALL)->render() . '</button>';
1037  }
1038  }
1039 
1040  // upload files
1041  if ($fileOrFolderObject->getStorage()->checkUserActionPermission('add', 'File') && $fileOrFolderObject->checkActionPermission('write')) {
1042  if ($fileOrFolderObject instanceof Folder) {
1043  $attributes = [
1044  'href' => (string)$this->uriBuilder->buildUriFromRoute('file_upload', ['target' => $fullIdentifier, 'returnUrl' => $this->listURL()]),
1045  'title' => $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload'),
1046  ];
1047  $cells['upload'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-edit-upload', ‪Icon::SIZE_SMALL)->render() . '</a>';
1048  }
1049  }
1050 
1051  if ($fileOrFolderObject->checkActionPermission('read')) {
1052  $attributes = [
1053  'title' => $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.info'),
1054  ];
1055  if ($fileOrFolderObject instanceof Folder || $fileOrFolderObject instanceof File) {
1056  $attributes['data-filelist-show-item-type'] = $fileOrFolderObject instanceof File ? '_FILE' : '_FOLDER';
1057  $attributes['data-filelist-show-item-identifier'] = $fullIdentifier;
1058  }
1059  $cells['info'] = '<a href="#" class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>'
1060  . $this->iconFactory->getIcon('actions-document-info', ‪Icon::SIZE_SMALL)->render() . '</a>';
1061  } else {
1062  $cells['info'] = ‪$this->spaceIcon;
1063  }
1064 
1065  // delete the file
1066  if ($fileOrFolderObject->checkActionPermission('delete')) {
1067  $identifier = $fileOrFolderObject->getIdentifier();
1068  if ($fileOrFolderObject instanceof Folder) {
1069  $referenceCountText = BackendUtility::referenceCount('_FILE', $identifier, ' ' . $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.referencesToFolder'));
1070  $deleteType = 'delete_folder';
1071  } else {
1072  $referenceCountText = BackendUtility::referenceCount('sys_file', (string)$fileOrFolderObject->getUid(), ' ' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.referencesToFile'));
1073  $deleteType = 'delete_file';
1074  }
1075 
1076  if ($this->‪getBackendUser()->jsConfirmation(‪JsConfirmation::DELETE)) {
1077  $confirmationCheck = '1';
1078  } else {
1079  $confirmationCheck = '0';
1080  }
1081 
1082  $deleteUrl = (string)$this->uriBuilder->buildUriFromRoute('tce_file');
1083  $confirmationMessage = sprintf($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:mess.delete'), $fileOrFolderObject->getName()) . $referenceCountText;
1084  $title = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.delete');
1085  $cells['delete'] = '<a href="#" class="btn btn-default t3js-filelist-delete" data-bs-content="' . htmlspecialchars($confirmationMessage)
1086  . '" data-check="' . $confirmationCheck
1087  . '" data-delete-url="' . htmlspecialchars($deleteUrl)
1088  . '" data-title="' . htmlspecialchars($title)
1089  . '" data-identifier="' . htmlspecialchars($fileOrFolderObject->getCombinedIdentifier())
1090  . '" data-delete-type="' . $deleteType
1091  . '" title="' . htmlspecialchars($title) . '">'
1092  . $this->iconFactory->getIcon('actions-edit-delete', ‪Icon::SIZE_SMALL)->render() . '</a>';
1093  } else {
1094  $cells['delete'] = ‪$this->spaceIcon;
1095  }
1096 
1097  // Hook for manipulating edit icons.
1098  // @deprecated will be removed in TYPO3 v12.0.
1099  $cells['__fileOrFolderObject'] = $fileOrFolderObject;
1100  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fileList']['editIconsHook'] ?? [] as $className) {
1101  $hookObject = GeneralUtility::makeInstance($className);
1102  if (!$hookObject instanceof FileListEditIconHookInterface) {
1103  throw new \UnexpectedValueException(
1104  $className . ' must implement interface ' . FileListEditIconHookInterface::class,
1105  1235225797
1106  );
1107  }
1108  $hookObject->manipulateEditIcons($cells, $this);
1109  }
1110  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fileList']['editIconsHook'])) {
1111  trigger_error('Using the hook $TYPO3_CONF_VARS[SC_OPTIONS][fileList][editIconsHook] will not work in TYPO3 v12.0 anymore. Use the PSR-14 based ProcessFileListActionsEvent instead.', E_USER_DEPRECATED);
1112  }
1113 
1114  unset($cells['__fileOrFolderObject']);
1115 
1116  // Get clipboard actions
1117  $clipboardActions = $this->‪makeClip($fileOrFolderObject);
1118  if ($clipboardActions !== []) {
1119  // Add divider in case at least one clipboard action is displayed
1120  $cells['divider'] = '<hr class="dropdown-divider me-0 ms-0 border-white">';
1121  }
1122  // Merge the clipboard actions into the existing cells
1123  $cells = array_merge($cells, $clipboardActions);
1124 
1125  $event = new ProcessFileListActionsEvent($fileOrFolderObject, $cells);
1126  $event = $this->eventDispatcher->dispatch($event);
1127  $cells = $event->getActionItems();
1128 
1129  // Compile items into a dropdown
1130  $cellOutput = '';
1131  ‪$output = '';
1132  foreach ($cells as $key => $action) {
1133  if (in_array($key, ['view', 'metadata', 'translations', 'delete'])) {
1134  ‪$output .= $action;
1135  continue;
1136  }
1137  if ($action === $this->spaceIcon || $action === null) {
1138  continue;
1139  }
1140  // This is a backwards-compat layer for the existing hook items, which will be removed in TYPO3 v12.
1141  $action = str_replace('btn btn-default', 'dropdown-item', $action);
1142  $title = [];
1143  preg_match('/title="([^"]*)"/', $action, $title);
1144  if (empty($title)) {
1145  preg_match('/aria-label="([^"]*)"/', $action, $title);
1146  }
1147  if (!empty($title[1])) {
1148  $action = str_replace(
1149  [
1150  '</a>',
1151  '</button>', ],
1152  [
1153  ' ' . $title[1] . '</a>',
1154  ' ' . $title[1] . '</button>',
1155  ],
1156  $action
1157  );
1158  // In case we added the title as tag content, we can remove the attribute,
1159  // since this is duplicated and would trigger a tooltip with the same content.
1160  if (!empty($title[0])) {
1161  $action = str_replace($title[0], '', $action);
1162  }
1163  }
1164  $cellOutput .= '<li>' . $action . '</li>';
1165  }
1166 
1167  if ($cellOutput !== '') {
1168  $icon = $this->iconFactory->getIcon('actions-menu-alternative', ‪Icon::SIZE_SMALL);
1169  $title = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.more');
1170  ‪$output .= '<div class="btn-group dropdown position-static" data-bs-toggle="tooltip" title="' . htmlspecialchars($title) . '" >' .
1171  '<a href="#actions_' . $fileOrFolderObject->getHashedIdentifier() . '" class="btn btn-default dropdown-toggle dropdown-toggle-no-chevron" data-bs-toggle="dropdown" data-bs-boundary="window" aria-expanded="false">' . $icon->render() . '</a>' .
1172  '<ul id="actions_' . $fileOrFolderObject->getHashedIdentifier() . '" class="dropdown-menu dropdown-list">' . $cellOutput . '</ul>' .
1173  '</div>';
1174  } else {
1176  }
1177 
1178  return '<div class="btn-group position-static">' . ‪$output . '</div>';
1179  }
1180 
1185  public function ‪makeRef(File $file): string
1186  {
1187  $referenceCount = $this->‪getFileReferenceCount($file);
1188  if (!$referenceCount) {
1189  return '-';
1190  }
1191 
1192  $attributes = [
1193  'type' => 'button',
1194  'class' => 'btn btn-link p-0',
1195  'data-filelist-show-item-type' => '_FILE',
1196  'data-filelist-show-item-identifier' => $file->getCombinedIdentifier(),
1197  'title' => $this->‪getLanguageService()->‪sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references') . ' (' . $referenceCount . ')',
1198  ];
1199 
1200  return '
1201  <button ' . GeneralUtility::implodeAttributes($attributes, true) . '>
1202  ' . $referenceCount . '
1203  </button>';
1204  }
1205 
1212  protected function ‪makePath(‪ResourceInterface $resource): string
1213  {
1214  $folder = null;
1215  $method = 'getReadablePath';
1216 
1217  if ($resource instanceof ‪FileInterface) {
1218  $folder = $resource->‪getParentFolder();
1219  } elseif ($resource instanceof ‪FolderInterface) {
1220  $folder = $resource;
1221  }
1222 
1223  if ($folder === null || !is_callable([$folder, $method])) {
1224  return '';
1225  }
1226 
1227  return htmlspecialchars($folder->$method());
1228  }
1229 
1239  protected function ‪makeTranslations(File $file): string
1240  {
1241  $backendUser = $this->‪getBackendUser();
1242 
1243  // Fetch all system languages except "default (0)" and "all languages (-1)"
1244  $systemLanguages = array_filter(
1245  $this->translateTools->getSystemLanguages(),
1246  static fn(array $languageRecord): bool => $languageRecord['uid'] > 0 && $backendUser->checkLanguageAccess($languageRecord['uid'])
1247  );
1248 
1249  if ($systemLanguages === []
1250  || !(‪$GLOBALS['TCA']['sys_file_metadata']['ctrl']['languageField'] ?? false)
1251  || !$file->isIndexed()
1252  || !$file->checkActionPermission('editMeta')
1253  || !$backendUser->check('tables_modify', 'sys_file_metadata')
1254  ) {
1255  // Early return in case no system languages exists or metadata
1256  // of this file can not be created / edited by the current user.
1257  return '';
1258  }
1259 
1260  ‪$translations = [];
1261  $metaDataRecord = $file->getMetaData()->get();
1262  $existingTranslations = $this->getTranslationsForMetaData($metaDataRecord);
1263 
1264  foreach ($systemLanguages as $languageId => $language) {
1265  if (!isset($existingTranslations[$languageId]) && !($metaDataRecord['uid'] ?? false)) {
1266  // Skip if neither a translation nor the metadata uid exists
1267  continue;
1268  }
1269 
1270  if (isset($existingTranslations[$languageId])) {
1271  // Set options for edit action of an existing translation
1272  $title = sprintf($this->‪getLanguageService()->getLL('editMetadataForLanguage'), $language['title']);
1273  $actionType = 'edit';
1274  $url = (string)$this->uriBuilder->buildUriFromRoute(
1275  'record_edit',
1276  [
1277  'edit' => [
1278  'sys_file_metadata' => [
1279  $existingTranslations[$languageId]['uid'] => 'edit',
1280  ],
1281  ],
1282  'returnUrl' => $this->listURL(),
1283  ]
1284  );
1285  } else {
1286  // Set options for "create new" action of a new translation
1287  $title = sprintf($this->‪getLanguageService()->getLL('createMetadataForLanguage'), $language['title']);
1288  $actionType = 'new';
1289  $metaDataRecordId = (int)($metaDataRecord['uid'] ?? 0);
1290  $url = BackendUtility::getLinkToDataHandlerAction(
1291  '&cmd[sys_file_metadata][' . $metaDataRecordId . '][localize]=' . $languageId,
1292  (string)$this->uriBuilder->buildUriFromRoute(
1293  'record_edit',
1294  [
1295  'justLocalized' => 'sys_file_metadata:' . $metaDataRecordId . ':' . $languageId,
1296  'returnUrl' => $this->listURL(),
1297  ]
1298  )
1299  );
1300  }
1302  ‪$translations[] = '
1303  <li>
1304  <a href="' . htmlspecialchars($url) . '" class="dropdown-item" title="' . htmlspecialchars($title) . '">
1305  ' . $this->iconFactory->getIcon($language['flagIcon'], ‪Icon::SIZE_SMALL, 'overlay-' . $actionType)->render() . ' ' . htmlspecialchars($title) . '
1306  </a>
1307  </li>';
1308  }
1309 
1310  return ‪$translations !== [] ? '
1311  <div class="btn-group dropdown position-static" data-bs-toggle="tooltip" title="' . htmlspecialchars($this->‪getLanguageService()->getLL('translateMetadata')) . '">
1312  <button class="btn btn-default dropdown-toggle dropdown-toggle-no-chevron" type="button" id="translations_' . $file->getHashedIdentifier() . '" data-bs-toggle="dropdown" data-bs-boundary="window" aria-expanded="false">
1313  ' . $this->iconFactory->getIcon('actions-translate', ‪Icon::SIZE_SMALL)->render() . '
1314  </button>
1315  <ul class="dropdown-menu dropdown-list" aria-labelledby="translations_' . $file->getHashedIdentifier() . '">
1316  ' . implode(LF, ‪$translations) . '
1317  </ul>
1318  </div>' : '';
1319  }
1320 
1321  protected function ‪isEditMetadataAllowed(‪File $file): bool
1322  {
1323  return $file->‪isIndexed()
1324  && $file->‪checkActionPermission('editMeta')
1325  && $this->‪getBackendUser()->‪check('tables_modify', 'sys_file_metadata');
1326  }
1327 
1335  protected function ‪getFileOrFolderIcon(string $title, $fileOrFolderObject): string
1336  {
1337  return '
1338  <span title="' . htmlspecialchars($title) . '">
1339  ' . $this->iconFactory->getIconForResource($fileOrFolderObject, ‪Icon::SIZE_SMALL)->render() . '
1340  </span>';
1341  }
1342 
1348  protected function ‪renderCheckboxActions(): string
1349  {
1350  // Early return in case there are no items
1351  if (!$this->totalItems) {
1352  return '';
1353  }
1354 
1355  $lang = $this->‪getLanguageService();
1356 
1357  $dropdownItems['checkAll'] = '
1358  <li>
1359  <button type="button" class="btn btn-link dropdown-item disabled" data-multi-record-selection-check-action="check-all" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.checkAll')) . '">
1360  ' . $this->iconFactory->getIcon('actions-check-square', ‪Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.checkAll')) . '
1361  </button>
1362  </li>';
1363 
1364  $dropdownItems['checkNone'] = '
1365  <li>
1366  <button type="button" class="btn btn-link dropdown-item disabled" data-multi-record-selection-check-action="check-none" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.uncheckAll')) . '">
1367  ' . $this->iconFactory->getIcon('actions-square', ‪Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.uncheckAll')) . '
1368  </button>
1369  </li>';
1370 
1371  $dropdownItems['toggleSelection'] = '
1372  <li>
1373  <button type="button" class="btn btn-link dropdown-item" data-multi-record-selection-check-action="toggle" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection')) . '">
1374  ' . $this->iconFactory->getIcon('actions-document-select', ‪Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection')) . '
1375  </button>
1376  </li>';
1377 
1378  return '
1379  <div class="btn-group dropdown position-static">
1380  <button type="button" class="btn btn-borderless dropdown-toggle t3js-multi-record-selection-check-actions-toggle" data-bs-toggle="dropdown" data-bs-boundary="window" aria-expanded="false">
1381  ' . $this->iconFactory->getIcon('content-special-div', ‪Icon::SIZE_SMALL) . '
1382  </button>
1383  <ul class="dropdown-menu t3js-multi-record-selection-check-actions">
1384  ' . implode(PHP_EOL, $dropdownItems) . '
1385  </ul>
1386  </div>';
1387  }
1388 
1393  protected function ‪getBackendUserInformation(int $backendUserId): string
1394  {
1395  if (!isset($this->backendUserCache[$backendUserId])) {
1396  $beUserRecord = BackendUtility::getRecord('be_users', $backendUserId);
1397  if (is_array($beUserRecord)) {
1398  $avatar = GeneralUtility::makeInstance(Avatar::class);
1399  $label = htmlspecialchars(BackendUtility::getRecordTitle('be_users', $beUserRecord));
1400  $content = $avatar->render($beUserRecord) . '<strong>' . $label . '</strong>';
1401  } else {
1402  $content = '<strong>&ndash;</strong>';
1403  }
1404  $this->backendUserCache[$backendUserId] = $content;
1405  }
1406  return $this->backendUserCache[$backendUserId];
1407  }
1408 
1416  protected function ‪getConcreteTableName(string $fieldName): string
1417  {
1418  return (‪$GLOBALS['TCA']['sys_file']['columns'][$fieldName] ?? false) ? 'sys_file' : 'sys_file_metadata';
1419  }
1420 
1426  protected function ‪fileDownloadEnabled(): bool
1427  {
1428  return (bool)($this->‪getBackendUser()->‪getTSConfig()['options.']['file_list.']['fileDownload.']['enabled'] ?? true);
1429  }
1430 
1435  protected function ‪sortFiles(array $files): array
1436  {
1437  $sortedFiles = [];
1438  foreach ($files as $file) {
1439  switch ($this->sort) {
1440  case 'fileext':
1441  $sortingKey = $file->getExtension();
1442  break;
1443  case 'size':
1444  $sortingKey = '0' . $file->getSize() . 's';
1445  break;
1446  case 'rw':
1447  $sortingKey = ($file->checkActionPermission('read') ? 'R' : '')
1448  . ($file->checkActionPermission('write') ? 'W' : '');
1449  break;
1450  case '_REF_':
1451  $sortingKey = '0' . $this->‪getFileReferenceCount($file) . 'ref';
1452  break;
1453  case 'tstamp':
1454  $sortingKey = $file->getModificationTime() . 't';
1455  break;
1456  case 'crdate':
1457  $sortingKey = $file->getCreationTime() . 'c';
1458  break;
1459  default:
1460  $sortingKey = $file->hasProperty($this->sort) ? (string)$file->getProperty($this->sort) : '';
1461  }
1462  $i = 0;
1463  while (isset($sortedFiles[$sortingKey . $i])) {
1464  $i++;
1465  }
1466  $sortedFiles[$sortingKey . $i] = $file;
1467  }
1468  uksort($sortedFiles, 'strnatcasecmp');
1469 
1470  if ($this->sortRev) {
1471  $sortedFiles = array_reverse($sortedFiles);
1472  }
1473 
1474  return $sortedFiles;
1475  }
1476 
1481  protected function ‪sortFolders(array $folders): array
1482  {
1483  if (!in_array($this->sort, ['size', 'rw', 'name'], true)) {
1484  // Early return in case the sorting field is not supported on folders.
1485  return $folders;
1486  }
1487 
1488  $sortedFolders = [];
1489  foreach ($folders as $folder) {
1490  switch ($this->sort) {
1491  case 'size':
1492  try {
1493  $fileCount = $folder->getFileCount();
1494  } catch (InsufficientFolderAccessPermissionsException $e) {
1495  $fileCount = 0;
1496  }
1497  $sortingKey = '0' . $fileCount . 's';
1498  break;
1499  case 'rw':
1500  $sortingKey = ($folder->checkActionPermission('read') ? 'R' : '')
1501  . ($folder->checkActionPermission('write') ? 'W' : '');
1502  break;
1503  case 'name':
1504  $sortingKey = $folder->getName();
1505  break;
1506  default:
1507  $sortingKey = '';
1508  }
1509  $i = 0;
1510  while (isset($sortedFolders[$sortingKey . $i])) {
1511  $i++;
1512  }
1513  $sortedFolders[$sortingKey . $i] = $folder;
1514  }
1515  uksort($sortedFolders, 'strnatcasecmp');
1516 
1517  if ($this->sortRev) {
1518  $sortedFolders = array_reverse($sortedFolders);
1519  }
1520 
1521  return $sortedFolders;
1522  }
1523 
1529  protected function ‪getFileReferenceCount(File $file): int
1530  {
1531  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
1532  return (int)$queryBuilder
1533  ->count('*')
1534  ->from('sys_refindex')
1535  ->where(
1536  $queryBuilder->expr()->eq(
1537  'ref_table',
1538  $queryBuilder->createNamedParameter('sys_file')
1539  ),
1540  $queryBuilder->expr()->eq(
1541  'ref_uid',
1542  $queryBuilder->createNamedParameter($file->getUid(), ‪Connection::PARAM_INT)
1543  ),
1544  $queryBuilder->expr()->neq(
1545  'tablename',
1546  $queryBuilder->createNamedParameter('sys_file_metadata')
1547  )
1548  )
1549  ->executeQuery()
1550  ->fetchOne();
1551  }
1552 
1558  protected function ‪getLanguageService()
1559  {
1560  return ‪$GLOBALS['LANG'];
1561  }
1562 
1568  protected function ‪getBackendUser()
1569  {
1570  return ‪$GLOBALS['BE_USER'];
1571  }
1572 }
‪TYPO3\CMS\Filelist\FileList\formatFileList
‪string formatFileList(array $files)
Definition: FileList.php:641
‪TYPO3\CMS\Filelist\FileList\makeRef
‪makeRef(File $file)
Definition: FileList.php:1165
‪TYPO3\CMS\Filelist\FileList\$addElement_tdCssClass
‪array $addElement_tdCssClass
Definition: FileList.php:127
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Filelist\FileList\start
‪start(Folder $folderObject, $pointer, $sort, $sortRev)
Definition: FileList.php:213
‪TYPO3\CMS\Core\Resource\File\getMetaData
‪MetaDataAspect getMetaData()
Definition: File.php:341
‪TYPO3\CMS\Core\Resource\ProcessedFile\CONTEXT_IMAGEPREVIEW
‪const CONTEXT_IMAGEPREVIEW
Definition: ProcessedFile.php:53
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Filelist\FileList\linkWrapSort
‪string linkWrapSort(string $fieldName, string $label='')
Definition: FileList.php:795
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:22
‪TYPO3\CMS\Filelist\FileList\setColumnsToRender
‪setColumnsToRender(array $additionalFields=[])
Definition: FileList.php:226
‪TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
Definition: InsufficientFolderAccessPermissionsException.php:23
‪TYPO3\CMS\Filelist\FileList\$translateTools
‪TranslationConfigurationProvider $translateTools
Definition: FileList.php:121
‪TYPO3\CMS\Filelist\FileList\$spaceIcon
‪string $spaceIcon
Definition: FileList.php:73
‪TYPO3\CMS\Backend\Clipboard\Clipboard
Definition: Clipboard.php:49
‪TYPO3\CMS\Core\Resource\MetaDataAspect\offsetGet
‪mixed offsetGet($offset)
Definition: MetaDataAspect.php:100
‪TYPO3\CMS\Filelist\FileList\$backendUserCache
‪array $backendUserCache
Definition: FileList.php:169
‪TYPO3\CMS\Core\Resource\File\isIndexed
‪bool null isIndexed()
Definition: File.php:150
‪TYPO3\CMS\Filelist\FileList\$searchDemand
‪FileSearchDemand $searchDemand
Definition: FileList.php:162
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Core\Resource\FolderInterface\ROLE_DEFAULT
‪const ROLE_DEFAULT
Definition: FolderInterface.php:26
‪TYPO3\CMS\Filelist\FileList\$iLimit
‪int $iLimit
Definition: FileList.php:61
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\getTSConfig
‪array getTSConfig()
Definition: BackendUserAuthentication.php:1000
‪TYPO3\CMS\Backend\Backend\Avatar\Avatar
Definition: Avatar.php:33
‪TYPO3\CMS\Filelist\FileList\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: FileList.php:171
‪TYPO3\CMS\Filelist\FileList\getBackendUserInformation
‪getBackendUserInformation(int $backendUserId)
Definition: FileList.php:1373
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Filelist\FileList\$resourceFactory
‪ResourceFactory $resourceFactory
Definition: FileList.php:148
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\check
‪bool check($type, $value)
Definition: BackendUserAuthentication.php:585
‪TYPO3\CMS\Core\Resource\Folder\getFileCount
‪int getFileCount(array $filterMethods=[], $recursive=false)
Definition: Folder.php:262
‪TYPO3\CMS\Filelist\FileList\$counter
‪int $counter
Definition: FileList.php:117
‪TYPO3\CMS\Core\Resource\Folder\FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
‪const FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
Definition: Folder.php:69
‪TYPO3\CMS\Core\Resource\AbstractFile\getHashedIdentifier
‪string getHashedIdentifier()
Definition: AbstractFile.php:151
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Filelist\FileList\formatDirList
‪string formatDirList(array $folders)
Definition: FileList.php:487
‪TYPO3\CMS\Filelist\FileList\makeClip
‪array makeClip($fileOrFolderObject)
Definition: FileList.php:834
‪TYPO3\CMS\Filelist\FileList\$clipObj
‪Clipboard $clipObj
Definition: FileList.php:144
‪TYPO3\CMS\Filelist\FileList\$thumbs
‪bool $thumbs
Definition: FileList.php:67
‪TYPO3\CMS\Core\Localization\LanguageService\sL
‪string sL($input)
Definition: LanguageService.php:161
‪TYPO3\CMS\Core\Resource\Utility\ListUtility
Definition: ListUtility.php:26
‪TYPO3\CMS\Filelist\FileList\getTable
‪string getTable(?FileSearchDemand $searchDemand=null)
Definition: FileList.php:237
‪TYPO3\CMS\Filelist\Event\ProcessFileListActionsEvent
Definition: ProcessFileListActionsEvent.php:27
‪TYPO3\CMS\Filelist\FileList\listURL
‪string listURL(array $params=[])
Definition: FileList.php:624
‪TYPO3\CMS\Filelist\FileList\$sortRev
‪bool $sortRev
Definition: FileList.php:91
‪TYPO3\CMS\Filelist
‪TYPO3\CMS\Filelist\FileList\getLanguageService
‪LanguageService getLanguageService()
Definition: FileList.php:1538
‪TYPO3\CMS\Filelist\FileList\$CBnames
‪array $CBnames
Definition: FileList.php:140
‪TYPO3\CMS\Filelist\FileList\$totalbytes
‪int $totalbytes
Definition: FileList.php:99
‪TYPO3\CMS\Filelist\FileList\$folderObject
‪Folder $folderObject
Definition: FileList.php:136
‪TYPO3\CMS\Filelist\FileList\getFileReferenceCount
‪getFileReferenceCount(File $file)
Definition: FileList.php:1509
‪TYPO3\CMS\Core\Type\Bitmask\JsConfirmation\DELETE
‪const DELETE
Definition: JsConfirmation.php:39
‪TYPO3\CMS\Core\Resource\Folder\getStorage
‪ResourceStorage getStorage()
Definition: Folder.php:149
‪TYPO3\CMS\Filelist\FileList\fwd_rwd_nav
‪string fwd_rwd_nav(int $currentItemCount)
Definition: FileList.php:437
‪TYPO3\CMS\Core\Resource\InaccessibleFolder
Definition: InaccessibleFolder.php:29
‪TYPO3\CMS\Filelist\FileList\$translationRecords
‪$translationRecords
Definition: FileList.php:765
‪TYPO3\CMS\Filelist\FileList
Definition: FileList.php:56
‪TYPO3\CMS\Filelist\FileList\makeTranslations
‪string makeTranslations(File $file)
Definition: FileList.php:1219
‪TYPO3\CMS\Filelist\FileList\sortFolders
‪Folder[] sortFolders(array $folders)
Definition: FileList.php:1461
‪TYPO3\CMS\Core\Resource\Search\FileSearchDemand
Definition: FileSearchDemand.php:26
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:37
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:41
‪TYPO3\CMS\Core\Resource\StorageRepository
Definition: StorageRepository.php:38
‪TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
Definition: ResourceDoesNotExistException.php:23
‪TYPO3\CMS\Filelist\FileList\$fixedL
‪int $fixedL
Definition: FileList.php:79
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:24
‪TYPO3\CMS\Filelist\FileList\addElement
‪string addElement(array $data, array $attributes=[], bool $isTableHeader=false)
Definition: FileList.php:395
‪TYPO3\CMS\Core\Resource\ResourceStorage\isWithinFolder
‪bool isWithinFolder(Folder $folder, ResourceInterface $resource)
Definition: ResourceStorage.php:2635
‪TYPO3\CMS\Filelist\FileList\__construct
‪__construct(?ServerRequestInterface $request=null)
Definition: FileList.php:173
‪TYPO3\CMS\Core\Resource\MetaDataAspect\get
‪array get()
Definition: MetaDataAspect.php:76
‪TYPO3\CMS\Core\Resource\Folder\checkActionPermission
‪bool checkActionPermission($action)
Definition: Folder.php:436
‪TYPO3\CMS\Filelist\FileList\$fileExtensionFilter
‪FileExtensionFilter $fileExtensionFilter
Definition: FileList.php:163
‪TYPO3\CMS\Filelist\FileList\linkWrapFile
‪string linkWrapFile($code, File $fileObject)
Definition: FileList.php:595
‪TYPO3\CMS\Core\Resource\AbstractFile\getCombinedIdentifier
‪string getCombinedIdentifier()
Definition: AbstractFile.php:452
‪TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter
Definition: FileExtensionFilter.php:28
‪TYPO3\CMS\Filelist\FileList\$fieldArray
‪array $fieldArray
Definition: FileList.php:111
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Filelist\FileList\makePath
‪string makePath(ResourceInterface $resource)
Definition: FileList.php:1192
‪TYPO3\CMS\Core\Resource\FolderInterface\ROLE_PROCESSING
‪const ROLE_PROCESSING
Definition: FolderInterface.php:28
‪TYPO3\CMS\Core\Resource\AbstractFile\getUid
‪int getUid()
Definition: AbstractFile.php:203
‪TYPO3\CMS\Filelist\FileList\getBackendUser
‪BackendUserAuthentication getBackendUser()
Definition: FileList.php:1548
‪TYPO3\CMS\Core\Resource\Folder\getRole
‪string getRole()
Definition: Folder.php:535
‪TYPO3\CMS\Filelist\FileList\$uriBuilder
‪UriBuilder $uriBuilder
Definition: FileList.php:160
‪TYPO3\CMS\Filelist\FileList\makeCheckbox
‪string makeCheckbox($fileOrFolderObject)
Definition: FileList.php:909
‪TYPO3\CMS\Filelist\FileList\$firstElementNumber
‪int $firstElementNumber
Definition: FileList.php:95
‪TYPO3\CMS\Core\Resource\File\checkActionPermission
‪bool checkActionPermission($action)
Definition: File.php:219
‪TYPO3\CMS\Filelist\FileList\fileDownloadEnabled
‪bool fileDownloadEnabled()
Definition: FileList.php:1406
‪TYPO3\CMS\Core\Resource\ResourceInterface\getName
‪string getName()
‪TYPO3\CMS\Filelist\FileList\$translations
‪foreach($translationRecords as $record) return $translations
Definition: FileList.php:781
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:45
‪TYPO3\CMS\Filelist\FileList\getFolderInfo
‪string getFolderInfo()
Definition: FileList.php:471
‪$output
‪$output
Definition: annotationChecker.php:121
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
Definition: TranslationConfigurationProvider.php:37
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Filelist\FileList\getFileOrFolderIcon
‪string getFileOrFolderIcon(string $title, $fileOrFolderObject)
Definition: FileList.php:1315
‪TYPO3\CMS\Filelist\FileList\getConcreteTableName
‪string getConcreteTableName(string $fieldName)
Definition: FileList.php:1396
‪TYPO3\CMS\Core\Resource\FolderInterface
Definition: FolderInterface.php:22
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Resource\Folder\getIdentifier
‪string getIdentifier()
Definition: Folder.php:160
‪TYPO3\CMS\Core\Resource\ResourceInterface
Definition: ResourceInterface.php:22
‪TYPO3\CMS\Core\Resource\Folder\getCombinedIdentifier
‪string getCombinedIdentifier()
Definition: Folder.php:181
‪TYPO3\CMS\Core\Localization\LanguageService\includeLLFile
‪array includeLLFile($fileRef)
Definition: LanguageService.php:271
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Filelist\FileList\sortFiles
‪File[] sortFiles(array $files)
Definition: FileList.php:1415
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Filelist\FileList\renderCheckboxActions
‪string renderCheckboxActions()
Definition: FileList.php:1328
‪TYPO3\CMS\Core\Localization\LanguageService\getLL
‪string getLL($index)
Definition: LanguageService.php:121
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Filelist\FileList\$sort
‪string $sort
Definition: FileList.php:85
‪TYPO3\CMS\Core\Resource\ResourceInterface\getParentFolder
‪FolderInterface getParentFolder()
‪TYPO3\CMS\Core\Type\Bitmask\JsConfirmation
Definition: JsConfirmation.php:25
‪TYPO3\CMS\Filelist\FileList\$totalItems
‪int $totalItems
Definition: FileList.php:105
‪TYPO3\CMS\Filelist\FileList\$translations
‪$translations
Definition: FileList.php:780
‪TYPO3\CMS\Filelist\FileList\linkWrapDir
‪string linkWrapDir($title, Folder $folderObject)
Definition: FileList.php:578
‪TYPO3\CMS\Filelist\FileList\isEditMetadataAllowed
‪isEditMetadataAllowed(File $file)
Definition: FileList.php:1301
‪TYPO3\CMS\Filelist\FileListEditIconHookInterface
Definition: FileListEditIconHookInterface.php:23
‪TYPO3\CMS\Filelist\FileList\$id
‪int $id
Definition: FileList.php:156
‪TYPO3\CMS\Filelist\FileList\makeEdit
‪string makeEdit($fileOrFolderObject)
Definition: FileList.php:932
‪TYPO3\CMS\Filelist\FileList\$iconFactory
‪IconFactory $iconFactory
Definition: FileList.php:152