Passed
Push — master ( ff1a76...9dbd27 )
by
unknown
13:17
created

FileListController::getShortcutTitle()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 1
nop 0
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\Controller;
17
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Log\LoggerAwareInterface;
20
use Psr\Log\LoggerAwareTrait;
21
use TYPO3\CMS\Backend\Clipboard\Clipboard;
22
use TYPO3\CMS\Backend\Routing\UriBuilder;
23
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
24
use TYPO3\CMS\Backend\Utility\BackendUtility;
25
use TYPO3\CMS\Backend\View\BackendTemplateView;
26
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
27
use TYPO3\CMS\Core\Imaging\Icon;
28
use TYPO3\CMS\Core\Imaging\IconFactory;
29
use TYPO3\CMS\Core\Localization\LanguageService;
30
use TYPO3\CMS\Core\Messaging\FlashMessage;
31
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
32
use TYPO3\CMS\Core\Resource\Exception;
33
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
34
use TYPO3\CMS\Core\Resource\FileRepository;
35
use TYPO3\CMS\Core\Resource\Folder;
36
use TYPO3\CMS\Core\Resource\ResourceFactory;
37
use TYPO3\CMS\Core\Resource\ResourceStorage;
38
use TYPO3\CMS\Core\Resource\Search\FileSearchDemand;
39
use TYPO3\CMS\Core\Resource\StorageRepository;
40
use TYPO3\CMS\Core\Resource\Utility\ListUtility;
41
use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
42
use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
43
use TYPO3\CMS\Core\Utility\GeneralUtility;
44
use TYPO3\CMS\Core\Utility\MathUtility;
45
use TYPO3\CMS\Extbase\Http\ForwardResponse;
46
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
47
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
48
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
49
use TYPO3\CMS\Filelist\Configuration\ThumbnailConfiguration;
50
use TYPO3\CMS\Filelist\FileFacade;
51
use TYPO3\CMS\Filelist\FileList;
52
53
/**
54
 * Script Class for creating the list of files in the File > Filelist module
55
 * @internal this is a concrete TYPO3 controller implementation and solely used for EXT:filelist and not part of TYPO3's Core API.
56
 */
57
class FileListController extends ActionController implements LoggerAwareInterface
58
{
59
    use LoggerAwareTrait;
60
61
    public const UPLOAD_ACTION_REPLACE = 'replace';
62
    public const UPLOAD_ACTION_RENAME = 'rename';
63
    public const UPLOAD_ACTION_SKIP = 'cancel';
64
65
    /**
66
     * @var array
67
     */
68
    protected $MOD_MENU = [];
69
70
    /**
71
     * @var array
72
     */
73
    protected $MOD_SETTINGS = [];
74
75
    /**
76
     * "id" -> the path to list.
77
     *
78
     * @var string
79
     */
80
    protected $id;
81
82
    /**
83
     * @var Folder
84
     */
85
    protected $folderObject;
86
87
    /**
88
     * @var FlashMessage
89
     */
90
    protected $errorMessage;
91
92
    /**
93
     * Pointer to listing
94
     *
95
     * @var int
96
     */
97
    protected $pointer;
98
99
    /**
100
     * Thumbnail mode.
101
     *
102
     * @var string
103
     */
104
    protected $imagemode;
105
106
    /**
107
     * @var string
108
     */
109
    protected $cmd;
110
111
    /**
112
     * Defines behaviour when uploading files with names that already exist; possible values are
113
     * the values of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration
114
     *
115
     * @var \TYPO3\CMS\Core\Resource\DuplicationBehavior
116
     */
117
    protected $overwriteExistingFiles;
118
119
    /**
120
     * The filelist object
121
     *
122
     * @var FileList
123
     */
124
    protected $filelist;
125
126
    /**
127
     * The name of the module
128
     *
129
     * @var string
130
     */
131
    protected $moduleName = 'file_list';
132
133
    /**
134
     * @var \TYPO3\CMS\Core\Resource\FileRepository
135
     */
136
    protected $fileRepository;
137
138
    /**
139
     * @var BackendTemplateView
140
     */
141
    protected $view;
142
143
    /**
144
     * BackendTemplateView Container
145
     *
146
     * @var string
147
     */
148
    protected $defaultViewObjectName = BackendTemplateView::class;
149
150
    /**
151
     * @param \TYPO3\CMS\Core\Resource\FileRepository $fileRepository
152
     */
153
    public function injectFileRepository(FileRepository $fileRepository)
154
    {
155
        $this->fileRepository = $fileRepository;
156
    }
157
158
    /**
159
     * Initialize variables, file object
160
     * Incoming GET vars include id, pointer, table, imagemode
161
     *
162
     * @throws \RuntimeException
163
     */
164
    public function initializeObject()
165
    {
166
        $this->getLanguageService()->includeLLFile('EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf');
167
        $this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
168
169
        // Setting GPvars:
170
        $this->id = ($combinedIdentifier = GeneralUtility::_GP('id'));
171
        $this->pointer = GeneralUtility::_GP('pointer');
172
        $this->imagemode = GeneralUtility::_GP('imagemode');
173
        $this->cmd = GeneralUtility::_GP('cmd');
174
        $this->overwriteExistingFiles = DuplicationBehavior::cast(GeneralUtility::_GP('overwriteExistingFiles'));
175
176
        try {
177
            if ($combinedIdentifier) {
178
                $this->getBackendUser()->evaluateUserSpecificFileFilterSettings();
179
                $storage = GeneralUtility::makeInstance(StorageRepository::class)->findByCombinedIdentifier($combinedIdentifier);
180
                $identifier = substr($combinedIdentifier, strpos($combinedIdentifier, ':') + 1);
181
                if (!$storage->hasFolder($identifier)) {
182
                    $identifier = $storage->getFolderIdentifierFromFileIdentifier($identifier);
183
                }
184
                $this->folderObject = $storage->getFolder($identifier);
185
                // Disallow access to fallback storage 0
186
                if ($storage->getUid() === 0) {
187
                    throw new InsufficientFolderAccessPermissionsException(
188
                        'You are not allowed to access files outside your storages',
189
                        1434539815
190
                    );
191
                }
192
                // Disallow the rendering of the processing folder (e.g. could be called manually)
193
                if ($this->folderObject && $storage->isProcessingFolder($this->folderObject)) {
194
                    $this->folderObject = $storage->getRootLevelFolder();
195
                }
196
            } else {
197
                // Take the first object of the first storage
198
                $fileStorages = $this->getBackendUser()->getFileStorages();
199
                $fileStorage = reset($fileStorages);
200
                if ($fileStorage) {
201
                    $this->folderObject = $fileStorage->getRootLevelFolder();
202
                } else {
203
                    throw new \RuntimeException('Could not find any folder to be displayed.', 1349276894);
204
                }
205
            }
206
207
            if ($this->folderObject && !$this->folderObject->getStorage()->isWithinFileMountBoundaries($this->folderObject)) {
208
                throw new \RuntimeException('Folder not accessible.', 1430409089);
209
            }
210
        } catch (InsufficientFolderAccessPermissionsException $permissionException) {
211
            $this->folderObject = null;
212
            $this->errorMessage = GeneralUtility::makeInstance(
213
                FlashMessage::class,
214
                sprintf(
215
                    $this->getLanguageService()->getLL('missingFolderPermissionsMessage'),
216
                    $this->id
217
                ),
218
                $this->getLanguageService()->getLL('missingFolderPermissionsTitle'),
219
                FlashMessage::NOTICE
220
            );
221
        } catch (Exception $fileException) {
222
            // Set folder object to null and throw a message later on
223
            $this->folderObject = null;
224
            // Take the first object of the first storage
225
            $fileStorages = $this->getBackendUser()->getFileStorages();
226
            $fileStorage = reset($fileStorages);
227
            if ($fileStorage instanceof ResourceStorage) {
228
                $this->folderObject = $fileStorage->getRootLevelFolder();
229
                if (!$fileStorage->isWithinFileMountBoundaries($this->folderObject)) {
230
                    $this->folderObject = null;
231
                }
232
            }
233
            $this->errorMessage = GeneralUtility::makeInstance(
234
                FlashMessage::class,
235
                sprintf(
236
                    $this->getLanguageService()->getLL('folderNotFoundMessage'),
237
                    $this->id
238
                ),
239
                $this->getLanguageService()->getLL('folderNotFoundTitle'),
240
                FlashMessage::NOTICE
241
            );
242
        } catch (\RuntimeException $e) {
243
            $this->folderObject = null;
244
            $this->errorMessage = GeneralUtility::makeInstance(
245
                FlashMessage::class,
246
                $e->getMessage() . ' (' . $e->getCode() . ')',
247
                $this->getLanguageService()->getLL('folderNotFoundTitle'),
248
                FlashMessage::NOTICE
249
            );
250
        }
251
252
        if ($this->folderObject && !$this->folderObject->getStorage()->checkFolderActionPermission(
253
            'read',
254
            $this->folderObject
255
        )
256
        ) {
257
            $this->folderObject = null;
258
        }
259
260
        // Configure the "menu" - which is used internally to save the values of sorting, displayThumbs etc.
261
        $this->menuConfig();
262
    }
263
264
    /**
265
     * Setting the menu/session variables
266
     */
267
    protected function menuConfig()
268
    {
269
        // MENU-ITEMS:
270
        // If array, then it's a selector box menu
271
        // If empty string it's just a variable, that will be saved.
272
        // Values NOT in this array will not be saved in the settings-array for the module.
273
        $this->MOD_MENU = [
274
            'sort' => '',
275
            'reverse' => '',
276
            'displayThumbs' => '',
277
            'clipBoard' => '',
278
            'bigControlPanel' => ''
279
        ];
280
        // CLEANSE SETTINGS
281
        $this->MOD_SETTINGS = BackendUtility::getModuleData(
282
            $this->MOD_MENU,
283
            GeneralUtility::_GP('SET'),
284
            $this->moduleName
285
        );
286
    }
287
288
    /**
289
     * Initialize the view
290
     *
291
     * @param ViewInterface $view The view
292
     */
293
    protected function initializeView(ViewInterface $view)
294
    {
295
        /** @var BackendTemplateView $view */
296
        parent::initializeView($view);
297
        $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
298
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileListLocalisation');
299
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileList');
300
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileSearch');
301
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
302
        $this->registerDocHeaderButtons();
303
        if ($this->folderObject instanceof Folder) {
0 ignored issues
show
introduced by
$this->folderObject is always a sub-type of TYPO3\CMS\Core\Resource\Folder.
Loading history...
304
            $view->assign(
305
                'currentFolderHash',
306
                'folder' . GeneralUtility::md5int($this->folderObject->getCombinedIdentifier())
307
            );
308
        }
309
        $view->assign('currentIdentifier', $this->id);
310
    }
311
312
    protected function initializeIndexAction()
313
    {
314
        // Apply predefined values for hidden checkboxes
315
        // Set predefined value for DisplayBigControlPanel:
316
        $backendUser = $this->getBackendUser();
317
        $userTsConfig = $backendUser->getTSConfig();
318
        if (($userTsConfig['options.']['file_list.']['enableDisplayBigControlPanel'] ?? '') === 'activated') {
319
            $this->MOD_SETTINGS['bigControlPanel'] = true;
320
        } elseif (($userTsConfig['options.']['file_list.']['enableDisplayBigControlPanel'] ?? '') === 'deactivated') {
321
            $this->MOD_SETTINGS['bigControlPanel'] = false;
322
        }
323
        // Set predefined value for DisplayThumbnails:
324
        if (($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'activated') {
325
            $this->MOD_SETTINGS['displayThumbs'] = true;
326
        } elseif (($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'deactivated') {
327
            $this->MOD_SETTINGS['displayThumbs'] = false;
328
        }
329
        // Set predefined value for Clipboard:
330
        if (($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'activated') {
331
            $this->MOD_SETTINGS['clipBoard'] = true;
332
        } elseif (($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'deactivated') {
333
            $this->MOD_SETTINGS['clipBoard'] = false;
334
        }
335
        if (!isset($this->MOD_SETTINGS['sort'])) {
336
            // Set default sorting
337
            $this->MOD_SETTINGS['sort'] = 'file';
338
            $this->MOD_SETTINGS['reverse'] = 0;
339
        }
340
    }
341
342
    protected function indexAction(): ResponseInterface
343
    {
344
        $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
345
        $pageRenderer->setTitle($this->getLanguageService()->getLL('files'));
346
347
        // There there was access to this file path, continue, make the list
348
        if ($this->folderObject) {
349
            $this->initClipboard();
350
            $userTsConfig = $this->getBackendUser()->getTSConfig();
351
            $this->filelist = GeneralUtility::makeInstance(FileList::class);
352
            $this->filelist->thumbs = $GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && $this->MOD_SETTINGS['displayThumbs'];
353
            $CB = GeneralUtility::_GET('CB');
354
            if ($this->cmd === 'setCB') {
355
                $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(
356
                    GeneralUtility::_POST('CBH'),
0 ignored issues
show
Bug introduced by
TYPO3\CMS\Core\Utility\G...alUtility::_POST('CBH') of type null|string is incompatible with the type array expected by parameter $array1 of array_merge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

356
                    /** @scrutinizer ignore-type */ GeneralUtility::_POST('CBH'),
Loading history...
357
                    (array)GeneralUtility::_POST('CBC')
358
                ), '_FILE');
359
            }
360
            if (!$this->MOD_SETTINGS['clipBoard']) {
361
                $CB['setP'] = 'normal';
362
            }
363
            $this->filelist->clipObj->setCmd($CB);
364
            $this->filelist->clipObj->cleanCurrent();
365
            // Saves
366
            $this->filelist->clipObj->endClipboard();
367
368
            // If the "cmd" was to delete files from the list (clipboard thing), do that:
369
            if ($this->cmd === 'delete') {
370
                $items = $this->filelist->clipObj->cleanUpCBC(GeneralUtility::_POST('CBC'), '_FILE', 1);
371
                if (!empty($items)) {
372
                    // Make command array:
373
                    $FILE = [];
374
                    foreach ($items as $clipboardIdentifier => $combinedIdentifier) {
375
                        $FILE['delete'][] = ['data' => $combinedIdentifier];
376
                        $this->filelist->clipObj->removeElement($clipboardIdentifier);
377
                    }
378
                    // Init file processing object for deleting and pass the cmd array.
379
                    /** @var ExtendedFileUtility $fileProcessor */
380
                    $fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
381
                    $fileProcessor->setActionPermissions();
382
                    $fileProcessor->setExistingFilesConflictMode($this->overwriteExistingFiles);
383
                    $fileProcessor->start($FILE);
384
                    $fileProcessor->processData();
385
                    // Clean & Save clipboard state
386
                    $this->filelist->clipObj->cleanCurrent();
387
                    $this->filelist->clipObj->endClipboard();
388
                }
389
            }
390
            // Start up filelisting object, include settings.
391
            $this->filelist->start(
392
                $this->folderObject,
393
                MathUtility::forceIntegerInRange($this->pointer, 0, 100000),
394
                $this->MOD_SETTINGS['sort'],
395
                (bool)$this->MOD_SETTINGS['reverse'],
396
                (bool)$this->MOD_SETTINGS['clipBoard'],
397
                (bool)$this->MOD_SETTINGS['bigControlPanel']
398
            );
399
            // Generate the list, if accessible
400
            if ($this->folderObject->getStorage()->isBrowsable()) {
401
                $this->view->assign('listHtml', $this->filelist->getTable());
402
            } else {
403
                $this->addFlashMessage(
404
                    $this->getLanguageService()->getLL('storageNotBrowsableMessage'),
405
                    $this->getLanguageService()->getLL('storageNotBrowsableTitle'),
406
                    FlashMessage::INFO
407
                );
408
            }
409
410
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClipboardComponent');
411
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete');
412
            $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons');
413
414
            // Include DragUploader only if we have write access
415
            if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
416
                && $this->folderObject->checkActionPermission('write')
417
            ) {
418
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DragUploader');
419
                $pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_upload');
420
                $pageRenderer->addInlineLanguageLabelArray([
421
                    'permissions.read' => $this->getLanguageService()->getLL('read'),
422
                    'permissions.write' => $this->getLanguageService()->getLL('write'),
423
                ]);
424
            }
425
426
            // Setting up the buttons
427
            $this->registerButtons();
428
429
            $pageRecord = [
430
                '_additional_info' => $this->filelist->getFolderInfo(),
431
                'combined_identifier' => $this->folderObject->getCombinedIdentifier(),
432
            ];
433
            $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
434
435
            $this->view->assign('headline', $this->getModuleHeadline());
436
437
            $this->view->assign('checkboxes', [
438
                'bigControlPanel' => [
439
                    'enabled' => ($userTsConfig['options.']['file_list.']['enableDisplayBigControlPanel'] ?? '') === 'selectable',
440
                    'label' => htmlspecialchars($this->getLanguageService()->getLL('bigControlPanel')),
441
                    'html' => BackendUtility::getFuncCheck(
442
                        $this->id,
443
                        'SET[bigControlPanel]',
444
                        $this->MOD_SETTINGS['bigControlPanel'] ?? '',
445
                        '',
446
                        '',
447
                        'id="bigControlPanel"'
448
                    ),
449
                ],
450
                'displayThumbs' => [
451
                    'enabled' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && ($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'selectable',
452
                    'label' => htmlspecialchars($this->getLanguageService()->getLL('displayThumbs')),
453
                    'html' => BackendUtility::getFuncCheck(
454
                        $this->id,
455
                        'SET[displayThumbs]',
456
                        $this->MOD_SETTINGS['displayThumbs'] ?? '',
457
                        '',
458
                        '',
459
                        'id="checkDisplayThumbs"'
460
                    ),
461
                ],
462
                'enableClipBoard' => [
463
                    'enabled' => ($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'selectable',
464
                    'label' => htmlspecialchars($this->getLanguageService()->getLL('clipBoard')),
465
                    'html' => BackendUtility::getFuncCheck(
466
                        $this->id,
467
                        'SET[clipBoard]',
468
                        $this->MOD_SETTINGS['clipBoard'] ?? '',
469
                        '',
470
                        '',
471
                        'id="checkClipBoard"'
472
                    ),
473
                ]
474
            ]);
475
            $this->view->assign('showClipBoard', (bool)$this->MOD_SETTINGS['clipBoard']);
476
            $this->view->assign('clipBoardHtml', $this->filelist->clipObj->printClipboard());
477
            $this->view->assign('folderIdentifier', $this->folderObject->getCombinedIdentifier());
478
            $this->view->assign('fileDenyPattern', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern']);
479
            $this->view->assign('maxFileSize', GeneralUtility::getMaxUploadFileSize() * 1024);
480
            $this->view->assign('defaultAction', $this->getDefaultAction());
481
            $this->buildListOptionCheckboxes();
482
        } else {
483
            return new ForwardResponse('missingFolder');
484
        }
485
486
        return $this->htmlResponse($this->view->render());
487
    }
488
489
    protected function getDefaultAction(): string
490
    {
491
        $defaultAction = $this->getBackendUser()->getTSConfig()
492
            ['options.']['file_list.']['uploader.']['defaultAction'] ?? '';
493
494
        if ($defaultAction === '') {
495
            $defaultAction = self::UPLOAD_ACTION_SKIP;
496
        }
497
        if (!in_array($defaultAction, [
498
            self::UPLOAD_ACTION_REPLACE,
499
            self::UPLOAD_ACTION_RENAME,
500
            self::UPLOAD_ACTION_SKIP
501
        ], true)) {
502
            $this->logger->warning(sprintf(
503
                'TSConfig: options.file_list.uploader.defaultAction contains an invalid value ("%s"), fallback to default value: "%s"',
504
                $defaultAction,
505
                self::UPLOAD_ACTION_SKIP
506
            ));
507
            $defaultAction = self::UPLOAD_ACTION_SKIP;
508
        }
509
        return $defaultAction;
510
    }
511
512
    protected function missingFolderAction(): ResponseInterface
513
    {
514
        if ($this->errorMessage) {
515
            $this->errorMessage->setSeverity(FlashMessage::ERROR);
516
            $this->getFlashMessageQueue('core.template.flashMessages')->addMessage($this->errorMessage);
517
        }
518
519
        return $this->htmlResponse($this->view->render());
520
    }
521
522
    /**
523
     * Search for files by name and pass them with a facade to fluid
524
     *
525
     * @param string $searchWord
526
     */
527
    protected function searchAction($searchWord = ''): ResponseInterface
528
    {
529
        if (empty($searchWord)) {
530
            return new ForwardResponse('index');
531
        }
532
        $searchDemand = FileSearchDemand::createForSearchTerm($searchWord)->withRecursive();
533
        $files = $this->folderObject->searchFiles($searchDemand);
534
535
        $fileFacades = [];
536
        if (count($files) === 0) {
537
            $this->getFlashMessageQueue('core.template.flashMessages')->addMessage(
538
                new FlashMessage(
539
                    LocalizationUtility::translate('flashmessage.no_results', 'filelist') ?? '',
540
                    '',
541
                    FlashMessage::INFO
542
                )
543
            );
544
        } else {
545
            foreach ($files as $file) {
546
                $fileFacades[] = new FileFacade($file);
547
            }
548
        }
549
550
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
551
552
        $thumbnailConfiguration = GeneralUtility::makeInstance(ThumbnailConfiguration::class);
553
        $this->view->assign('thumbnail', [
554
            'width' => $thumbnailConfiguration->getWidth(),
555
            'height' => $thumbnailConfiguration->getHeight(),
556
        ]);
557
558
        $this->view->assign('searchWord', $searchWord);
559
        $this->view->assign('files', $fileFacades);
560
        $this->view->assign('deleteUrl', (string)$uriBuilder->buildUriFromRoute('tce_file'));
561
        $this->view->assign('settings', [
562
            'jsConfirmationDelete' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE)
563
        ]);
564
        $this->view->assign('moduleSettings', $this->MOD_SETTINGS);
565
566
        $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
567
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete');
568
        $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons');
569
570
        $this->initClipboard();
571
        $this->buildListOptionCheckboxes($searchWord);
572
573
        return $this->htmlResponse($this->view->render());
574
    }
575
576
    /**
577
     * Get main headline based on active folder or storage for backend module
578
     * Folder names are resolved to their special names like done in the tree view.
579
     *
580
     * @return string
581
     */
582
    protected function getModuleHeadline()
583
    {
584
        $name = $this->folderObject->getName();
585
        if ($name === '') {
586
            // Show storage name on storage root
587
            if ($this->folderObject->getIdentifier() === '/') {
588
                $name = $this->folderObject->getStorage()->getName();
589
            }
590
        } else {
591
            $name = key(ListUtility::resolveSpecialFolderNames(
592
                [$name => $this->folderObject]
593
            ));
594
        }
595
        return $name;
596
    }
597
598
    /**
599
     * Registers the Icons into the docheader
600
     *
601
     * @throws \InvalidArgumentException
602
     */
603
    protected function registerDocHeaderButtons()
604
    {
605
        /** @var ButtonBar $buttonBar */
606
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
607
608
        // CSH
609
        $cshButton = $buttonBar->makeHelpButton()
610
            ->setModuleName('xMOD_csh_corebe')
611
            ->setFieldName('filelist_module');
612
        $buttonBar->addButton($cshButton);
613
    }
614
615
    /**
616
     * Create the panel of buttons for submitting the form or otherwise perform operations.
617
     */
618
    protected function registerButtons()
619
    {
620
        /** @var ButtonBar $buttonBar */
621
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
622
623
        /** @var IconFactory $iconFactory */
624
        $iconFactory = $this->view->getModuleTemplate()->getIconFactory();
625
626
        $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
627
628
        $lang = $this->getLanguageService();
629
630
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
631
632
        // Refresh page
633
        $refreshLink = GeneralUtility::linkThisScript(
634
            [
635
                'target' => rawurlencode($this->folderObject->getCombinedIdentifier()),
636
                'imagemode' => $this->filelist->thumbs
637
            ]
638
        );
639
        $refreshButton = $buttonBar->makeLinkButton()
640
            ->setHref($refreshLink)
641
            ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
642
            ->setIcon($iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL));
643
        $buttonBar->addButton($refreshButton, ButtonBar::BUTTON_POSITION_RIGHT);
644
645
        // Level up
646
        try {
647
            $currentStorage = $this->folderObject->getStorage();
648
            $parentFolder = $this->folderObject->getParentFolder();
649
            if ($parentFolder->getIdentifier() !== $this->folderObject->getIdentifier()
650
                && $currentStorage->isWithinFileMountBoundaries($parentFolder)
651
            ) {
652
                $levelUpButton = $buttonBar->makeLinkButton()
653
                    ->setDataAttributes([
654
                        'tree-update-request' => htmlspecialchars('folder' . GeneralUtility::md5int($parentFolder->getCombinedIdentifier())),
655
                    ])
656
                    ->setHref((string)$uriBuilder->buildUriFromRoute('file_FilelistList', ['id' => $parentFolder->getCombinedIdentifier()]))
657
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel'))
658
                    ->setIcon($iconFactory->getIcon('actions-view-go-up', Icon::SIZE_SMALL));
659
                $buttonBar->addButton($levelUpButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
660
            }
661
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
662
        }
663
664
        // Shortcut
665
        $shortCutButton = $buttonBar->makeShortcutButton()
666
            ->setModuleName('file_FilelistList')
667
            ->setDisplayName($this->getShortcutTitle())
668
            ->setArguments([
669
                'route' => GeneralUtility::_GP('route'),
670
                'id' => $this->id,
671
            ]);
672
        $buttonBar->addButton($shortCutButton, ButtonBar::BUTTON_POSITION_RIGHT);
673
674
        // Upload button (only if upload to this directory is allowed)
675
        if ($this->folderObject && $this->folderObject->getStorage()->checkUserActionPermission(
676
            'add',
677
            'File'
678
        ) && $this->folderObject->checkActionPermission('write')
679
        ) {
680
            $uploadButton = $buttonBar->makeLinkButton()
681
                ->setHref((string)$uriBuilder->buildUriFromRoute(
682
                    'file_upload',
683
                    [
684
                        'target' => $this->folderObject->getCombinedIdentifier(),
685
                        'returnUrl' => $this->filelist->listURL(),
686
                    ]
687
                ))
688
                ->setClasses('t3js-drag-uploader-trigger')
689
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload'))
690
                ->setIcon($iconFactory->getIcon('actions-edit-upload', Icon::SIZE_SMALL));
691
            $buttonBar->addButton($uploadButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
692
        }
693
694
        // New folder button
695
        if ($this->folderObject && $this->folderObject->checkActionPermission('write')
696
            && ($this->folderObject->getStorage()->checkUserActionPermission(
697
                'add',
698
                'File'
699
            ) || $this->folderObject->checkActionPermission('add'))
700
        ) {
701
            $newButton = $buttonBar->makeLinkButton()
702
                ->setHref((string)$uriBuilder->buildUriFromRoute(
703
                    'file_newfolder',
704
                    [
705
                        'target' => $this->folderObject->getCombinedIdentifier(),
706
                        'returnUrl' => $this->filelist->listURL(),
707
                    ]
708
                ))
709
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.new'))
710
                ->setIcon($iconFactory->getIcon('actions-add', Icon::SIZE_SMALL));
711
            $buttonBar->addButton($newButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
712
        }
713
714
        // Add paste button if clipboard is initialized
715
        if ($this->filelist->clipObj instanceof Clipboard && $this->folderObject->checkActionPermission('write')) {
716
            $elFromTable = $this->filelist->clipObj->elFromTable('_FILE');
717
            if (!empty($elFromTable)) {
718
                $addPasteButton = true;
719
                $elToConfirm = [];
720
                foreach ($elFromTable as $key => $element) {
721
                    $clipBoardElement = $resourceFactory->retrieveFileOrFolderObject($element);
722
                    if ($clipBoardElement instanceof Folder && $clipBoardElement->getStorage()->isWithinFolder(
723
                        $clipBoardElement,
724
                        $this->folderObject
725
                    )
726
                    ) {
727
                        $addPasteButton = false;
728
                    }
729
                    $elToConfirm[$key] = $clipBoardElement->getName();
730
                }
731
                if ($addPasteButton) {
732
                    $confirmText = $this->filelist->clipObj
733
                        ->confirmMsgText('_FILE', $this->folderObject->getReadablePath(), 'into', $elToConfirm);
734
                    $pasteButton = $buttonBar->makeLinkButton()
735
                        ->setHref($this->filelist->clipObj
736
                            ->pasteUrl('_FILE', $this->folderObject->getCombinedIdentifier()))
737
                        ->setClasses('t3js-modal-trigger')
738
                        ->setDataAttributes([
739
                            'severity' => 'warning',
740
                            'content' => $confirmText,
741
                            'title' => $lang->getLL('clip_paste')
742
                        ])
743
                        ->setTitle($lang->getLL('clip_paste'))
744
                        ->setIcon($iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL));
745
                    $buttonBar->addButton($pasteButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
746
                }
747
            }
748
        }
749
    }
750
751
    /**
752
     * Returns an instance of LanguageService
753
     *
754
     * @return LanguageService
755
     */
756
    protected function getLanguageService(): LanguageService
757
    {
758
        return $GLOBALS['LANG'];
759
    }
760
761
    /**
762
     * Returns the current BE user.
763
     *
764
     * @return BackendUserAuthentication
765
     */
766
    protected function getBackendUser(): BackendUserAuthentication
767
    {
768
        return $GLOBALS['BE_USER'];
769
    }
770
771
    /**
772
     * build option checkboxes for filelist
773
     */
774
    protected function buildListOptionCheckboxes(string $searchWord = ''): void
775
    {
776
        $backendUser = $this->getBackendUser();
777
        $userTsConfig = $backendUser->getTSConfig();
778
779
        $addParams = '';
780
        if ($searchWord) {
781
            $addParams = '&tx_filelist_file_filelistlist%5Baction%5D=search';
782
            $addParams .= '&tx_filelist_file_filelistlist%5Bcontroller%5D=FileList';
783
            $addParams .= '&tx_filelist_file_filelistlist%5BsearchWord%5D=' . htmlspecialchars($searchWord);
784
        }
785
        $this->view->assign('checkboxes', [
786
            'bigControlPanel' => [
787
                'enabled' => $userTsConfig['options.']['file_list.']['enableDisplayBigControlPanel'] === 'selectable',
788
                'label' => htmlspecialchars($this->getLanguageService()->getLL('bigControlPanel')),
789
                'html' => BackendUtility::getFuncCheck(
790
                    $this->id,
791
                    'SET[bigControlPanel]',
792
                    $this->MOD_SETTINGS['bigControlPanel'] ?? '',
793
                    '',
794
                    $addParams,
795
                    'id="bigControlPanel"'
796
                ),
797
            ],
798
            'displayThumbs' => [
799
                'enabled' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && $userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] === 'selectable',
800
                'label' => htmlspecialchars($this->getLanguageService()->getLL('displayThumbs')),
801
                'html' => BackendUtility::getFuncCheck(
802
                    $this->id,
803
                    'SET[displayThumbs]',
804
                    $this->MOD_SETTINGS['displayThumbs'] ?? '',
805
                    '',
806
                    $addParams,
807
                    'id="checkDisplayThumbs"'
808
                ),
809
            ],
810
            'enableClipBoard' => [
811
                'enabled' => $userTsConfig['options.']['file_list.']['enableClipBoard'] === 'selectable',
812
                'label' => htmlspecialchars($this->getLanguageService()->getLL('clipBoard')),
813
                'html' => BackendUtility::getFuncCheck(
814
                    $this->id,
815
                    'SET[clipBoard]',
816
                    $this->MOD_SETTINGS['clipBoard'] ?? '',
817
                    '',
818
                    $addParams,
819
                    'id="checkClipBoard"'
820
                ),
821
            ]
822
        ]);
823
    }
824
825
    /**
826
     * init and assign clipboard to view
827
     */
828
    protected function initClipboard(): void
829
    {
830
        // Create fileListing object
831
        $this->filelist = GeneralUtility::makeInstance(FileList::class, $this);
832
        $this->filelist->thumbs = $GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && $this->MOD_SETTINGS['displayThumbs'];
833
        // Create clipboard object and initialize that
834
        $this->filelist->clipObj = GeneralUtility::makeInstance(Clipboard::class);
835
        $this->filelist->clipObj->fileMode = true;
836
        $this->filelist->clipObj->initializeClipboard();
837
        $CB = GeneralUtility::_GET('CB');
838
        if ($this->cmd === 'setCB') {
839
            $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(
840
                GeneralUtility::_POST('CBH'),
0 ignored issues
show
Bug introduced by
TYPO3\CMS\Core\Utility\G...alUtility::_POST('CBH') of type null|string is incompatible with the type array expected by parameter $array1 of array_merge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

840
                /** @scrutinizer ignore-type */ GeneralUtility::_POST('CBH'),
Loading history...
841
                (array)GeneralUtility::_POST('CBC')
842
            ), '_FILE');
843
        }
844
        if (!$this->MOD_SETTINGS['clipBoard']) {
845
            $CB['setP'] = 'normal';
846
        }
847
        $this->filelist->clipObj->setCmd($CB);
848
        $this->filelist->clipObj->cleanCurrent();
849
        // Saves
850
        $this->filelist->clipObj->endClipboard();
851
852
        $this->view->assign('showClipBoard', (bool)$this->MOD_SETTINGS['clipBoard']);
853
        $this->view->assign('clipBoardHtml', $this->filelist->clipObj->printClipboard());
854
    }
855
856
    /**
857
     * Returns the shortcut title for the current folder object
858
     *
859
     * @return string
860
     */
861
    protected function getShortcutTitle(): string
862
    {
863
        return sprintf(
864
            '%s: %s',
865
            $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'),
866
            $this->folderObject->getName() ?: $this->folderObject->getIdentifier()
867
        );
868
    }
869
}
870