‪TYPO3CMS  ‪main
FileListController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ResponseFactoryInterface;
21 use Psr\Http\Message\ResponseInterface;
22 use Psr\Http\Message\ServerRequestInterface;
23 use Psr\Log\LoggerAwareInterface;
24 use Psr\Log\LoggerAwareTrait;
39 use TYPO3\CMS\Core\Imaging\IconSize;
65 
71 #[AsController]
72 class ‪FileListController implements LoggerAwareInterface
73 {
74  use LoggerAwareTrait;
75 
76  protected string ‪$id = '';
77  protected string ‪$cmd = '';
78  protected string ‪$searchTerm = '';
79  protected int ‪$currentPage = 1;
80 
81  protected ?‪Folder ‪$folderObject = null;
83  protected ?‪ModuleTemplate ‪$view = null;
84  protected ?‪FileList ‪$filelist = null;
85  protected ?‪ModuleData ‪$moduleData = null;
86 
87  public function ‪__construct(
88  protected readonly ‪UriBuilder $uriBuilder,
89  protected readonly ‪PageRenderer $pageRenderer,
90  protected readonly ‪IconFactory $iconFactory,
91  protected readonly ‪ResourceFactory $resourceFactory,
92  protected readonly ‪ModuleTemplateFactory $moduleTemplateFactory,
93  protected readonly ‪BackendViewFactory $viewFactory,
94  protected readonly ResponseFactoryInterface $responseFactory,
95  ) {}
96 
97  public function ‪handleRequest(ServerRequestInterface $request): ResponseInterface
98  {
99  $lang = $this->‪getLanguageService();
100  $backendUser = $this->‪getBackendUser();
101 
102  $this->moduleData = $request->getAttribute('moduleData');
103 
104  $this->view = $this->moduleTemplateFactory->create($request);
105  $this->view->setTitle($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'));
106 
107  $queryParams = $request->getQueryParams();
108  $parsedBody = $request->getParsedBody();
109 
110  $this->id = (string)($parsedBody['id'] ?? $queryParams['id'] ?? '');
111  $this->cmd = (string)($parsedBody['cmd'] ?? $queryParams['cmd'] ?? '');
112  $this->searchTerm = (string)trim($parsedBody['searchTerm'] ?? $queryParams['searchTerm'] ?? '');
113  $this->currentPage = (int)($parsedBody['currentPage'] ?? $queryParams['currentPage'] ?? 1);
114  $duplicationBehaviorFromRequest = $parsedBody['overwriteExistingFiles'] ?? $queryParams['overwriteExistingFiles'] ?? '';
115  $this->overwriteExistingFiles = DuplicationBehavior::tryFrom($duplicationBehaviorFromRequest) ?? ‪DuplicationBehavior::getDefaultDuplicationBehaviour();
116 
117  $storage = null;
118  try {
119  if ($this->id !== '') {
120  $backendUser->evaluateUserSpecificFileFilterSettings();
121  $storage = GeneralUtility::makeInstance(StorageRepository::class)->findByCombinedIdentifier($this->id);
122  if ($storage !== null) {
123  ‪$identifier = substr($this->id, strpos($this->id, ':') + 1);
124  if (!$storage->hasFolder(‪$identifier)) {
125  ‪$identifier = $storage->getFolderIdentifierFromFileIdentifier(‪$identifier);
126  }
127  $this->folderObject = $storage->getFolder(‪$identifier);
128  // Disallow access to fallback storage 0
129  if ($storage->isFallbackStorage()) {
131  'You are not allowed to access files outside your storages',
132  1434539815
133  );
134  }
135  // Disallow the rendering of the processing folder (e.g. could be called manually)
136  if ($this->folderObject instanceof ‪Folder && $storage->isProcessingFolder($this->folderObject)) {
137  $this->folderObject = $storage->getRootLevelFolder();
138  }
139  }
140  } else {
141  // Take the first object of the first storage
142  $fileStorages = $backendUser->getFileStorages();
143  $fileStorage = reset($fileStorages);
144  if ($fileStorage) {
145  $this->folderObject = $fileStorage->getRootLevelFolder();
146  } else {
147  throw new \RuntimeException('Could not find any folder to be displayed.', 1349276894);
148  }
149  }
150 
151  if ($this->folderObject && !$this->folderObject->getStorage()->isWithinFileMountBoundaries($this->folderObject)) {
152  throw new \RuntimeException('Folder not accessible.', 1430409089);
153  }
155  $this->folderObject = null;
156  if ($storage !== null && $storage->getDriverType() === 'Local' && !$storage->isOnline()) {
157  // If the base folder for a local storage does not exists, the storage is marked as offline and the
158  // access permission exception is thrown. In this case we however want to display another error message.
159  // @see https://forge.typo3.org/issues/85323
160  $this->‪addFlashMessage(
161  sprintf($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:localStorageOfflineMessage'), $storage->getName()),
162  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:localStorageOfflineTitle'),
163  ContextualFeedbackSeverity::ERROR
164  );
165  } else {
166  $this->‪addFlashMessage(
167  sprintf($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:missingFolderPermissionsMessage'), $this->id),
168  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:missingFolderPermissionsTitle'),
169  ContextualFeedbackSeverity::ERROR
170  );
171  }
172  } catch (‪Exception $fileException) {
173  $this->folderObject = null;
174  // Take the first object of the first storage
175  $fileStorages = $backendUser->getFileStorages();
176  $fileStorage = reset($fileStorages);
177  if ($fileStorage instanceof ‪ResourceStorage) {
178  $this->folderObject = $fileStorage->getRootLevelFolder();
179  if (!$fileStorage->isWithinFileMountBoundaries($this->folderObject)) {
180  $this->folderObject = null;
181  }
182  }
183  if (!$this->folderObject) {
184  $this->‪addFlashMessage(
185  sprintf($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:folderNotFoundMessage'), $this->id),
186  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:folderNotFoundTitle'),
187  ContextualFeedbackSeverity::ERROR
188  );
189  }
190  } catch (\RuntimeException $e) {
191  $this->folderObject = null;
192  $this->‪addFlashMessage(
193  $e->getMessage() . ' (' . $e->getCode() . ')',
194  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:folderNotFoundTitle'),
195  ContextualFeedbackSeverity::ERROR
196  );
197  }
198 
199  if ($this->folderObject
200  && !$this->folderObject->getStorage()->checkFolderActionPermission('read', $this->folderObject)
201  ) {
202  $this->folderObject = null;
203  }
204 
205  $this->view->assign('currentIdentifier', $this->folderObject ? $this->folderObject->getCombinedIdentifier() : '');
206  $javaScriptRenderer = $this->pageRenderer->getJavaScriptRenderer();
207  $javaScriptRenderer->addJavaScriptModuleInstruction(
208  ‪JavaScriptModuleInstruction::create('@typo3/filelist/file-list.js')->instance()
209  );
210 
211  $this->pageRenderer->loadJavaScriptModule('@typo3/filelist/file-list-dragdrop.js');
212  $this->pageRenderer->loadJavaScriptModule('@typo3/filelist/file-list-transfer-handler.js');
213  $this->pageRenderer->addInlineLanguageLabelFile('EXT:filelist/Resources/Private/Language/locallang_transfer_handler.xlf');
214 
215  $this->pageRenderer->loadJavaScriptModule('@typo3/filelist/file-list-actions.js');
216  $this->pageRenderer->loadJavaScriptModule('@typo3/filelist/file-list-rename-handler.js');
217  $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_rename');
218 
219  $this->pageRenderer->loadJavaScriptModule('@typo3/filelist/file-delete.js');
220  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/context-menu.js');
221  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/clipboard-panel.js');
222  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/multi-record-selection.js');
223  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/column-selector-button.js');
224 
225  $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons');
226 
227  $this->‪initializeModule($request);
228 
229  // In case the folderObject is NULL, the request is either invalid or the user
230  // does not have necessary permissions. Just render and return the "empty" view.
231  if ($this->folderObject === null) {
232  return $this->view->renderResponse('File/List');
233  }
234 
235  return $this->‪processRequest($request);
236  }
237 
238  protected function ‪processRequest(ServerRequestInterface $request): ResponseInterface
239  {
240  $lang = $this->‪getLanguageService();
241 
242  // Initialize FileList, including the clipboard actions
243  $this->‪initializeFileList($request);
244 
245  // Generate the file listing markup
246  $this->‪generateFileList($request);
247 
248  // Generate the clipboard, if enabled
249  $this->view->assign('showClipboardPanel', (bool)$this->moduleData->get('clipBoard'));
250 
251  // Register drag-uploader
252  $this->‪registerDragUploader();
253 
254  // Register the display thumbnails / show clipboard checkboxes
256 
257  // Register additional doc header buttons
258  $this->‪registerAdditionalDocHeaderButtons($request);
259 
260  // Add additional view variables
261  $this->view->assignMultiple([
262  'headline' => $this->‪getModuleHeadline(),
263  'folderIdentifier' => $this->folderObject->getCombinedIdentifier(),
264  'searchTerm' => $this->searchTerm,
265  ]);
266 
267  // Overwrite the default module title, adding the specific module headline (the folder name)
268  $this->view->setTitle(
269  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'),
270  $this->getModuleHeadline()
271  );
272 
273  // Additional doc header information: current path and folder info
274  $this->view->getDocHeaderComponent()->setMetaInformation([
275  '_additional_info' => $this->filelist->getFolderInfo(),
276  ]);
277  $this->view->getDocHeaderComponent()->setMetaInformationForResource($this->folderObject);
278 
279  return $this->view->renderResponse('File/List');
280  }
281 
282  protected function ‪initializeModule(ServerRequestInterface $request): void
283  {
284  $userTsConfig = $this->‪getBackendUser()->getTSConfig();
285 
286  // Set predefined value for DisplayThumbnails:
287  if (($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'activated') {
288  $this->moduleData->set('displayThumbs', true);
289  } elseif (($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'deactivated') {
290  $this->moduleData->set('displayThumbs', false);
291  }
292  // Set predefined value for Clipboard:
293  if (($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'activated') {
294  $this->moduleData->set('clipBoard', true);
295  } elseif (($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'deactivated') {
296  $this->moduleData->set('clipBoard', false);
297  }
298  }
299 
300  protected function ‪initializeFileList(ServerRequestInterface $request): void
301  {
302  // Create the file list
303  $this->filelist = GeneralUtility::makeInstance(FileList::class, $request);
304  $this->filelist->viewMode = ViewMode::tryFrom($this->moduleData->get('viewMode')) ?? ‪ViewMode::TILES;
305  $this->filelist->thumbs = (‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] ?? false) && $this->moduleData->get('displayThumbs');
306 
307  // Create clipboard object and initialize it
308  $CB = array_replace_recursive($request->getQueryParams()['CB'] ?? [], $request->getParsedBody()['CB'] ?? []);
309  if (($this->cmd === 'copyMarked' || $this->cmd === 'removeMarked')) {
310  // Get CBC from request, and map the element values, since they must either be the file identifier,
311  // in case the element should be transferred to the clipboard, or false if it should be removed.
312  $CBC = array_map(fn($item) => $this->cmd === 'copyMarked' ? $item : false, (array)($request->getParsedBody()['CBC'] ?? []));
313  // Cleanup CBC
314  $CB['el'] = $this->filelist->clipObj->cleanUpCBC($CBC, '_FILE');
315  }
316  if (!$this->moduleData->get('clipBoard')) {
317  $CB['setP'] = 'normal';
318  }
319  $this->filelist->clipObj->setCmd($CB);
320  $this->filelist->clipObj->cleanCurrent();
321  $this->filelist->clipObj->endClipboard();
322 
323  // If the "cmd" was to delete files from the list, do that:
324  if ($this->cmd === 'delete') {
325  $items = $this->filelist->clipObj->cleanUpCBC(
326  (array)($request->getParsedBody()['CBC'] ?? []),
327  '_FILE',
328  true
329  );
330  if (!empty($items)) {
331  // Make command array:
332  $FILE = [];
333  foreach ($items as $clipboardIdentifier => $combinedIdentifier) {
334  $FILE['delete'][] = ['data' => $combinedIdentifier];
335  $this->filelist->clipObj->removeElement($clipboardIdentifier);
336  }
337  // Init file processing object for deleting and pass the cmd array.
338  $fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
339  $fileProcessor->setActionPermissions();
340  $fileProcessor->setExistingFilesConflictMode($this->overwriteExistingFiles);
341  $fileProcessor->start($FILE);
342  $fileProcessor->processData();
343  // Clean & Save clipboard state
344  $this->filelist->clipObj->cleanCurrent();
345  $this->filelist->clipObj->endClipboard();
346  }
347  }
348 
349  // Start up the file list by including processed settings.
350  $this->filelist->start(
351  $this->folderObject,
352  ‪MathUtility::forceIntegerInRange($this->currentPage, 1, 100000),
353  (string)$this->moduleData->get('sort'),
354  (bool)$this->moduleData->get('reverse')
355  );
356  $this->filelist->setColumnsToRender($this->‪getBackendUser()->getModuleData('list/displayFields')['_FILE'] ?? []);
357 
358  $resourceSelectableMatcher = GeneralUtility::makeInstance(Matcher::class);
359  $resourceSelectableMatcher->addMatcher(GeneralUtility::makeInstance(ResourceFileTypeMatcher::class));
360  $resourceSelectableMatcher->addMatcher(GeneralUtility::makeInstance(ResourceFolderTypeMatcher::class));
361  $this->filelist->setResourceSelectableMatcher($resourceSelectableMatcher);
362 
363  $resourceDownloadMatcher = GeneralUtility::makeInstance(Matcher::class);
364  $resourceDownloadMatcher->addMatcher(GeneralUtility::makeInstance(ResourceFileTypeMatcher::class));
365  $resourceDownloadMatcher->addMatcher(GeneralUtility::makeInstance(ResourceFolderTypeMatcher::class));
366  $this->filelist->setResourceDownloadMatcher($resourceDownloadMatcher);
367  }
368 
369  protected function ‪generateFileList(ServerRequestInterface $request): void
370  {
371  $lang = $this->‪getLanguageService();
372 
373  // If a searchTerm is provided, create the searchDemand object
374  $searchDemand = $this->searchTerm !== ''
375  ? ‪FileSearchDemand::createForSearchTerm($this->searchTerm)->withRecursive()
376  : null;
377 
378  // Generate the list, if accessible
379  if ($this->folderObject->getStorage()->isBrowsable()) {
380  $fileListView = $this->viewFactory->create($request);
381  $this->view->assignMultiple([
382  'listHtml' => $this->filelist->render($searchDemand, $fileListView),
383  'listUrl' => $this->filelist->createModuleUri(),
384  'fileUploadUrl' => $this->getFileUploadUrl(),
385  'totalItems' => $this->filelist->totalItems,
386  ]);
387 
388  // Add edit metadata configuration, if user can edit default language
389  if ($this->‪getBackendUser()->checkLanguageAccess(0)) {
390  $this->view->assign(
391  'editActionConfiguration',
392  GeneralUtility::jsonEncodeForHtmlAttribute([
393  'idField' => 'filelistMetaUid',
394  'table' => 'sys_file_metadata',
395  'returnUrl' => $this->filelist->createModuleUri(),
396  ])
397  );
398  }
399 
400  // Assign meta information for the multi record selection
401  $this->view->assign(
402  'deleteActionConfiguration',
403  GeneralUtility::jsonEncodeForHtmlAttribute([
404  'ok' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.delete'),
405  'title' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_deleteMarked'),
406  'content' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_deleteMarkedWarning'),
407  ]),
408  );
409 
410  // Add download button configuration, if file download is enabled
411  if ($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['fileDownload.']['enabled'] ?? true) {
412  $this->view->assign(
413  'downloadActionConfiguration',
414  GeneralUtility::jsonEncodeForHtmlAttribute([
415  'downloadUrl' => (string)$this->uriBuilder->buildUriFromRoute('file_download'),
416  ])
417  );
418  }
419  } else {
420  $this->‪addFlashMessage(
421  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:storageNotBrowsableMessage'),
422  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:storageNotBrowsableTitle')
423  );
424  }
425  }
426 
427  protected function ‪registerDragUploader(): void
428  {
429  // Include DragUploader only if we have write access
430  if ($this->folderObject->checkActionPermission('write')
431  && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
432  ) {
433  $lang = $this->‪getLanguageService();
434  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/drag-uploader.js');
435  $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_upload');
436  $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_download');
437  $this->pageRenderer->addInlineLanguageLabelArray([
438  'type.file' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:file'),
439  'permissions.read' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:read'),
440  'permissions.write' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:write'),
441  'online_media.update.success' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:online_media.update.success'),
442  'online_media.update.error' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:online_media.update.error'),
443  ]);
444  $defaultDuplicationBehavior = ‪DuplicationBehavior::getDefaultDuplicationBehaviour($this->‪getBackendUser());
445  $this->view->assign('dragUploader', [
446  'fileDenyPattern' => ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] ?? null,
447  'maxFileSize' => GeneralUtility::getMaxUploadFileSize() * 1024,
448  'defaultDuplicationBehaviourAction' => $defaultDuplicationBehavior->value,
449  ]);
450  }
451  }
452 
453  protected function ‪registerFileListCheckboxes(): void
454  {
455  $lang = $this->‪getLanguageService();
456  $userTsConfig = $this->‪getBackendUser()->getTSConfig();
457 
458  $this->view->assign('enableClipBoard', [
459  'enabled' => ($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'selectable',
460  'label' => htmlspecialchars($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clipBoard')),
461  'mode' => $this->filelist->clipObj->current,
462  ]);
463  }
464 
468  protected function ‪registerAdditionalDocHeaderButtons(ServerRequestInterface $request): void
469  {
470  $lang = $this->‪getLanguageService();
471  $buttonBar = $this->view->getDocHeaderComponent()->getButtonBar();
472 
473  // Refresh
474  $refreshButton = $buttonBar->makeLinkButton()
475  ->setHref($request->getAttribute('normalizedParams')->getRequestUri())
476  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
477  ->setIcon($this->iconFactory->getIcon('actions-refresh', IconSize::SMALL));
478  $buttonBar->addButton($refreshButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
479 
480  // ViewMode
481  $viewModeItems = [];
482  $viewModeItems[] = GeneralUtility::makeInstance(DropDownRadio::class)
483  ->setActive($this->moduleData->get('viewMode') === ‪ViewMode::TILES->value)
484  ->setHref($this->filelist->createModuleUri(['viewMode' => ‪ViewMode::TILES->value]))
485  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.tiles'))
486  ->setIcon($this->iconFactory->getIcon('actions-viewmode-tiles'));
487  $viewModeItems[] = GeneralUtility::makeInstance(DropDownRadio::class)
488  ->setActive($this->moduleData->get('viewMode') === ‪ViewMode::LIST->value)
489  ->setHref($this->filelist->createModuleUri(['viewMode' => ‪ViewMode::LIST->value]))
490  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.list'))
491  ->setIcon($this->iconFactory->getIcon('actions-viewmode-list'));
492  $viewModeItems[] = GeneralUtility::makeInstance(DropDownDivider::class);
493  if (‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && ($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'selectable') {
494  $viewModeItems[] = GeneralUtility::makeInstance(DropDownToggle::class)
495  ->setActive((bool)$this->moduleData->get('displayThumbs'))
496  ->setHref($this->filelist->createModuleUri(['displayThumbs' => $this->moduleData->get('displayThumbs') ? 0 : 1]))
497  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.showThumbnails'))
498  ->setIcon($this->iconFactory->getIcon('actions-image'));
499  }
500  $viewModeItems[] = GeneralUtility::makeInstance(DropDownToggle::class)
501  ->setActive((bool)$this->moduleData->get('clipBoard'))
502  ->setHref($this->filelist->createModuleUri(['clipBoard' => $this->moduleData->get('clipBoard') ? 0 : 1]))
503  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.showClipboard'))
504  ->setIcon($this->iconFactory->getIcon('actions-clipboard'));
505  if (($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['displayColumnSelector'] ?? true)
506  && $this->moduleData->get('viewMode') === ‪ViewMode::LIST->value) {
507  $viewModeItems[] = GeneralUtility::makeInstance(DropDownDivider::class);
508  $viewModeItems[] = GeneralUtility::makeInstance(DropDownItem::class)
509  ->setTag('typo3-backend-column-selector-button')
510  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.selectColumns'))
511  ->setAttributes([
512  'data-url' => $this->uriBuilder->buildUriFromRoute(
513  'ajax_show_columns_selector',
514  ['id' => $this->id, 'table' => '_FILE']
515  ),
516  'data-target' => $this->filelist->createModuleUri(),
517  'data-title' => sprintf(
518  $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:showColumnsSelection'),
519  $lang->sL(‪$GLOBALS['TCA']['sys_file']['ctrl']['title'] ?? ''),
520  ),
521  'data-button-ok' => $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:updateColumnView'),
522  'data-button-close' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel'),
523  'data-error-message' => $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:updateColumnView.error'),
524  ])
525  ->setIcon($this->iconFactory->getIcon('actions-options'));
526  }
527  $viewModeButton = $buttonBar->makeDropDownButton()
528  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view'))
529  ->setShowLabelText(true);
530  foreach ($viewModeItems as $viewModeItem) {
531  $viewModeButton->addItem($viewModeItem);
532  }
533  $buttonBar->addButton($viewModeButton, ‪ButtonBar::BUTTON_POSITION_RIGHT, 2);
534 
535  // Level up
536  try {
537  $currentStorage = $this->folderObject->getStorage();
538  $parentFolder = $this->folderObject->getParentFolder();
539  if ($currentStorage->isWithinFileMountBoundaries($parentFolder)
540  && $parentFolder->getIdentifier() !== $this->folderObject->getIdentifier()
541  && $parentFolder instanceof ‪Folder
542  ) {
543  $levelUpButton = $buttonBar->makeLinkButton()
544  ->setDataAttributes([
545  'tree-update-request' => htmlspecialchars('folder' . ‪GeneralUtility::md5int($parentFolder->getCombinedIdentifier())),
546  ])
547  ->setHref(
548  (string)$this->uriBuilder->buildUriFromRoute(
549  'media_management',
550  ['id' => $parentFolder->getCombinedIdentifier()]
551  )
552  )
553  ->setShowLabelText(true)
554  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel'))
555  ->setIcon($this->iconFactory->getIcon('actions-view-go-up', IconSize::SMALL));
556  $buttonBar->addButton($levelUpButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 1);
557  }
558  } catch (\‪Exception $e) {
559  }
560 
561  // Shortcut
562  $shortCutButton = $buttonBar->makeShortcutButton()
563  ->setRouteIdentifier('media_management')
564  ->setDisplayName(sprintf(
565  '%s: %s',
566  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'),
567  $this->folderObject->getName() ?: $this->folderObject->getIdentifier()
568  ))
569  ->setArguments(array_filter([
570  'id' => $this->id,
571  'searchTerm' => $this->searchTerm,
572  ]));
573  $buttonBar->addButton($shortCutButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
574 
575  // Upload button (only if upload to this directory is allowed)
576  if ($this->folderObject
577  && $this->folderObject->checkActionPermission('write')
578  && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
579  ) {
580  $uploadButton = $buttonBar->makeLinkButton()
581  ->setHref($this->‪getFileUploadUrl())
582  ->setClasses('t3js-drag-uploader-trigger')
583  ->setShowLabelText(true)
584  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload'))
585  ->setIcon($this->iconFactory->getIcon('actions-edit-upload', IconSize::SMALL));
586  $buttonBar->addButton($uploadButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 2);
587  }
588 
589  // New folder button
590  if ($this->folderObject && $this->folderObject->checkActionPermission('write') && $this->folderObject->checkActionPermission('add')) {
591  $newButton = $buttonBar->makeLinkButton()
592  ->setClasses('t3js-element-browser')
593  ->setHref((string)$this->uriBuilder->buildUriFromRoute('wizard_element_browser'))
594  ->setDataAttributes([
595  'identifier' => $this->folderObject->getCombinedIdentifier(),
597  ])
598  ->setShowLabelText(true)
599  ->setTitle($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:actions.create_folder'))
600  ->setIcon($this->iconFactory->getIcon('actions-folder-add', IconSize::SMALL));
601  $buttonBar->addButton($newButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 3);
602  }
603 
604  // New file button
605  if ($this->folderObject && $this->folderObject->checkActionPermission('write')
606  && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
607  ) {
608  $newButton = $buttonBar->makeLinkButton()
609  ->setHref((string)$this->uriBuilder->buildUriFromRoute(
610  'file_create',
611  [
612  'target' => $this->folderObject->getCombinedIdentifier(),
613  'returnUrl' => $this->filelist->createModuleUri(),
614  ]
615  ))
616  ->setShowLabelText(true)
617  ->setTitle($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:actions.create_file'))
618  ->setIcon($this->iconFactory->getIcon('actions-file-add', IconSize::SMALL));
619  $buttonBar->addButton($newButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 4);
620  }
621 
622  // Add paste button if clipboard is initialized
623  if ($this->filelist->clipObj instanceof ‪Clipboard && $this->folderObject->checkActionPermission('write')) {
624  $elFromTable = $this->filelist->clipObj->elFromTable('_FILE');
625  if (!empty($elFromTable)) {
626  $addPasteButton = true;
627  $elToConfirm = [];
628  foreach ($elFromTable as $key => $element) {
629  $clipBoardElement = $this->resourceFactory->retrieveFileOrFolderObject($element);
630  if ($clipBoardElement instanceof ‪Folder && $clipBoardElement->‪getStorage()->isWithinFolder(
631  $clipBoardElement,
632  $this->folderObject
633  )
634  ) {
635  $addPasteButton = false;
636  }
637  $elToConfirm[$key] = $clipBoardElement->getName();
638  }
639  if ($addPasteButton) {
640  $confirmText = $this->filelist->clipObj
641  ->confirmMsgText('_FILE', $this->folderObject->getReadablePath(), 'into', $elToConfirm);
642  $pastButtonTitle = $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_paste');
643  $pasteButton = $buttonBar->makeLinkButton()
644  ->setHref($this->filelist->clipObj
645  ->pasteUrl('_FILE', $this->folderObject->getCombinedIdentifier()))
646  ->setClasses('t3js-modal-trigger')
647  ->setDataAttributes([
648  'severity' => 'warning',
649  'bs-content' => $confirmText,
650  'title' => $pastButtonTitle,
651  ])
652  ->setShowLabelText(true)
653  ->setTitle($pastButtonTitle)
654  ->setIcon($this->iconFactory->getIcon('actions-document-paste-into', IconSize::SMALL));
655  $buttonBar->addButton($pasteButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 10);
656  }
657  }
658  }
659  }
660 
665  protected function ‪getModuleHeadline(): string
666  {
667  $name = $this->folderObject->getName();
668  if ($name === '') {
669  // Show storage name on storage root
670  if ($this->folderObject->getIdentifier() === '/') {
671  $name = $this->folderObject->getStorage()->getName();
672  }
673  } else {
674  $name = key(ListUtility::resolveSpecialFolderNames(
675  [$name => $this->folderObject]
676  ));
677  }
678  return (string)$name;
679  }
680 
684  protected function ‪htmlResponse(string $html): ResponseInterface
685  {
686  $response = $this->responseFactory
687  ->createResponse()
688  ->withHeader('Content-Type', 'text/html; charset=utf-8');
689 
690  $response->getBody()->write($html);
691  return $response;
692  }
693 
697  protected function ‪addFlashMessage(string $message, string $title = '', ‪ContextualFeedbackSeverity $severity = ContextualFeedbackSeverity::INFO): void
698  {
699  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $message, $title, $severity, true);
700  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
701  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
702  $defaultFlashMessageQueue->enqueue($flashMessage);
703  }
704 
708  protected function ‪getFileUploadUrl(): string
709  {
710  return (string)$this->uriBuilder->buildUriFromRoute(
711  'file_upload',
712  [
713  'target' => $this->folderObject->getCombinedIdentifier(),
714  'returnUrl' => $this->filelist->createModuleUri(),
715  ]
716  );
717  }
718 
720  {
721  return ‪$GLOBALS['LANG'];
722  }
723 
725  {
726  return ‪$GLOBALS['BE_USER'];
727  }
728 }
‪TYPO3\CMS\Filelist\Controller\FileListController\getModuleHeadline
‪getModuleHeadline()
Definition: FileListController.php:665
‪TYPO3\CMS\Filelist\Matcher\ResourceFolderTypeMatcher
Definition: ResourceFolderTypeMatcher.php:27
‪TYPO3\CMS\Scheduler\LIST
‪@ LIST
Definition: SchedulerManagementAction.php:28
‪TYPO3\CMS\Filelist\Controller\FileListController\initializeFileList
‪initializeFileList(ServerRequestInterface $request)
Definition: FileListController.php:300
‪TYPO3\CMS\Filelist\Controller\FileListController\processRequest
‪processRequest(ServerRequestInterface $request)
Definition: FileListController.php:238
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_LEFT
‪const BUTTON_POSITION_LEFT
Definition: ButtonBar.php:37
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:33
‪TYPO3\CMS\Filelist\Controller\FileListController\__construct
‪__construct(protected readonly UriBuilder $uriBuilder, protected readonly PageRenderer $pageRenderer, protected readonly IconFactory $iconFactory, protected readonly ResourceFactory $resourceFactory, protected readonly ModuleTemplateFactory $moduleTemplateFactory, protected readonly BackendViewFactory $viewFactory, protected readonly ResponseFactoryInterface $responseFactory,)
Definition: FileListController.php:87
‪TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
Definition: InsufficientFolderAccessPermissionsException.php:23
‪TYPO3\CMS\Backend\Clipboard\Clipboard
Definition: Clipboard.php:48
‪TYPO3\CMS\Backend\View\BackendViewFactory
Definition: BackendViewFactory.php:35
‪TYPO3\CMS\Filelist\Controller\FileListController\$view
‪ModuleTemplate $view
Definition: FileListController.php:83
‪TYPO3\CMS\Backend\Template\ModuleTemplateFactory
Definition: ModuleTemplateFactory.php:33
‪TYPO3\CMS\Filelist\Controller\FileListController\getFileUploadUrl
‪getFileUploadUrl()
Definition: FileListController.php:708
‪TYPO3\CMS\Filelist\Controller\FileListController\$filelist
‪FileList $filelist
Definition: FileListController.php:84
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Module\ModuleData
Definition: ModuleData.php:30
‪TYPO3\CMS\Filelist\Controller\FileListController\initializeModule
‪initializeModule(ServerRequestInterface $request)
Definition: FileListController.php:282
‪TYPO3\CMS\Filelist\Matcher\Matcher
Definition: Matcher.php:24
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Core\Resource\Utility\ListUtility
Definition: ListUtility.php:26
‪TYPO3\CMS\Filelist\Controller\FileListController\getLanguageService
‪getLanguageService()
Definition: FileListController.php:719
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:46
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownToggle
Definition: DropDownToggle.php:39
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownDivider
Definition: DropDownDivider.php:27
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Core\Utility\File\ExtendedFileUtility
Definition: ExtendedFileUtility.php:76
‪TYPO3\CMS\Core\Page\PageRenderer
Definition: PageRenderer.php:44
‪TYPO3\CMS\Core\Resource\Enum\getDefaultDuplicationBehaviour
‪@ getDefaultDuplicationBehaviour
Definition: DuplicationBehavior.php:53
‪TYPO3\CMS\Filelist\Controller
‪TYPO3\CMS\Filelist\FileList
Definition: FileList.php:74
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownRadio
Definition: DropDownRadio.php:54
‪TYPO3\CMS\Filelist\Controller\FileListController\htmlResponse
‪htmlResponse(string $html)
Definition: FileListController.php:684
‪TYPO3\CMS\Filelist\Controller\FileListController
Definition: FileListController.php:73
‪TYPO3\CMS\Filelist\Controller\FileListController\$searchTerm
‪string $searchTerm
Definition: FileListController.php:78
‪TYPO3\CMS\Core\Resource\Search\FileSearchDemand
Definition: FileSearchDemand.php:26
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:38
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:42
‪TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException
Definition: FolderDoesNotExistException.php:21
‪TYPO3\CMS\Core\Resource\StorageRepository
Definition: StorageRepository.php:38
‪TYPO3\CMS\Core\Resource\Folder\getStorage
‪getStorage()
Definition: Folder.php:139
‪TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior
‪DuplicationBehavior
Definition: DuplicationBehavior.php:28
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Filelist\ElementBrowser\CreateFolderBrowser\IDENTIFIER
‪const IDENTIFIER
Definition: CreateFolderBrowser.php:35
‪TYPO3\CMS\Filelist\Controller\FileListController\$moduleData
‪ModuleData $moduleData
Definition: FileListController.php:85
‪TYPO3\CMS\Filelist\Controller\FileListController\$id
‪string $id
Definition: FileListController.php:76
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Filelist\Controller\FileListController\getBackendUser
‪getBackendUser()
Definition: FileListController.php:724
‪TYPO3\CMS\Filelist\Controller\FileListController\addFlashMessage
‪addFlashMessage(string $message, string $title='', ContextualFeedbackSeverity $severity=ContextualFeedbackSeverity::INFO)
Definition: FileListController.php:697
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:129
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪TYPO3\CMS\Filelist\Controller\FileListController\registerFileListCheckboxes
‪registerFileListCheckboxes()
Definition: FileListController.php:453
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Filelist\Controller\FileListController\registerDragUploader
‪registerDragUploader()
Definition: FileListController.php:427
‪TYPO3\CMS\Filelist\Controller\FileListController\registerAdditionalDocHeaderButtons
‪registerAdditionalDocHeaderButtons(ServerRequestInterface $request)
Definition: FileListController.php:468
‪TYPO3\CMS\Filelist\Type\TILES
‪@ TILES
Definition: ViewMode.php:26
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Filelist\Controller\FileListController\handleRequest
‪handleRequest(ServerRequestInterface $request)
Definition: FileListController.php:97
‪TYPO3\CMS\Backend\Attribute\AsController
Definition: AsController.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility\md5int
‪static int md5int($str)
Definition: GeneralUtility.php:462
‪TYPO3\CMS\Filelist\Controller\FileListController\generateFileList
‪generateFileList(ServerRequestInterface $request)
Definition: FileListController.php:369
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪TYPO3\CMS\Filelist\Controller\FileListController\$cmd
‪string $cmd
Definition: FileListController.php:77
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Resource\Search\FileSearchDemand\createForSearchTerm
‪static createForSearchTerm(string $searchTerm)
Definition: FileSearchDemand.php:70
‪TYPO3\CMS\Filelist\Type\ViewMode
‪ViewMode
Definition: ViewMode.php:24
‪TYPO3\CMS\Filelist\ElementBrowser\CreateFolderBrowser
Definition: CreateFolderBrowser.php:34
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_RIGHT
‪const BUTTON_POSITION_RIGHT
Definition: ButtonBar.php:42
‪TYPO3\CMS\Filelist\Matcher\ResourceFileTypeMatcher
Definition: ResourceFileTypeMatcher.php:27
‪TYPO3\CMS\Filelist\Controller\FileListController\$currentPage
‪int $currentPage
Definition: FileListController.php:79
‪TYPO3\CMS\Filelist\Controller\FileListController\$overwriteExistingFiles
‪DuplicationBehavior $overwriteExistingFiles
Definition: FileListController.php:82
‪TYPO3\CMS\Core\Resource\Exception
Definition: AbstractFileOperationException.php:16
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownItem
Definition: DropDownItem.php:34
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Filelist\Controller\FileListController\$folderObject
‪Folder $folderObject
Definition: FileListController.php:81