Passed
Push — master ( bf7994...5e2021 )
by Nicolaas
02:52
created

View::getDisplayer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Sunnysideup\AssetsOverview\Control;
4
5
use SilverStripe\CMS\Controllers\ContentController;
6
use SilverStripe\Control\Director;
7
use SilverStripe\Control\HTTPRequest;
8
use SilverStripe\Control\HTTPResponse;
9
use SilverStripe\Control\Middleware\HTTPCacheControlMiddleware;
10
use SilverStripe\Core\Environment;
11
use SilverStripe\Core\Flushable;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Forms\CheckboxField;
14
use SilverStripe\Forms\CheckboxSetField;
15
use SilverStripe\Forms\DropdownField;
16
use SilverStripe\Forms\FieldList;
17
use SilverStripe\Forms\Form;
18
use SilverStripe\Forms\FormAction;
19
use SilverStripe\Forms\HiddenField;
20
use SilverStripe\Forms\OptionsetField;
21
use SilverStripe\Forms\TextField;
22
use SilverStripe\ORM\ArrayList;
23
use SilverStripe\ORM\FieldType\DBField;
24
use SilverStripe\Security\Permission;
25
use SilverStripe\Security\Security;
26
use SilverStripe\Versioned\Versioned;
27
use SilverStripe\View\ArrayData;
28
use SilverStripe\View\Requirements;
29
use SilverStripe\View\SSViewer;
30
use Sunnysideup\AssetsOverview\Api\AddAndRemoveFromDb;
31
use Sunnysideup\AssetsOverview\Files\AllFilesInfo;
32
use Sunnysideup\AssetsOverview\Files\OneFileInfo;
33
use Sunnysideup\AssetsOverview\Traits\FilesystemRelatedTraits;
34
35
/**
36
 * Class \Sunnysideup\AssetsOverview\Control\View
37
 *
38
 * @property \Sunnysideup\AssetsOverview\Control\View $dataRecord
39
 * @method \Sunnysideup\AssetsOverview\Control\View data()
40
 * @mixin \Sunnysideup\AssetsOverview\Control\View
41
 */
42
class View extends ContentController implements Flushable
43
{
44
    use FilesystemRelatedTraits;
45
46
    public static function get_sorters()
47
    {
48
        return self::SORTERS;
49
    }
50
51
    public static function get_filters()
52
    {
53
        return self::FILTERS;
54
    }
55
56
    public static function get_displayers()
57
    {
58
        return self::DISPLAYERS;
59
    }
60
61
62
    protected static $allFilesProvider = null;
63
64
    /**
65
     * @var string
66
     */
67
    protected string $title = '';
68
69
70
    /**
71
     * @var int
72
     */
73
    protected int $limit = 1000;
74
75
    /**
76
     * @var int
77
     */
78
    protected int $startLimit = 0;
79
80
    /**
81
     * @var int
82
     */
83
    protected int $endLimit = 0;
84
85
    /**
86
     * @var int
87
     */
88
    protected int $pageNumber = 1;
89
90
    /**
91
     * @var bool
92
     */
93
    protected bool $dryRun = true;
94
95
    /**
96
     * @var string
97
     */
98
    protected string $sorter = 'byfolder';
99
100
    /**
101
     * @var string
102
     */
103
    protected string $filter = '';
104
105
    /**
106
     * @var string
107
     */
108
    protected string $displayer = 'thumbs';
109
110
    /**
111
     * @var array
112
     */
113
    protected array $allowedExtensions = [];
114
115
    /**
116
     * Defines methods that can be called directly.
117
     *
118
     * @var array
119
     */
120
    private static $allowed_actions = [
121
        'index' => 'ADMIN',
122
        'json' => 'ADMIN',
123
        'jsonfull' => 'ADMIN',
124
        'sync' => 'ADMIN',
125
        'addtodb' => 'ADMIN',
126
        'removefromdb' => 'ADMIN',
127
    ];
128
129
    public static function flush()
130
    {
131
        AllFilesInfo::flushCache();
132
    }
133
134
    public function Link($action = null)
135
    {
136
        $str = Director::absoluteURL(DIRECTORY_SEPARATOR . 'admin/assets-overview');
137
        if ($action) {
138
            $str .= DIRECTORY_SEPARATOR . $action;
139
        }
140
141
        return $str;
142
    }
143
144
    public function getTitle(): string
145
    {
146
        $this->getSortStatement();
147
        $this->getFilterStatement();
148
        $this->getPageStatement();
149
150
        if ($this->hasFilter()) {
151
            $filterStatement = '' .
152
                $this->getTotalFileCountFiltered() . ' files / ' .
153
                $this->getTotalFileSizeFiltered();
154
        } else {
155
            $filterStatement =
156
                $this->getTotalFileCountRaw() . ' / ' .
157
                $this->getTotalFileSizeRaw();
158
        }
159
160
        return DBField::create_field(
161
            'HTMLText',
162
            'Found ' . $filterStatement
163
        );
164
    }
165
166
    public function getSubTitle(): string
167
    {
168
        $array = array_filter(
169
            [
170
                $this->getSortStatement(),
171
                $this->getFilterStatement(),
172
                $this->getPageStatement(),
173
                $this->getTotalsStatement(),
174
            ]
175
        );
176
177
        return DBField::create_field(
178
            'HTMLText',
179
            '- ' . implode('<br /> - ', $array)
180
        );
181
    }
182
183
    public function getSortStatement(): string
184
    {
185
        return '<strong>sorted by</strong>: ' . self::SORTERS[$this->sorter]['Title'] ?? 'ERROR IN SORTER';
186
    }
187
188
    public function getFilterStatement(): string
189
    {
190
        $filterArray = array_filter(
191
            [
192
                self::FILTERS[$this->filter]['Title'] ?? '',
193
                implode(', ', $this->allowedExtensions),
194
            ]
195
        );
196
197
        return count($filterArray) ? '<strong>filtered for</strong>: ' . implode(', ', $filterArray) : '';
198
    }
199
200
    public function getPageStatement(): string
201
    {
202
        return $this->getNumberOfPages() > 1 ?
203
            '<strong>page</strong>: ' . $this->pageNumber . ' of ' . $this->getNumberOfPages() . ', showing file ' . ($this->startLimit + 1) . ' to ' . $this->endLimit
204
            :
205
            '';
206
    }
207
208
    public function getDisplayer(): string
209
    {
210
        return $this->displayer;
211
    }
212
213
    public function getFilesAsArrayList(): ArrayList
214
    {
215
        return $this->getAllFilesInfoProvider()->getFilesAsArrayList();
216
    }
217
218
    public function getFilesAsSortedArrayList(): ArrayList
219
    {
220
        return $this->getAllFilesInfoProvider()->getFilesAsSortedArrayList();
221
    }
222
223
    public function getTotalFileCountRaw(): string
224
    {
225
        return (string) number_format($this->getAllFilesInfoProvider()->getTotalFileCountRaw());
226
    }
227
228
    public function getTotalFileCountFiltered(): string
229
    {
230
        return (string) number_format($this->getAllFilesInfoProvider()->getTotalFileCountFiltered());
231
    }
232
233
    public function getTotalFileSizeFiltered(): string
234
    {
235
        return (string) $this->humanFileSize($this->getAllFilesInfoProvider()->getTotalFileSizeFiltered());
236
    }
237
238
    public function getTotalFileSizeRaw(): string
239
    {
240
        return (string) $this->humanFileSize($this->getAllFilesInfoProvider()->getTotalFileSizesRaw());
241
    }
242
243
    public function index($request)
244
    {
245
        if ('rawlistfull' === $this->displayer) {
246
            $this->addMapToItems();
247
        }
248
249
        // if (false === AllFilesInfo::loadedFromCache()) {
250
        //     $url = $_SERVER['REQUEST_URI'];
251
        //     $url = str_replace('flush=', 'previousflush=', $url);
252
253
        //     $js = '<script>window.location.href = \'' . $url . '\';</script>';
254
        //     return 'go to <a href="' . $url . '">' . $url . '</a> if this page does not autoload';
255
        // }
256
257
258
        return $this->renderWith('AssetsOverview');
259
    }
260
261
    public function json($request)
262
    {
263
        return $this->sendJSON($this->getRawData());
264
    }
265
266
    public function jsonfull($request)
267
    {
268
        $array = [];
269
270
        foreach ($this->getFilesAsArrayList()->toArray() as $item) {
271
            $array[] = $item->toMap();
272
        }
273
274
        return $this->sendJSON($array);
275
    }
276
277
    public function sync()
278
    {
279
        $obj = $this->getAddAndRemoveFromDbClass();
280
        foreach ($this->getFilesAsArrayList()->toArray() as $item) {
281
            $obj->run($item->toMap());
282
        }
283
    }
284
285
    public function addtodb()
286
    {
287
        $obj = $this->getAddAndRemoveFromDbClass();
288
        foreach ($this->getFilesAsArrayList()->toArray() as $item) {
289
            $obj->run($item->toMap(), 'add');
290
        }
291
    }
292
293
    public function removefromdb()
294
    {
295
        $obj = $this->getAddAndRemoveFromDbClass();
296
        foreach ($this->filesAsArrayList->toArray() as $item) {
0 ignored issues
show
Bug introduced by
The method toArray() 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

296
        foreach ($this->filesAsArrayList->/** @scrutinizer ignore-call */ toArray() as $item) {

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...
Bug Best Practice introduced by
The property filesAsArrayList does not exist on Sunnysideup\AssetsOverview\Control\View. Since you implemented __get, consider adding a @property annotation.
Loading history...
297
            $obj->run($item->toMap(), 'remove');
298
        }
299
    }
300
301
    protected function getAddAndRemoveFromDbClass(): AddAndRemoveFromDb
302
    {
303
        $obj = Injector::inst()->get(AddAndRemoveFromDb::class);
304
        return $obj->setIsDryRun($this->dryRun);
305
    }
306
307
    public function addMapToItems()
308
    {
309
        $this->isThumbList = false;
0 ignored issues
show
Bug Best Practice introduced by
The property isThumbList does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
310
        foreach ($this->getFilesAsSortedArrayList() as $group) {
311
            foreach ($group->Items as $item) {
312
                $map = $item->toMap();
313
                $item->FullFields = ArrayList::create();
314
                foreach ($map as $key => $value) {
315
                    if (false === $value) {
316
                        $value = 'no';
317
                    }
318
319
                    if (true === $value) {
320
                        $value = 'yes';
321
                    }
322
323
                    $item->FullFields->push(ArrayData::create(['Key' => $key, 'Value' => $value]));
324
                }
325
            }
326
        }
327
    }
328
329
    //#############################################
330
    // FORM
331
    //#############################################
332
    public function Form()
333
    {
334
        return $this->getForm();
335
    }
336
337
    protected function init()
338
    {
339
        parent::init();
340
        if (! Permission::check('ADMIN')) {
341
            return Security::permissionFailure($this);
342
        }
343
344
        Requirements::clear();
345
        ini_set('memory_limit', '1024M');
346
        Environment::increaseMemoryLimitTo();
347
        Environment::increaseTimeLimitTo(7200);
348
        SSViewer::config()->set('theme_enabled', false);
349
        Versioned::set_stage(Versioned::DRAFT);
350
        $this->getGetVariables();
351
        $this->getAllFilesInfoProvider();
352
    }
353
354
    protected function getTotalsStatement()
355
    {
356
        return $this->hasFilter() ? '<strong>Totals</strong>: ' .
357
            $this->getTotalFileCountRaw() . ' files / ' . $this->getTotalFileSizeRaw()
358
            : '';
359
    }
360
361
    protected function hasFilter(): bool
362
    {
363
        return $this->filter || count($this->allowedExtensions);
364
    }
365
366
    protected function getGetVariables()
367
    {
368
        $filter = $this->request->getVar('filter');
369
        if ($filter) {
370
            $this->filter = $filter;
371
        }
372
373
        $sorter = $this->request->getVar('sorter');
374
        if ($sorter) {
375
            $this->sorter = $sorter;
376
        }
377
378
        $displayer = $this->request->getVar('displayer');
379
        if ($displayer) {
380
            $this->displayer = $displayer;
381
        }
382
383
        $extensions = $this->request->getVar('extensions');
384
        if ($extensions) {
385
            if (! is_array($extensions)) {
386
                $extensions = [$extensions];
387
            }
388
389
            $this->allowedExtensions = $extensions;
390
            //make sure all are valid!
391
            $this->allowedExtensions = array_filter($this->allowedExtensions);
392
        }
393
394
        $limit = $this->request->getVar('limit');
395
        if ($limit) {
396
            $this->limit = $limit;
397
        }
398
399
        $this->pageNumber = ($this->request->getVar('page') ?: 1);
400
        $this->dryRun = $this->request->getVar('dryrun') ? true : false;
401
        $this->startLimit = $this->limit * ($this->pageNumber - 1);
402
        $this->endLimit = $this->limit * ($this->pageNumber + 0);
403
        $this->getAllFilesInfoProvider();
404
    }
405
406
    protected function sendJSON($data)
407
    {
408
        $json = json_encode($data, JSON_PRETTY_PRINT);
409
        if ($this->request->getVar('download')) {
410
            return HTTPRequest::send_file($json, 'files.json', 'text/json');
411
        }
412
        $response = (new HTTPResponse($json));
413
        $response->addHeader('Content-Type', 'application/json; charset="utf-8"');
414
        $response->addHeader('Pragma', 'no-cache');
415
        $response->addHeader('cache-control', 'no-cache, no-store, must-revalidate');
416
        $response->addHeader('Access-Control-Allow-Origin', '*');
417
        $response->addHeader('Expires', 0);
418
        HTTPCacheControlMiddleware::singleton()
419
            ->disableCache()
420
        ;
421
        $response->output();
422
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
423
    }
424
425
426
427
428
    protected function getForm(): Form
429
    {
430
        $fieldList = FieldList::create(
431
            [
432
                $this->createFormField('dryrun', 'Dry Run (not for real)', $this->dryrun, $this->getSorterList()),
0 ignored issues
show
Bug Best Practice introduced by
The property dryrun does not exist on Sunnysideup\AssetsOverview\Control\View. Since you implemented __get, consider adding a @property annotation.
Loading history...
433
                $this->createFormField('sorter', 'Sort by', $this->sorter, $this->getSorterList()),
434
                $this->createFormField('filter', 'Filter for errors', $this->filter, $this->getFilterList()),
435
                $this->createFormField('extensions', 'Filter by extensions', $this->allowedExtensions, $this->getExtensionList()),
436
                $this->createFormField('displayer', 'Displayed by', $this->displayer, $this->getDisplayerList()),
437
                $this->createFormField('limit', 'Items per page', $this->limit, $this->getLimitList()),
438
                $this->createFormField('page', 'Page number', $this->pageNumber, $this->getPageNumberList()),
439
                // TextField::create('compare', 'Compare With')->setDescription('add a link to a comparison file - e.g. http://oldsite.com/admin/assets-overview/test.json'),
440
            ]
441
        );
442
        $actionList = FieldList::create(
443
            [
444
                FormAction::create('index', 'Update File List'),
445
            ]
446
        );
447
448
        $form = Form::create($this, 'index', $fieldList, $actionList);
449
        $form->setFormMethod('GET', true);
450
        $form->disableSecurityToken();
451
452
        return $form;
453
    }
454
455
    protected function createFormField(string $name, string $title, $value, ?array $list = [])
456
    {
457
        $listCount = count($list);
458
        if ($name === 'dryrun') {
459
            $type = CheckboxField::class;
460
        } elseif (0 === $listCount) {
461
            $type = HiddenField::class;
462
        } elseif ('limit' === $name || 'page' === $name) {
463
            $type = DropdownField::class;
464
        } elseif ('extensions' === $name) {
465
            $type = CheckboxSetField::class;
466
        } elseif ($listCount < 20) {
467
            $type = OptionsetField::class;
468
        } else {
469
            $type = DropdownField::class;
470
        }
471
472
        $field = $type::create($name, $title)
473
            ->setValue($value);
474
        if ($listCount) {
475
            $field->setSource($list);
476
        }
477
478
        // $field->setAttribute('onchange', 'this.form.submit()');
479
480
        return $field;
481
    }
482
483
    protected function getSorterList(): array
484
    {
485
        $array = [];
486
        foreach (self::SORTERS as $key => $data) {
487
            $array[$key] = $data['Title'];
488
        }
489
490
        return $array;
491
    }
492
493
    protected function getFilterList(): array
494
    {
495
        $array = ['' => '-- no filter --'];
496
        foreach (self::FILTERS as $key => $data) {
497
            $array[$key] = $data['Title'];
498
        }
499
500
        return $array;
501
    }
502
503
    protected function getDisplayerList(): array
504
    {
505
        return self::DISPLAYERS;
506
    }
507
508
    protected function getExtensionList(): array
509
    {
510
        $list = array_filter($this->getAllFilesInfoProvider()->getAvailableExtensions());
511
        $list = ['n/a' => 'n/a'] + $list;
512
        return $list;
513
    }
514
515
    protected function getPageNumberList(): array
516
    {
517
        $list = range(1, $this->getNumberOfPages());
518
        $list = array_combine($list, $list);
519
        $list[(string) $this->pageNumber] = (string) $this->pageNumber;
520
        if (count($list) < 2) {
521
            return [];
522
        }
523
524
        return $list;
525
    }
526
527
    protected function getNumberOfPages(): int
528
    {
529
        return ceil($this->getAllFilesInfoProvider()->getTotalFileCountFiltered() / $this->limit);
0 ignored issues
show
Bug Best Practice introduced by
The expression return ceil($this->getAl...tered() / $this->limit) returns the type double which is incompatible with the type-hinted return integer.
Loading history...
530
    }
531
532
    protected function getLimitList(): array
533
    {
534
        $step = 100;
535
        $array = [];
536
        $i = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $i is dead and can be removed.
Loading history...
537
        if ($this->getAllFilesInfoProvider()->getTotalFileCountRaw() > $step) {
538
            for ($i = $step; ($i - $step) < $this->totalFileCountFiltered; $i += $step) {
0 ignored issues
show
Bug Best Practice introduced by
The property totalFileCountFiltered does not exist on Sunnysideup\AssetsOverview\Control\View. Since you implemented __get, consider adding a @property annotation.
Loading history...
539
                if ($i > $this->limit && ! isset($array[$this->limit])) {
540
                    $array[$this->limit] = $this->limit;
541
                }
542
543
                $array[$i] = $i;
544
            }
545
        }
546
547
        return $array;
548
    }
549
550
551
552
    protected function getRawData(): array
553
    {
554
        return $this->getAllFilesInfoProvider()->toArray();
555
    }
556
557
    protected function getAllFilesInfoProvider(): AllFilesInfo
558
    {
559
        if (!self::$allFilesProvider) {
560
            /** @var AllFilesInfo self::$allFilesProvider */
561
            self::$allFilesProvider = AllFilesInfo::inst();
562
            self::$allFilesProvider
563
                ->setFilters(self::get_filters())
564
                ->setSorters(self::get_sorters())
565
                ->setFilter($this->filter)
566
                ->setAllowedExtensions($this->allowedExtensions)
567
                ->setSorter($this->sorter)
568
                ->setLimit($this->limit)
569
                ->setPageNumber($this->pageNumber)
570
                ->setStartLimit($this->startLimit)
571
                ->setEndLimit($this->endLimit)
572
                ->setDisplayer($this->displayer)
573
                ->getFilesAsArrayList();
574
            while ($this->startLimit > $this->filesAsArrayList->count()) {
0 ignored issues
show
Bug Best Practice introduced by
The property filesAsArrayList does not exist on Sunnysideup\AssetsOverview\Control\View. Since you implemented __get, consider adding a @property annotation.
Loading history...
575
                $this->pageNumber--;
576
                $this->startLimit = $this->limit * ($this->pageNumber - 1);
577
                $this->endLimit = $this->limit * ($this->pageNumber + 0);
578
            }
579
        }
580
        return self::$allFilesProvider;
581
    }
582
583
584
    private const SORTERS = [
585
        'byfolder' => [
586
            'Title' => 'Folder',
587
            'Sort' => 'PathFolderFromAssets',
588
            'Group' => 'PathFolderFromAssets',
589
        ],
590
        'byfilename' => [
591
            'Title' => 'Filename',
592
            'Sort' => 'PathFileName',
593
            'Group' => 'PathFileNameFirstLetter',
594
        ],
595
        'bydbtitle' => [
596
            'Title' => 'Database Title',
597
            'Sort' => 'DBTitle',
598
            'Group' => 'DBTitleFirstLetter',
599
        ],
600
        'byfilesize' => [
601
            'Title' => 'Filesize',
602
            'Sort' => 'PathFileSize',
603
            'Group' => 'HumanFileSizeRounded',
604
        ],
605
        'bylastedited' => [
606
            'Title' => 'Last Edited',
607
            'Sort' => 'DBLastEditedTS',
608
            'Group' => 'DBLastEdited',
609
        ],
610
        'byextension' => [
611
            'Title' => 'PathExtension',
612
            'Sort' => 'PathExtensionAsLower',
613
            'Group' => 'PathExtensionAsLower',
614
        ],
615
        'byisimage' => [
616
            'Title' => 'Image vs Other Files',
617
            'Sort' => 'ImageIsImage',
618
            'Group' => 'HumanImageIsImage',
619
        ],
620
        'byclassname' => [
621
            'Title' => 'Class Name',
622
            'Sort' => 'DBClassName',
623
            'Group' => 'DBClassName',
624
        ],
625
        'bydimensions' => [
626
            'Title' => 'Dimensions (small to big)',
627
            'Sort' => 'ImagePixels',
628
            'Group' => 'HumanImageDimensions',
629
        ],
630
        'byratio' => [
631
            'Title' => 'ImageRatio',
632
            'Sort' => 'ImageRatio',
633
            'Group' => 'ImageRatio',
634
        ],
635
    ];
636
637
    private const FILTERS = [
638
        'byanyerror' => [
639
            'Title' => 'Any Error',
640
            'Field' => 'ErrorHasAnyError',
641
            'Values' => [1, true],
642
        ],
643
        'byfilesystemstatus' => [
644
            'Title' => 'Not in filesystem',
645
            'Field' => 'ErrorIsInFileSystem',
646
            'Values' => [1, true],
647
        ],
648
        'bymissingfromdatabase' => [
649
            'Title' => 'Not in database',
650
            'Field' => 'ErrorDBNotPresent',
651
            'Values' => [1, true],
652
        ],
653
        'bymissingfromlive' => [
654
            'Title' => 'Not on live site',
655
            'Field' => 'ErrorDBNotPresentLive',
656
            'Values' => [1, true],
657
        ],
658
        'bymissingfromstaging' => [
659
            'Title' => 'Not on draft site',
660
            'Field' => 'ErrorDBNotPresentStaging',
661
            'Values' => [1, true],
662
        ],
663
        'bydraftonly' => [
664
            'Title' => 'In draft only (not on live)',
665
            'Field' => 'ErrorInDraftOnly',
666
            'Values' => [1, true],
667
        ],
668
        'byliveonly' => [
669
            'Title' => 'On live only (not in draft)',
670
            'Field' => 'ErrorNotInDraft',
671
            'Values' => [1, true],
672
        ],
673
        'byfoldererror' => [
674
            'Title' => 'Folder error',
675
            'Field' => 'ErrorParentID',
676
            'Values' => [1, true],
677
        ],
678
        'bydatabaseerror' => [
679
            'Title' => 'Error in file name',
680
            'Field' => 'ErrorInFilename',
681
            'Values' => [1, true],
682
        ],
683
        'byextensionerror' => [
684
            'Title' => 'UPPER/lower case error in file type',
685
            'Field' => 'ErrorExtensionMisMatch',
686
            'Values' => [1, true],
687
        ],
688
        'byextensionallowed' => [
689
            'Title' => 'Extension not allowed',
690
            'Field' => 'ErrorInvalidExtension',
691
            'Values' => [1, true],
692
        ],
693
        'by3to4error' => [
694
            'Title' => 'Potential SS4 migration error',
695
            'Field' => 'ErrorInSs3Ss4Comparison',
696
            'Values' => [1, true],
697
        ],
698
    ];
699
    /**
700
     * @var array<string, string>
701
     */
702
    private const DISPLAYERS = [
703
        'thumbs' => 'Thumbnails',
704
        'rawlist' => 'File List',
705
        'rawlistfull' => 'Raw Data',
706
    ];
707
}
708