‪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  // Assign meta information for the multi record selection
388  $this->view->assignMultiple([
389  'editActionConfiguration' => GeneralUtility::jsonEncodeForHtmlAttribute([
390  'idField' => 'filelistMetaUid',
391  'table' => 'sys_file_metadata',
392  'returnUrl' => $this->filelist->createModuleUri(),
393  ], true),
394  'deleteActionConfiguration' => GeneralUtility::jsonEncodeForHtmlAttribute([
395  'ok' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.delete'),
396  'title' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_deleteMarked'),
397  'content' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_deleteMarkedWarning'),
398  ], true),
399  ]);
400 
401  // Add download button configuration, if file download is enabled
402  if ($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['fileDownload.']['enabled'] ?? true) {
403  $this->view->assign(
404  'downloadActionConfiguration',
405  GeneralUtility::jsonEncodeForHtmlAttribute([
406  'downloadUrl' => (string)$this->uriBuilder->buildUriFromRoute('file_download'),
407  ], true)
408  );
409  }
410  } else {
411  $this->‪addFlashMessage(
412  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:storageNotBrowsableMessage'),
413  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:storageNotBrowsableTitle')
414  );
415  }
416  }
417 
418  protected function ‪registerDragUploader(): void
419  {
420  // Include DragUploader only if we have write access
421  if ($this->folderObject->checkActionPermission('write')
422  && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
423  ) {
424  $lang = $this->‪getLanguageService();
425  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/drag-uploader.js');
426  $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_upload');
427  $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_download');
428  $this->pageRenderer->addInlineLanguageLabelArray([
429  'type.file' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:file'),
430  'permissions.read' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:read'),
431  'permissions.write' => $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:write'),
432  'online_media.update.success' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:online_media.update.success'),
433  'online_media.update.error' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:online_media.update.error'),
434  ]);
435  $defaultDuplicationBehavior = ‪DuplicationBehavior::getDefaultDuplicationBehaviour($this->‪getBackendUser());
436  $this->view->assign('dragUploader', [
437  'fileDenyPattern' => ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] ?? null,
438  'maxFileSize' => GeneralUtility::getMaxUploadFileSize() * 1024,
439  'defaultDuplicationBehaviourAction' => $defaultDuplicationBehavior->value,
440  ]);
441  }
442  }
443 
444  protected function ‪registerFileListCheckboxes(): void
445  {
446  $lang = $this->‪getLanguageService();
447  $userTsConfig = $this->‪getBackendUser()->getTSConfig();
448 
449  $this->view->assign('enableClipBoard', [
450  'enabled' => ($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'selectable',
451  'label' => htmlspecialchars($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clipBoard')),
452  'mode' => $this->filelist->clipObj->current,
453  ]);
454  }
455 
459  protected function ‪registerAdditionalDocHeaderButtons(ServerRequestInterface $request): void
460  {
461  $lang = $this->‪getLanguageService();
462  $buttonBar = $this->view->getDocHeaderComponent()->getButtonBar();
463 
464  // Refresh
465  $refreshButton = $buttonBar->makeLinkButton()
466  ->setHref($request->getAttribute('normalizedParams')->getRequestUri())
467  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
468  ->setIcon($this->iconFactory->getIcon('actions-refresh', IconSize::SMALL));
469  $buttonBar->addButton($refreshButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
470 
471  // ViewMode
472  $viewModeItems = [];
473  $viewModeItems[] = GeneralUtility::makeInstance(DropDownRadio::class)
474  ->setActive($this->moduleData->get('viewMode') === ‪ViewMode::TILES->value)
475  ->setHref($this->filelist->createModuleUri(['viewMode' => ‪ViewMode::TILES->value]))
476  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.tiles'))
477  ->setIcon($this->iconFactory->getIcon('actions-viewmode-tiles'));
478  $viewModeItems[] = GeneralUtility::makeInstance(DropDownRadio::class)
479  ->setActive($this->moduleData->get('viewMode') === ‪ViewMode::LIST->value)
480  ->setHref($this->filelist->createModuleUri(['viewMode' => ‪ViewMode::LIST->value]))
481  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.list'))
482  ->setIcon($this->iconFactory->getIcon('actions-viewmode-list'));
483  $viewModeItems[] = GeneralUtility::makeInstance(DropDownDivider::class);
484  if (‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && ($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'selectable') {
485  $viewModeItems[] = GeneralUtility::makeInstance(DropDownToggle::class)
486  ->setActive((bool)$this->moduleData->get('displayThumbs'))
487  ->setHref($this->filelist->createModuleUri(['displayThumbs' => $this->moduleData->get('displayThumbs') ? 0 : 1]))
488  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.showThumbnails'))
489  ->setIcon($this->iconFactory->getIcon('actions-image'));
490  }
491  $viewModeItems[] = GeneralUtility::makeInstance(DropDownToggle::class)
492  ->setActive((bool)$this->moduleData->get('clipBoard'))
493  ->setHref($this->filelist->createModuleUri(['clipBoard' => $this->moduleData->get('clipBoard') ? 0 : 1]))
494  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.showClipboard'))
495  ->setIcon($this->iconFactory->getIcon('actions-clipboard'));
496  if (($this->‪getBackendUser()->getTSConfig()['options.']['file_list.']['displayColumnSelector'] ?? true)
497  && $this->moduleData->get('viewMode') === ‪ViewMode::LIST->value) {
498  $viewModeItems[] = GeneralUtility::makeInstance(DropDownDivider::class);
499  $viewModeItems[] = GeneralUtility::makeInstance(DropDownItem::class)
500  ->setTag('typo3-backend-column-selector-button')
501  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.selectColumns'))
502  ->setAttributes([
503  'data-url' => $this->uriBuilder->buildUriFromRoute(
504  'ajax_show_columns_selector',
505  ['id' => $this->id, 'table' => '_FILE']
506  ),
507  'data-target' => $this->filelist->createModuleUri(),
508  'data-title' => sprintf(
509  $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:showColumnsSelection'),
510  $lang->sL(‪$GLOBALS['TCA']['sys_file']['ctrl']['title'] ?? ''),
511  ),
512  'data-button-ok' => $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:updateColumnView'),
513  'data-button-close' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel'),
514  'data-error-message' => $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:updateColumnView.error'),
515  ])
516  ->setIcon($this->iconFactory->getIcon('actions-options'));
517  }
518  $viewModeButton = $buttonBar->makeDropDownButton()
519  ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view'))
520  ->setShowLabelText(true);
521  foreach ($viewModeItems as $viewModeItem) {
522  $viewModeButton->addItem($viewModeItem);
523  }
524  $buttonBar->addButton($viewModeButton, ‪ButtonBar::BUTTON_POSITION_RIGHT, 2);
525 
526  // Level up
527  try {
528  $currentStorage = $this->folderObject->getStorage();
529  $parentFolder = $this->folderObject->getParentFolder();
530  if ($currentStorage->isWithinFileMountBoundaries($parentFolder)
531  && $parentFolder->getIdentifier() !== $this->folderObject->getIdentifier()
532  && $parentFolder instanceof ‪Folder
533  ) {
534  $levelUpButton = $buttonBar->makeLinkButton()
535  ->setDataAttributes([
536  'tree-update-request' => htmlspecialchars('folder' . ‪GeneralUtility::md5int($parentFolder->getCombinedIdentifier())),
537  ])
538  ->setHref(
539  (string)$this->uriBuilder->buildUriFromRoute(
540  'media_management',
541  ['id' => $parentFolder->getCombinedIdentifier()]
542  )
543  )
544  ->setShowLabelText(true)
545  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel'))
546  ->setIcon($this->iconFactory->getIcon('actions-view-go-up', IconSize::SMALL));
547  $buttonBar->addButton($levelUpButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 1);
548  }
549  } catch (\‪Exception $e) {
550  }
551 
552  // Shortcut
553  $shortCutButton = $buttonBar->makeShortcutButton()
554  ->setRouteIdentifier('media_management')
555  ->setDisplayName(sprintf(
556  '%s: %s',
557  $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'),
558  $this->folderObject->getName() ?: $this->folderObject->getIdentifier()
559  ))
560  ->setArguments(array_filter([
561  'id' => $this->id,
562  'searchTerm' => $this->searchTerm,
563  ]));
564  $buttonBar->addButton($shortCutButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
565 
566  // Upload button (only if upload to this directory is allowed)
567  if ($this->folderObject
568  && $this->folderObject->checkActionPermission('write')
569  && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
570  ) {
571  $uploadButton = $buttonBar->makeLinkButton()
572  ->setHref($this->‪getFileUploadUrl())
573  ->setClasses('t3js-drag-uploader-trigger')
574  ->setShowLabelText(true)
575  ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload'))
576  ->setIcon($this->iconFactory->getIcon('actions-edit-upload', IconSize::SMALL));
577  $buttonBar->addButton($uploadButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 2);
578  }
579 
580  // New folder button
581  if ($this->folderObject && $this->folderObject->checkActionPermission('write') && $this->folderObject->checkActionPermission('add')) {
582  $newButton = $buttonBar->makeLinkButton()
583  ->setClasses('t3js-element-browser')
584  ->setHref((string)$this->uriBuilder->buildUriFromRoute('wizard_element_browser'))
585  ->setDataAttributes([
586  'identifier' => $this->folderObject->getCombinedIdentifier(),
588  ])
589  ->setShowLabelText(true)
590  ->setTitle($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:actions.create_folder'))
591  ->setIcon($this->iconFactory->getIcon('actions-folder-add', IconSize::SMALL));
592  $buttonBar->addButton($newButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 3);
593  }
594 
595  // New file button
596  if ($this->folderObject && $this->folderObject->checkActionPermission('write')
597  && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
598  ) {
599  $newButton = $buttonBar->makeLinkButton()
600  ->setHref((string)$this->uriBuilder->buildUriFromRoute(
601  'file_create',
602  [
603  'target' => $this->folderObject->getCombinedIdentifier(),
604  'returnUrl' => $this->filelist->createModuleUri(),
605  ]
606  ))
607  ->setShowLabelText(true)
608  ->setTitle($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:actions.create_file'))
609  ->setIcon($this->iconFactory->getIcon('actions-file-add', IconSize::SMALL));
610  $buttonBar->addButton($newButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 4);
611  }
612 
613  // Add paste button if clipboard is initialized
614  if ($this->filelist->clipObj instanceof ‪Clipboard && $this->folderObject->checkActionPermission('write')) {
615  $elFromTable = $this->filelist->clipObj->elFromTable('_FILE');
616  if (!empty($elFromTable)) {
617  $addPasteButton = true;
618  $elToConfirm = [];
619  foreach ($elFromTable as $key => $element) {
620  $clipBoardElement = $this->resourceFactory->retrieveFileOrFolderObject($element);
621  if ($clipBoardElement instanceof ‪Folder && $clipBoardElement->‪getStorage()->isWithinFolder(
622  $clipBoardElement,
623  $this->folderObject
624  )
625  ) {
626  $addPasteButton = false;
627  }
628  $elToConfirm[$key] = $clipBoardElement->getName();
629  }
630  if ($addPasteButton) {
631  $confirmText = $this->filelist->clipObj
632  ->confirmMsgText('_FILE', $this->folderObject->getReadablePath(), 'into', $elToConfirm);
633  $pastButtonTitle = $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_paste');
634  $pasteButton = $buttonBar->makeLinkButton()
635  ->setHref($this->filelist->clipObj
636  ->pasteUrl('_FILE', $this->folderObject->getCombinedIdentifier()))
637  ->setClasses('t3js-modal-trigger')
638  ->setDataAttributes([
639  'severity' => 'warning',
640  'bs-content' => $confirmText,
641  'title' => $pastButtonTitle,
642  ])
643  ->setShowLabelText(true)
644  ->setTitle($pastButtonTitle)
645  ->setIcon($this->iconFactory->getIcon('actions-document-paste-into', IconSize::SMALL));
646  $buttonBar->addButton($pasteButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 10);
647  }
648  }
649  }
650  }
651 
656  protected function ‪getModuleHeadline(): string
657  {
658  $name = $this->folderObject->getName();
659  if ($name === '') {
660  // Show storage name on storage root
661  if ($this->folderObject->getIdentifier() === '/') {
662  $name = $this->folderObject->getStorage()->getName();
663  }
664  } else {
665  $name = key(ListUtility::resolveSpecialFolderNames(
666  [$name => $this->folderObject]
667  ));
668  }
669  return (string)$name;
670  }
671 
675  protected function ‪htmlResponse(string $html): ResponseInterface
676  {
677  $response = $this->responseFactory
678  ->createResponse()
679  ->withHeader('Content-Type', 'text/html; charset=utf-8');
680 
681  $response->getBody()->write($html);
682  return $response;
683  }
684 
688  protected function ‪addFlashMessage(string $message, string $title = '', ‪ContextualFeedbackSeverity $severity = ContextualFeedbackSeverity::INFO): void
689  {
690  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $message, $title, $severity, true);
691  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
692  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
693  $defaultFlashMessageQueue->enqueue($flashMessage);
694  }
695 
699  protected function ‪getFileUploadUrl(): string
700  {
701  return (string)$this->uriBuilder->buildUriFromRoute(
702  'file_upload',
703  [
704  'target' => $this->folderObject->getCombinedIdentifier(),
705  'returnUrl' => $this->filelist->createModuleUri(),
706  ]
707  );
708  }
709 
711  {
712  return ‪$GLOBALS['LANG'];
713  }
714 
716  {
717  return ‪$GLOBALS['BE_USER'];
718  }
719 }
‪TYPO3\CMS\Filelist\Controller\FileListController\getModuleHeadline
‪getModuleHeadline()
Definition: FileListController.php:656
‪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:699
‪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:710
‪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:75
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownRadio
Definition: DropDownRadio.php:54
‪TYPO3\CMS\Filelist\Controller\FileListController\htmlResponse
‪htmlResponse(string $html)
Definition: FileListController.php:675
‪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:61
‪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:715
‪TYPO3\CMS\Filelist\Controller\FileListController\addFlashMessage
‪addFlashMessage(string $message, string $title='', ContextualFeedbackSeverity $severity=ContextualFeedbackSeverity::INFO)
Definition: FileListController.php:688
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:128
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪TYPO3\CMS\Filelist\Controller\FileListController\registerFileListCheckboxes
‪registerFileListCheckboxes()
Definition: FileListController.php:444
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Filelist\Controller\FileListController\registerDragUploader
‪registerDragUploader()
Definition: FileListController.php:418
‪TYPO3\CMS\Filelist\Controller\FileListController\registerAdditionalDocHeaderButtons
‪registerAdditionalDocHeaderButtons(ServerRequestInterface $request)
Definition: FileListController.php:459
‪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