Passed
Push — master ( c9e6a5...ceebe9 )
by
unknown
43:14
created

FileListController::initializeIndexAction()   A

Complexity

Conditions 6
Paths 18

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 21
rs 9.2222
cc 6
nc 18
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|null
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');
0 ignored issues
show
Documentation Bug introduced by
It seems like TYPO3\CMS\Core\Utility\G...Utility::_GP('pointer') can also be of type string. However, the property $pointer is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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
        ];
279
        // CLEANSE SETTINGS
280
        $this->MOD_SETTINGS = BackendUtility::getModuleData(
281
            $this->MOD_MENU,
282
            GeneralUtility::_GP('SET'),
0 ignored issues
show
Bug introduced by
It seems like TYPO3\CMS\Core\Utility\GeneralUtility::_GP('SET') can also be of type string; however, parameter $CHANGED_SETTINGS of TYPO3\CMS\Backend\Utilit...tility::getModuleData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

282
            /** @scrutinizer ignore-type */ GeneralUtility::_GP('SET'),
Loading history...
283
            $this->moduleName
284
        );
285
    }
286
287
    /**
288
     * Initialize the view
289
     *
290
     * @param ViewInterface $view The view
291
     */
292
    protected function initializeView(ViewInterface $view)
293
    {
294
        /** @var BackendTemplateView $view */
295
        parent::initializeView($view);
296
        $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
297
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileListLocalisation');
298
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileList');
299
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileSearch');
300
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
301
        $this->registerDocHeaderButtons();
302
        if ($this->folderObject instanceof Folder) {
303
            $view->assign(
304
                'currentFolderHash',
305
                'folder' . GeneralUtility::md5int($this->folderObject->getCombinedIdentifier())
306
            );
307
        }
308
        $view->assign('currentIdentifier', $this->id);
309
    }
310
311
    protected function initializeIndexAction()
312
    {
313
        // Apply predefined values for hidden checkboxes
314
        $backendUser = $this->getBackendUser();
315
        $userTsConfig = $backendUser->getTSConfig();
316
        // Set predefined value for DisplayThumbnails:
317
        if (($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'activated') {
318
            $this->MOD_SETTINGS['displayThumbs'] = true;
319
        } elseif (($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'deactivated') {
320
            $this->MOD_SETTINGS['displayThumbs'] = false;
321
        }
322
        // Set predefined value for Clipboard:
323
        if (($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'activated') {
324
            $this->MOD_SETTINGS['clipBoard'] = true;
325
        } elseif (($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'deactivated') {
326
            $this->MOD_SETTINGS['clipBoard'] = false;
327
        }
328
        if (!isset($this->MOD_SETTINGS['sort'])) {
329
            // Set default sorting
330
            $this->MOD_SETTINGS['sort'] = 'file';
331
            $this->MOD_SETTINGS['reverse'] = 0;
332
        }
333
    }
334
335
    protected function indexAction(): ResponseInterface
336
    {
337
        $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
338
        $pageRenderer->setTitle($this->getLanguageService()->getLL('files'));
339
340
        // There there was access to this file path, continue, make the list
341
        if ($this->folderObject) {
342
            $this->initClipboard();
343
            $userTsConfig = $this->getBackendUser()->getTSConfig();
344
            $this->filelist = GeneralUtility::makeInstance(FileList::class);
345
            $this->filelist->thumbs = ($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] ?? false) && ($this->MOD_SETTINGS['displayThumbs'] ?? false);
346
            $CB = GeneralUtility::_GET('CB');
347
            if ($this->cmd === 'setCB') {
348
                $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(
349
                    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 $arrays 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

349
                    /** @scrutinizer ignore-type */ GeneralUtility::_POST('CBH'),
Loading history...
350
                    (array)GeneralUtility::_POST('CBC')
351
                ), '_FILE');
352
            }
353
            if (!($this->MOD_SETTINGS['clipBoard'] ?? false)) {
354
                $CB['setP'] = 'normal';
355
            }
356
            $this->filelist->clipObj->setCmd($CB);
357
            $this->filelist->clipObj->cleanCurrent();
358
            // Saves
359
            $this->filelist->clipObj->endClipboard();
360
361
            // If the "cmd" was to delete files from the list (clipboard thing), do that:
362
            if ($this->cmd === 'delete') {
363
                $items = $this->filelist->clipObj->cleanUpCBC(GeneralUtility::_POST('CBC'), '_FILE', 1);
364
                if (!empty($items)) {
365
                    // Make command array:
366
                    $FILE = [];
367
                    foreach ($items as $clipboardIdentifier => $combinedIdentifier) {
368
                        $FILE['delete'][] = ['data' => $combinedIdentifier];
369
                        $this->filelist->clipObj->removeElement($clipboardIdentifier);
370
                    }
371
                    // Init file processing object for deleting and pass the cmd array.
372
                    /** @var ExtendedFileUtility $fileProcessor */
373
                    $fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
374
                    $fileProcessor->setActionPermissions();
375
                    $fileProcessor->setExistingFilesConflictMode($this->overwriteExistingFiles);
376
                    $fileProcessor->start($FILE);
377
                    $fileProcessor->processData();
378
                    // Clean & Save clipboard state
379
                    $this->filelist->clipObj->cleanCurrent();
380
                    $this->filelist->clipObj->endClipboard();
381
                }
382
            }
383
            // Start up filelisting object, include settings.
384
            $this->filelist->start(
385
                $this->folderObject,
386
                MathUtility::forceIntegerInRange($this->pointer, 0, 100000),
387
                $this->MOD_SETTINGS['sort'],
388
                (bool)($this->MOD_SETTINGS['reverse'] ?? false),
389
                (bool)($this->MOD_SETTINGS['clipBoard'] ?? false)
390
            );
391
            // Generate the list, if accessible
392
            if ($this->folderObject->getStorage()->isBrowsable()) {
393
                $this->view->assign('listHtml', $this->filelist->getTable());
394
            } else {
395
                $this->addFlashMessage(
396
                    $this->getLanguageService()->getLL('storageNotBrowsableMessage'),
397
                    $this->getLanguageService()->getLL('storageNotBrowsableTitle'),
398
                    FlashMessage::INFO
399
                );
400
            }
401
402
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClipboardComponent');
403
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete');
404
            $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons');
405
406
            // Include DragUploader only if we have write access
407
            if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
408
                && $this->folderObject->checkActionPermission('write')
409
            ) {
410
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DragUploader');
411
                $pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf', 'file_upload');
412
                $pageRenderer->addInlineLanguageLabelArray([
413
                    'permissions.read' => $this->getLanguageService()->getLL('read'),
414
                    'permissions.write' => $this->getLanguageService()->getLL('write'),
415
                ]);
416
            }
417
418
            // Setting up the buttons
419
            $this->registerButtons();
420
421
            $pageRecord = [
422
                '_additional_info' => $this->filelist->getFolderInfo(),
423
                'combined_identifier' => $this->folderObject->getCombinedIdentifier(),
424
            ];
425
            $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
426
427
            $this->view->assign('headline', $this->getModuleHeadline());
428
429
            $this->view->assign('checkboxes', [
430
                'displayThumbs' => [
431
                    'enabled' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && ($userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] ?? '') === 'selectable',
432
                    'label' => htmlspecialchars($this->getLanguageService()->getLL('displayThumbs')),
433
                    'html' => BackendUtility::getFuncCheck(
434
                        $this->id,
435
                        'SET[displayThumbs]',
436
                        $this->MOD_SETTINGS['displayThumbs'] ?? '',
437
                        '',
438
                        '',
439
                        'id="checkDisplayThumbs"'
440
                    ),
441
                ],
442
                'enableClipBoard' => [
443
                    'enabled' => ($userTsConfig['options.']['file_list.']['enableClipBoard'] ?? '') === 'selectable',
444
                    'label' => htmlspecialchars($this->getLanguageService()->getLL('clipBoard')),
445
                    'html' => BackendUtility::getFuncCheck(
446
                        $this->id,
447
                        'SET[clipBoard]',
448
                        $this->MOD_SETTINGS['clipBoard'] ?? '',
449
                        '',
450
                        '',
451
                        'id="checkClipBoard"'
452
                    ),
453
                ]
454
            ]);
455
            $this->view->assign('showClipBoard', (bool)($this->MOD_SETTINGS['clipBoard'] ?? false));
456
            $this->view->assign('clipBoardHtml', $this->filelist->clipObj->printClipboard());
457
            $this->view->assign('folderIdentifier', $this->folderObject->getCombinedIdentifier());
458
            $this->view->assign('fileDenyPattern', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] ?? null);
459
            $this->view->assign('maxFileSize', GeneralUtility::getMaxUploadFileSize() * 1024);
460
            $this->view->assign('defaultAction', $this->getDefaultAction());
461
            $this->buildListOptionCheckboxes();
462
            $this->view->getModuleTemplate()->setTitle(
463
                $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'),
464
                $this->getModuleHeadline()
465
            );
466
        } else {
467
            return new ForwardResponse('missingFolder');
468
        }
469
470
        return $this->htmlResponse();
471
    }
472
473
    protected function getDefaultAction(): string
474
    {
475
        $defaultAction = $this->getBackendUser()->getTSConfig()
476
            ['options.']['file_list.']['uploader.']['defaultAction'] ?? '';
477
478
        if ($defaultAction === '') {
479
            $defaultAction = self::UPLOAD_ACTION_SKIP;
480
        }
481
        if (!in_array($defaultAction, [
482
            self::UPLOAD_ACTION_REPLACE,
483
            self::UPLOAD_ACTION_RENAME,
484
            self::UPLOAD_ACTION_SKIP
485
        ], true)) {
486
            $this->logger->warning('TSConfig: options.file_list.uploader.defaultAction contains an invalid value ("{value}"), fallback to default value: "{default}"', [
0 ignored issues
show
Bug introduced by
The method warning() does not exist on null. ( Ignorable by Annotation )

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

486
            $this->logger->/** @scrutinizer ignore-call */ 
487
                           warning('TSConfig: options.file_list.uploader.defaultAction contains an invalid value ("{value}"), fallback to default value: "{default}"', [

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
487
                'value' => $defaultAction,
488
                'default' => self::UPLOAD_ACTION_SKIP
489
            ]);
490
            $defaultAction = self::UPLOAD_ACTION_SKIP;
491
        }
492
        return $defaultAction;
493
    }
494
495
    protected function missingFolderAction(): ResponseInterface
496
    {
497
        if ($this->errorMessage) {
498
            $this->errorMessage->setSeverity(FlashMessage::ERROR);
499
            $this->getFlashMessageQueue('core.template.flashMessages')->addMessage($this->errorMessage);
500
        }
501
502
        return $this->htmlResponse();
503
    }
504
505
    /**
506
     * Search for files by name and pass them with a facade to fluid
507
     *
508
     * @param string $searchWord
509
     */
510
    protected function searchAction($searchWord = ''): ResponseInterface
511
    {
512
        if (empty($searchWord)) {
513
            return new ForwardResponse('index');
514
        }
515
        $searchDemand = FileSearchDemand::createForSearchTerm($searchWord)->withRecursive();
516
        $files = $this->folderObject->searchFiles($searchDemand);
0 ignored issues
show
Bug introduced by
The method searchFiles() does not exist on null. ( Ignorable by Annotation )

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

516
        /** @scrutinizer ignore-call */ 
517
        $files = $this->folderObject->searchFiles($searchDemand);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
517
518
        $fileFacades = [];
519
        if (count($files) === 0) {
520
            $this->getFlashMessageQueue('core.template.flashMessages')->addMessage(
521
                new FlashMessage(
522
                    LocalizationUtility::translate('flashmessage.no_results', 'filelist') ?? '',
523
                    '',
524
                    FlashMessage::INFO
525
                )
526
            );
527
        } else {
528
            foreach ($files as $file) {
529
                $fileFacades[] = new FileFacade($file);
530
            }
531
        }
532
533
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
534
535
        $thumbnailConfiguration = GeneralUtility::makeInstance(ThumbnailConfiguration::class);
536
        $this->view->assign('thumbnail', [
537
            'width' => $thumbnailConfiguration->getWidth(),
538
            'height' => $thumbnailConfiguration->getHeight(),
539
        ]);
540
541
        $this->view->assign('searchWord', $searchWord);
542
        $this->view->assign('files', $fileFacades);
543
        $this->view->assign('deleteUrl', (string)$uriBuilder->buildUriFromRoute('tce_file'));
544
        $this->view->assign('settings', [
545
            'jsConfirmationDelete' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE)
546
        ]);
547
        $this->view->assign('moduleSettings', $this->MOD_SETTINGS);
548
549
        $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
550
        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete');
551
        $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons');
552
553
        $this->initClipboard();
554
        $this->buildListOptionCheckboxes($searchWord);
555
556
        return $this->htmlResponse();
557
    }
558
559
    /**
560
     * Get main headline based on active folder or storage for backend module
561
     * Folder names are resolved to their special names like done in the tree view.
562
     *
563
     * @return string
564
     */
565
    protected function getModuleHeadline()
566
    {
567
        $name = $this->folderObject->getName();
568
        if ($name === '') {
569
            // Show storage name on storage root
570
            if ($this->folderObject->getIdentifier() === '/') {
571
                $name = $this->folderObject->getStorage()->getName();
572
            }
573
        } else {
574
            $name = key(ListUtility::resolveSpecialFolderNames(
575
                [$name => $this->folderObject]
576
            ));
577
        }
578
        return $name;
579
    }
580
581
    /**
582
     * Registers the Icons into the docheader
583
     *
584
     * @throws \InvalidArgumentException
585
     */
586
    protected function registerDocHeaderButtons()
587
    {
588
        /** @var ButtonBar $buttonBar */
589
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
590
591
        // CSH
592
        $cshButton = $buttonBar->makeHelpButton()
593
            ->setModuleName('xMOD_csh_corebe')
594
            ->setFieldName('filelist_module');
595
        $buttonBar->addButton($cshButton);
596
    }
597
598
    /**
599
     * Create the panel of buttons for submitting the form or otherwise perform operations.
600
     */
601
    protected function registerButtons()
602
    {
603
        /** @var ButtonBar $buttonBar */
604
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
605
606
        /** @var IconFactory $iconFactory */
607
        $iconFactory = $this->view->getModuleTemplate()->getIconFactory();
608
609
        $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
610
611
        $lang = $this->getLanguageService();
612
613
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
614
615
        // Refresh page
616
        $refreshLink = GeneralUtility::linkThisScript(
617
            [
618
                'target' => rawurlencode($this->folderObject->getCombinedIdentifier()),
619
                'imagemode' => $this->filelist->thumbs
620
            ]
621
        );
622
        $refreshButton = $buttonBar->makeLinkButton()
623
            ->setHref($refreshLink)
624
            ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
625
            ->setIcon($iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL));
626
        $buttonBar->addButton($refreshButton, ButtonBar::BUTTON_POSITION_RIGHT);
627
628
        // Level up
629
        try {
630
            $currentStorage = $this->folderObject->getStorage();
631
            $parentFolder = $this->folderObject->getParentFolder();
632
            if ($parentFolder->getIdentifier() !== $this->folderObject->getIdentifier()
633
                && $currentStorage->isWithinFileMountBoundaries($parentFolder)
634
            ) {
635
                $levelUpButton = $buttonBar->makeLinkButton()
636
                    ->setDataAttributes([
637
                        'tree-update-request' => htmlspecialchars('folder' . GeneralUtility::md5int($parentFolder->getCombinedIdentifier())),
638
                    ])
639
                    ->setHref((string)$uriBuilder->buildUriFromRoute('file_FilelistList', ['id' => $parentFolder->getCombinedIdentifier()]))
640
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel'))
641
                    ->setIcon($iconFactory->getIcon('actions-view-go-up', Icon::SIZE_SMALL));
642
                $buttonBar->addButton($levelUpButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
643
            }
644
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
645
        }
646
647
        // Shortcut
648
        $shortCutButton = $buttonBar->makeShortcutButton()
649
            ->setRouteIdentifier('file_FilelistList')
650
            ->setDisplayName($this->getShortcutTitle())
651
            ->setArguments(['id' => $this->id]);
652
        $buttonBar->addButton($shortCutButton, ButtonBar::BUTTON_POSITION_RIGHT);
653
654
        // Upload button (only if upload to this directory is allowed)
655
        if ($this->folderObject && $this->folderObject->getStorage()->checkUserActionPermission(
656
            'add',
657
            'File'
658
        ) && $this->folderObject->checkActionPermission('write')
659
        ) {
660
            $uploadButton = $buttonBar->makeLinkButton()
661
                ->setHref((string)$uriBuilder->buildUriFromRoute(
662
                    'file_upload',
663
                    [
664
                        'target' => $this->folderObject->getCombinedIdentifier(),
665
                        'returnUrl' => $this->filelist->listURL(),
666
                    ]
667
                ))
668
                ->setClasses('t3js-drag-uploader-trigger')
669
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload'))
670
                ->setIcon($iconFactory->getIcon('actions-edit-upload', Icon::SIZE_SMALL));
671
            $buttonBar->addButton($uploadButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
672
        }
673
674
        // New folder button
675
        if ($this->folderObject && $this->folderObject->checkActionPermission('write')
676
            && ($this->folderObject->getStorage()->checkUserActionPermission(
677
                'add',
678
                'File'
679
            ) || $this->folderObject->checkActionPermission('add'))
680
        ) {
681
            $newButton = $buttonBar->makeLinkButton()
682
                ->setHref((string)$uriBuilder->buildUriFromRoute(
683
                    'file_newfolder',
684
                    [
685
                        'target' => $this->folderObject->getCombinedIdentifier(),
686
                        'returnUrl' => $this->filelist->listURL(),
687
                    ]
688
                ))
689
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.new'))
690
                ->setIcon($iconFactory->getIcon('actions-add', Icon::SIZE_SMALL));
691
            $buttonBar->addButton($newButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
692
        }
693
694
        // Add paste button if clipboard is initialized
695
        if ($this->filelist->clipObj instanceof Clipboard && $this->folderObject->checkActionPermission('write')) {
696
            $elFromTable = $this->filelist->clipObj->elFromTable('_FILE');
697
            if (!empty($elFromTable)) {
698
                $addPasteButton = true;
699
                $elToConfirm = [];
700
                foreach ($elFromTable as $key => $element) {
701
                    $clipBoardElement = $resourceFactory->retrieveFileOrFolderObject($element);
702
                    if ($clipBoardElement instanceof Folder && $clipBoardElement->getStorage()->isWithinFolder(
703
                        $clipBoardElement,
704
                        $this->folderObject
0 ignored issues
show
Bug introduced by
It seems like $this->folderObject can also be of type null; however, parameter $resource of TYPO3\CMS\Core\Resource\...orage::isWithinFolder() does only seem to accept TYPO3\CMS\Core\Resource\ResourceInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

704
                        /** @scrutinizer ignore-type */ $this->folderObject
Loading history...
705
                    )
706
                    ) {
707
                        $addPasteButton = false;
708
                    }
709
                    $elToConfirm[$key] = $clipBoardElement->getName();
710
                }
711
                if ($addPasteButton) {
712
                    $confirmText = $this->filelist->clipObj
713
                        ->confirmMsgText('_FILE', $this->folderObject->getReadablePath(), 'into', $elToConfirm);
714
                    $pasteButton = $buttonBar->makeLinkButton()
715
                        ->setHref($this->filelist->clipObj
716
                            ->pasteUrl('_FILE', $this->folderObject->getCombinedIdentifier()))
717
                        ->setClasses('t3js-modal-trigger')
718
                        ->setDataAttributes([
719
                            'severity' => 'warning',
720
                            'bs-content' => $confirmText,
721
                            'title' => $lang->getLL('clip_paste')
722
                        ])
723
                        ->setTitle($lang->getLL('clip_paste'))
724
                        ->setIcon($iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL));
725
                    $buttonBar->addButton($pasteButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
726
                }
727
            }
728
        }
729
    }
730
731
    /**
732
     * Returns an instance of LanguageService
733
     *
734
     * @return LanguageService
735
     */
736
    protected function getLanguageService(): LanguageService
737
    {
738
        return $GLOBALS['LANG'];
739
    }
740
741
    /**
742
     * Returns the current BE user.
743
     *
744
     * @return BackendUserAuthentication
745
     */
746
    protected function getBackendUser(): BackendUserAuthentication
747
    {
748
        return $GLOBALS['BE_USER'];
749
    }
750
751
    /**
752
     * build option checkboxes for filelist
753
     */
754
    protected function buildListOptionCheckboxes(string $searchWord = ''): void
755
    {
756
        $backendUser = $this->getBackendUser();
757
        $userTsConfig = $backendUser->getTSConfig();
758
759
        $addParams = '';
760
        if ($searchWord) {
761
            $addParams = '&tx_filelist_file_filelistlist%5Baction%5D=search';
762
            $addParams .= '&tx_filelist_file_filelistlist%5Bcontroller%5D=FileList';
763
            $addParams .= '&tx_filelist_file_filelistlist%5BsearchWord%5D=' . htmlspecialchars($searchWord);
764
        }
765
        $this->view->assign('checkboxes', [
766
            'displayThumbs' => [
767
                'enabled' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] && $userTsConfig['options.']['file_list.']['enableDisplayThumbnails'] === 'selectable',
768
                'label' => htmlspecialchars($this->getLanguageService()->getLL('displayThumbs')),
769
                'html' => BackendUtility::getFuncCheck(
770
                    $this->id,
771
                    'SET[displayThumbs]',
772
                    $this->MOD_SETTINGS['displayThumbs'] ?? '',
773
                    '',
774
                    $addParams,
775
                    'id="checkDisplayThumbs"'
776
                ),
777
            ],
778
            'enableClipBoard' => [
779
                'enabled' => $userTsConfig['options.']['file_list.']['enableClipBoard'] === 'selectable',
780
                'label' => htmlspecialchars($this->getLanguageService()->getLL('clipBoard')),
781
                'html' => BackendUtility::getFuncCheck(
782
                    $this->id,
783
                    'SET[clipBoard]',
784
                    $this->MOD_SETTINGS['clipBoard'] ?? '',
785
                    '',
786
                    $addParams,
787
                    'id="checkClipBoard"'
788
                ),
789
            ]
790
        ]);
791
    }
792
793
    /**
794
     * init and assign clipboard to view
795
     */
796
    protected function initClipboard(): void
797
    {
798
        // Create fileListing object
799
        $this->filelist = GeneralUtility::makeInstance(FileList::class, $this);
800
        $this->filelist->thumbs = ($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] ?? false) && ($this->MOD_SETTINGS['displayThumbs'] ?? false);
801
        // Create clipboard object and initialize that
802
        $this->filelist->clipObj = GeneralUtility::makeInstance(Clipboard::class);
803
        $this->filelist->clipObj->fileMode = true;
804
        $this->filelist->clipObj->initializeClipboard();
805
        $CB = GeneralUtility::_GET('CB');
806
        if ($this->cmd === 'setCB') {
807
            $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(
808
                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 $arrays 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

808
                /** @scrutinizer ignore-type */ GeneralUtility::_POST('CBH'),
Loading history...
809
                (array)GeneralUtility::_POST('CBC')
810
            ), '_FILE');
811
        }
812
        if (!($this->MOD_SETTINGS['clipBoard'] ?? false)) {
813
            $CB['setP'] = 'normal';
814
        }
815
        $this->filelist->clipObj->setCmd($CB);
816
        $this->filelist->clipObj->cleanCurrent();
817
        // Saves
818
        $this->filelist->clipObj->endClipboard();
819
820
        $this->view->assign('showClipBoard', (bool)($this->MOD_SETTINGS['clipBoard'] ?? false));
821
        $this->view->assign('clipBoardHtml', $this->filelist->clipObj->printClipboard());
822
    }
823
824
    /**
825
     * Returns the shortcut title for the current folder object
826
     *
827
     * @return string
828
     */
829
    protected function getShortcutTitle(): string
830
    {
831
        return sprintf(
832
            '%s: %s',
833
            $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:mlang_tabs_tab'),
834
            $this->folderObject->getName() ?: $this->folderObject->getIdentifier()
835
        );
836
    }
837
}
838