Completed
Push — master ( ceaaa1...b24b7d )
by Fabien
02:17
created
Classes/Module/ModuleLoader.php 1 patch
Indentation   +1002 added lines, -1002 removed lines patch added patch discarded remove patch
@@ -20,1007 +20,1007 @@
 block discarded – undo
20 20
 class ModuleLoader
21 21
 {
22 22
 
23
-    /**
24
-     * Define the default main module
25
-     */
26
-    const DEFAULT_MAIN_MODULE = 'content';
27
-
28
-    /**
29
-     * Define the default pid
30
-     */
31
-    const DEFAULT_PID = 0;
32
-
33
-    /**
34
-     * The type of data being listed (which corresponds to a table name in TCA)
35
-     *
36
-     * @var string
37
-     */
38
-    protected $dataType;
39
-
40
-    /**
41
-     * @var string
42
-     */
43
-    protected $defaultPid;
44
-
45
-    /**
46
-     * @var bool
47
-     */
48
-    protected $isPidIgnored = false;
49
-
50
-    /**
51
-     * @var bool
52
-     */
53
-    protected $showPageTree = false;
54
-
55
-    /**
56
-     * @var bool
57
-     */
58
-    protected $isShown = true;
59
-
60
-    /**
61
-     * @var string
62
-     */
63
-    protected $access;
64
-
65
-    /**
66
-     * @var string
67
-     */
68
-    protected $mainModule;
69
-
70
-    /**
71
-     * @var string
72
-     */
73
-    protected $position = '';
74
-
75
-    /**
76
-     * @var string
77
-     */
78
-    protected $icon;
79
-
80
-    /**
81
-     * @var string
82
-     */
83
-    protected $moduleLanguageFile;
84
-
85
-    /**
86
-     * The module key such as m1, m2.
87
-     *
88
-     * @var string
89
-     */
90
-    protected $moduleKey = 'm1';
91
-
92
-    /**
93
-     * @var string[]
94
-     */
95
-    protected $additionalJavaScriptFiles = [];
96
-
97
-    /**
98
-     * @var string[]
99
-     */
100
-    protected $additionalStyleSheetFiles = [];
101
-
102
-    /**
103
-     * @var array
104
-     */
105
-    protected $components = [];
106
-
107
-    /**
108
-     * @param string $dataType
109
-     */
110
-    public function __construct($dataType = null)
111
-    {
112
-        $this->dataType = $dataType;
113
-
114
-        // Initialize components
115
-        $this->components = [
116
-            ModulePosition::DOC_HEADER => [
117
-                ModulePosition::TOP => [
118
-                    ModulePosition::LEFT => [],
119
-                    ModulePosition::RIGHT => [
120
-                        \Fab\Vidi\View\Button\ToolButton::class,
121
-                    ],
122
-                ],
123
-                ModulePosition::BOTTOM => [
124
-                    ModulePosition::LEFT => [
125
-                        \Fab\Vidi\View\Button\NewButton::class,
126
-                        \Fab\Vidi\ViewHelpers\Link\BackViewHelper::class,
127
-                    ],
128
-                    ModulePosition::RIGHT => [],
129
-                ],
130
-            ],
131
-            ModulePosition::GRID => [
132
-                ModulePosition::TOP => [
133
-                    \Fab\Vidi\View\Check\PidCheck::class,
134
-                    \Fab\Vidi\View\Check\RelationsCheck::class,
135
-                    #\Fab\Vidi\View\Tab\DataTypeTab::class,
136
-                ],
137
-                ModulePosition::BUTTONS => [
138
-                    \Fab\Vidi\View\Button\EditButton::class,
139
-                    \Fab\Vidi\View\Button\DeleteButton::class,
140
-                ],
141
-                ModulePosition::BOTTOM => [],
142
-            ],
143
-            ModulePosition::MENU_MASS_ACTION => [
144
-                \Fab\Vidi\View\MenuItem\ExportXlsMenuItem::class,
145
-                \Fab\Vidi\View\MenuItem\ExportXmlMenuItem::class,
146
-                \Fab\Vidi\View\MenuItem\ExportCsvMenuItem::class,
147
-                \Fab\Vidi\View\MenuItem\DividerMenuItem::class,
148
-                \Fab\Vidi\View\MenuItem\MassDeleteMenuItem::class,
149
-                #\Fab\Vidi\View\MenuItem\MassEditMenuItem::class,
150
-            ],
151
-        ];
152
-    }
153
-
154
-    /**
155
-     * Tell whether a module is already registered.
156
-     *
157
-     * @param string $dataType
158
-     * @return bool
159
-     */
160
-    public function isRegistered($dataType): bool
161
-    {
162
-        $internalModuleSignature = $this->getInternalModuleSignature($dataType);
163
-        return !empty($GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature]);
164
-    }
165
-
166
-    /**
167
-     * @return array
168
-     */
169
-    protected function getExistingInternalConfiguration(): array
170
-    {
171
-        $internalModuleSignature = $this->getInternalModuleSignature();
172
-        return is_array($GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature])
173
-            ? $GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature]
174
-            : [];
175
-    }
176
-
177
-    /**
178
-     * @return array
179
-     */
180
-    protected function getExistingMainConfiguration(): array
181
-    {
182
-        $possibleConfiguration = $GLOBALS['TBE_MODULES']['_configuration'][$this->computeMainModule() . '_' . $this->getInternalModuleSignature()];
183
-        return is_array($possibleConfiguration) ? $possibleConfiguration : [];
184
-    }
185
-
186
-    /**
187
-     * @return string
188
-     */
189
-    protected function computeMainModule(): string
190
-    {
191
-        $existingConfiguration = $this->getExistingInternalConfiguration();
192
-
193
-        if ($this->mainModule !== null) {
194
-            $mainModule = $this->mainModule;
195
-        } elseif ($existingConfiguration['mainModule']) { // existing configuration may override.
196
-            $mainModule = $existingConfiguration['mainModule'];
197
-        } else {
198
-            $mainModule = self::DEFAULT_MAIN_MODULE; //default value.
199
-        }
200
-        return $mainModule;
201
-    }
202
-
203
-    /**
204
-     * @return string
205
-     */
206
-    protected function computeDefaultPid(): string
207
-    {
208
-        $existingConfiguration = $this->getExistingInternalConfiguration();
209
-
210
-        if ($this->defaultPid !== null) {
211
-            $defaultPid = $this->defaultPid;
212
-        } elseif ($existingConfiguration['defaultPid']) { // existing configuration may override.
213
-            $defaultPid = $existingConfiguration['defaultPid'];
214
-        } else {
215
-            $defaultPid = self::DEFAULT_PID; //default value.
216
-        }
217
-        return $defaultPid;
218
-    }
219
-
220
-    /**
221
-     * @return array
222
-     */
223
-    protected function computeAdditionalJavaScriptFiles(): array
224
-    {
225
-        $additionalJavaScriptFiles = $this->additionalJavaScriptFiles;
226
-
227
-        // Possible merge of existing javascript files.
228
-        $existingConfiguration = $this->getExistingInternalConfiguration();
229
-        if ($existingConfiguration['additionalJavaScriptFiles']) {
230
-            $additionalJavaScriptFiles = array_merge($additionalJavaScriptFiles, $existingConfiguration['additionalJavaScriptFiles']);
231
-        }
232
-
233
-        return $additionalJavaScriptFiles;
234
-    }
235
-
236
-    /**
237
-     * @return array
238
-     */
239
-    protected function computeAdditionalStyleSheetFiles(): array
240
-    {
241
-        $additionalStyleSheetFiles = $this->additionalStyleSheetFiles;
242
-
243
-        // Possible merge of existing style sheets.
244
-        $existingConfiguration = $this->getExistingInternalConfiguration();
245
-        if ($existingConfiguration['additionalStyleSheetFiles']) {
246
-            $additionalStyleSheetFiles = array_merge($additionalStyleSheetFiles, $existingConfiguration['additionalStyleSheetFiles']);
247
-        }
248
-
249
-        return $additionalStyleSheetFiles;
250
-    }
251
-
252
-    /**
253
-     * @return array
254
-     */
255
-    protected function computeComponents(): array
256
-    {
257
-        // We override the config in any case. See if we need more than that.
258
-        return $this->components;
259
-    }
260
-
261
-    /**
262
-     * Register the module in two places: core + vidi internal.
263
-     *
264
-     * @return void
265
-     */
266
-    public function register(): void
267
-    {
268
-        // Internal Vidi module registration.
269
-        $configuration = [];
270
-        $configuration['dataType'] = $this->dataType;
271
-        $configuration['mainModule'] = $this->computeMainModule();
272
-        $configuration['defaultPid'] = $this->computeDefaultPid();
273
-        $configuration['additionalJavaScriptFiles'] = $this->computeAdditionalJavaScriptFiles();
274
-        $configuration['additionalStyleSheetFiles'] = $this->computeAdditionalStyleSheetFiles();
275
-        $configuration['components'] = $this->computeComponents();
276
-        $configuration['isPidIgnored'] = $this->isPidIgnored;
277
-
278
-        $internalModuleSignature = $this->getInternalModuleSignature();
279
-        $GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature] = $configuration;
280
-
281
-        // Core module registration.
282
-        // Register and displays module in the BE only if told, default is "true".
283
-        if ($this->isShown) {
284
-
285
-            $moduleConfiguration = [];
286
-            #$moduleConfiguration['routeTarget'] = \Fab\Vidi\Controller\ContentController::class . '::mainAction', // what to do here?
287
-            $moduleConfiguration['access'] = $this->getAccess();
288
-            $moduleConfiguration['labels'] = $this->getModuleLanguageFile();
289
-            $icon = $this->getIcon();
290
-            if ($icon) {
291
-                $moduleConfiguration['icon'] = $icon;
292
-            }
293
-
294
-            if ($this->showPageTree) {
295
-                $moduleConfiguration['navigationComponentId'] = 'TYPO3/CMS/Backend/PageTree/PageTreeElement';
296
-                $moduleConfiguration['inheritNavigationComponentFromMainModule'] = true;
297
-            } else {
298
-                $moduleConfiguration['inheritNavigationComponentFromMainModule'] = true;
299
-            }
300
-
301
-            ExtensionUtility::registerModule(
302
-                'Fab.vidi',
303
-                $this->computeMainModule(),
304
-                $this->dataType . '_' . $this->moduleKey,
305
-                $this->position,
306
-                [
307
-                    'Content' => 'index, list, delete, update, edit, copy, move, localize, sort, copyClipboard, moveClipboard',
308
-                    'Tool' => 'welcome, work',
309
-                    'Facet' => 'autoSuggest, autoSuggests',
310
-                    'Selection' => 'edit, update, create, delete, list, show',
311
-                    'UserPreferences' => 'save',
312
-                    'Clipboard' => 'save, flush, show',
313
-                ],
314
-                $moduleConfiguration
315
-            );
316
-        }
317
-    }
318
-
319
-    /**
320
-     * Return the module code for a BE module.
321
-     *
322
-     * @return string
323
-     */
324
-    public function getSignature(): string
325
-    {
326
-        $signature = GeneralUtility::_GP(Parameter::MODULE);
327
-        $trimmedSignature = trim($signature, '/');
328
-        return str_replace('/', '_', $trimmedSignature);
329
-    }
330
-
331
-    /**
332
-     * Returns the current pid.
333
-     *
334
-     * @return bool
335
-     */
336
-    public function getCurrentPid(): bool
337
-    {
338
-        return GeneralUtility::_GET(Parameter::PID) > 0 ? (int)GeneralUtility::_GET(Parameter::PID) : 0;
339
-    }
340
-
341
-    /**
342
-     * Return the module URL.
343
-     *
344
-     * @param array $additionalParameters
345
-     * @return string
346
-     */
347
-    public function getModuleUrl(array $additionalParameters = []): string
348
-    {
349
-        $moduleCode = $this->getSignature();
350
-
351
-        // And don't forget the pid!
352
-        if (GeneralUtility::_GET(Parameter::PID)) {
353
-            $additionalParameters[Parameter::PID] = GeneralUtility::_GET(Parameter::PID);
354
-        }
355
-
356
-        return BackendUtility::getModuleUrl($moduleCode, $additionalParameters);
357
-    }
358
-
359
-    /**
360
-     * Return the parameter prefix for a BE module.
361
-     *
362
-     * @return string
363
-     */
364
-    public function getParameterPrefix(): string
365
-    {
366
-        return 'tx_vidi_' . strtolower($this->getSignature());
367
-    }
368
-
369
-    /**
370
-     * Return a configuration key or the entire module configuration array if not key is given.
371
-     *
372
-     * @param string $key
373
-     * @return mixed
374
-     */
375
-    public function getModuleConfiguration($key = '')
376
-    {
377
-
378
-        $vidiModuleCode = $this->getSignature();
379
-
380
-        // Module code must exist
381
-        if (empty($GLOBALS['TBE_MODULES_EXT']['vidi'][$vidiModuleCode])) {
382
-            $message = sprintf('Invalid or not existing module code "%s"', $vidiModuleCode);
383
-            throw new InvalidKeyInArrayException($message, 1375092053);
384
-        }
385
-
386
-        $result = $GLOBALS['TBE_MODULES_EXT']['vidi'][$vidiModuleCode];
387
-
388
-        if (!empty($key)) {
389
-            if (isset($result[$key])) {
390
-                $result = $result[$key];
391
-            } else {
392
-                // key must exist
393
-                $message = sprintf('Invalid key configuration "%s"', $key);
394
-                throw new InvalidKeyInArrayException($message, 1375092054);
395
-            }
396
-        }
397
-        return $result;
398
-    }
399
-
400
-    /**
401
-     * @param string $icon
402
-     * @return $this
403
-     */
404
-    public function setIcon($icon): self
405
-    {
406
-        $this->icon = $icon;
407
-        return $this;
408
-    }
409
-
410
-    /**
411
-     * @return string
412
-     */
413
-    protected function getIcon(): string
414
-    {
415
-        $moduleConfiguration = $this->getExistingMainConfiguration();
416
-
417
-
418
-        if ($this->icon) {
419
-            $icon = $this->icon;
420
-        } elseif ($moduleConfiguration['icon']) { // existing configuration may override.
421
-            $icon = $moduleConfiguration['icon'];
422
-        } else {
423
-            $icon = ''; //default value.
424
-        }
425
-
426
-        return $icon;
427
-    }
428
-
429
-    /**
430
-     * @param string $mainModule
431
-     * @return $this
432
-     */
433
-    public function setMainModule($mainModule): self
434
-    {
435
-        $this->mainModule = $mainModule;
436
-        return $this;
437
-    }
438
-
439
-    /**
440
-     * @return string
441
-     */
442
-    public function getMainModule(): string
443
-    {
444
-        if ($this->mainModule === null) {
445
-            $this->mainModule = $this->getModuleConfiguration('mainModule');
446
-        }
447
-        return $this->mainModule;
448
-    }
449
-
450
-    /**
451
-     * @param string $moduleLanguageFile
452
-     * @return $this
453
-     */
454
-    public function setModuleLanguageFile($moduleLanguageFile): self
455
-    {
456
-        $this->moduleLanguageFile = $moduleLanguageFile;
457
-        return $this;
458
-    }
459
-
460
-    /**
461
-     * @param string $component
462
-     * @return $this
463
-     */
464
-    public function removeComponentFromDocHeader(string $component): self
465
-    {
466
-        foreach ($this->components[ModulePosition::DOC_HEADER] as $verticalPosition => $docHeaders) {
467
-            foreach ($docHeaders as $horizontalPosition => $docHeader) {
468
-
469
-                $index = array_search($component, $docHeader, true);
470
-                if ($index !== false) {
471
-                    // $verticalPosition: top or bottom
472
-                    // $horizontalPosition: left or right
473
-                    unset($this->components[ModulePosition::DOC_HEADER][$verticalPosition][$horizontalPosition][$index]);
474
-                }
475
-            }
476
-        }
477
-        return $this;
478
-    }
479
-
480
-    /**
481
-     * @param bool $isPidIgnored
482
-     * @return $this
483
-     */
484
-    public function ignorePid(bool $isPidIgnored): self
485
-    {
486
-        $this->isPidIgnored = $isPidIgnored;
487
-        return $this;
488
-    }
489
-
490
-    /**
491
-     * @return bool
492
-     */
493
-    public function isPidIgnored(): bool
494
-    {
495
-        return $this->getModuleConfiguration('isPidIgnored');
496
-    }
497
-
498
-    /**
499
-     * @param string $component
500
-     * @return bool
501
-     */
502
-    public function hasComponentInDocHeader(string $component): bool
503
-    {
504
-        foreach ($this->getModuleConfiguration('components')[ModulePosition::DOC_HEADER] as $verticalPosition => $docHeaders) {
505
-            foreach ($docHeaders as $horizontalPosition => $docHeader) {
506
-
507
-                $index = array_search($component, $docHeader, true);
508
-                if ($index !== false) {
509
-                    return true;
510
-                }
511
-            }
512
-        }
513
-        return false;
514
-    }
515
-
516
-    /**
517
-     * @return string
518
-     */
519
-    protected function getModuleLanguageFile(): string
520
-    {
521
-        $moduleConfiguration = $this->getExistingMainConfiguration();
522
-
523
-        if ($this->moduleLanguageFile) {
524
-            $moduleLanguageFile = $this->moduleLanguageFile;
525
-        } elseif ($moduleConfiguration['labels']) { // existing configuration may override.
526
-            $moduleLanguageFile = $moduleConfiguration['labels'];
527
-        }
528
-        else {
529
-            $moduleLanguageFile = ''; //default value.
530
-        }
531
-
532
-        return $moduleLanguageFile;
533
-    }
534
-
535
-    /**
536
-     * @param string $position
537
-     * @return $this
538
-     */
539
-    public function setPosition($position): self
540
-    {
541
-        $this->position = $position;
542
-        return $this;
543
-    }
544
-
545
-    /**
546
-     * @return string
547
-     */
548
-    public function getPosition(): string
549
-    {
550
-        return $this->position;
551
-    }
552
-
553
-    /**
554
-     * @param array $files
555
-     * @return $this
556
-     */
557
-    public function addJavaScriptFiles(array $files): self
558
-    {
559
-        foreach ($files as $file) {
560
-            $this->additionalJavaScriptFiles[] = $file;
561
-        }
562
-        return $this;
563
-    }
564
-
565
-    /**
566
-     * @param string $fileNameAndPath
567
-     * @return $this
568
-     */
569
-    public function addJavaScriptFile($fileNameAndPath): self
570
-    {
571
-        $this->additionalJavaScriptFiles[] = $fileNameAndPath;
572
-        return $this;
573
-    }
574
-
575
-    /**
576
-     * @param array $files
577
-     * @return $this
578
-     */
579
-    public function addStyleSheetFiles(array $files): self
580
-    {
581
-        foreach ($files as $file) {
582
-            $this->additionalStyleSheetFiles[] = $file;
583
-        }
584
-        return $this;
585
-    }
586
-
587
-    /**
588
-     * @param string $fileNameAndPath
589
-     * @return $this
590
-     */
591
-    public function addStyleSheetFile($fileNameAndPath): self
592
-    {
593
-        $this->additionalStyleSheetFiles[] = $fileNameAndPath;
594
-        return $this;
595
-    }
596
-
597
-    /**
598
-     * @return string
599
-     */
600
-    public function getDataType(): string
601
-    {
602
-        if ($this->dataType === null) {
603
-            $this->dataType = $this->getModuleConfiguration('dataType');
604
-        }
605
-        return $this->dataType;
606
-    }
607
-
608
-    /**
609
-     * @return array
610
-     */
611
-    public function getDataTypes(): array
612
-    {
613
-        $dataTypes = [];
614
-        foreach ($GLOBALS['TBE_MODULES_EXT']['vidi'] as $module) {
615
-            $dataTypes[] = $module['dataType'];
616
-        }
617
-        return $dataTypes;
618
-    }
619
-
620
-    /**
621
-     * @param string $dataType
622
-     * @return $this
623
-     */
624
-    public function setDataType($dataType): self
625
-    {
626
-        $this->dataType = $dataType;
627
-        return $this;
628
-    }
629
-
630
-    /**
631
-     * @return string
632
-     */
633
-    public function getDefaultPid(): string
634
-    {
635
-        if (empty($this->defaultPid)) {
636
-            $this->defaultPid = $this->getModuleConfiguration('defaultPid');
637
-        }
638
-        return $this->defaultPid;
639
-    }
640
-
641
-    /**
642
-     * @param string $defaultPid
643
-     * @return $this
644
-     */
645
-    public function setDefaultPid($defaultPid): self
646
-    {
647
-        $this->defaultPid = $defaultPid;
648
-        return $this;
649
-    }
650
-
651
-    /**
652
-     * @param bool $isPageTreeShown
653
-     * @return $this
654
-     */
655
-    public function showPageTree($isPageTreeShown): self
656
-    {
657
-        $this->showPageTree = $isPageTreeShown;
658
-        return $this;
659
-    }
660
-
661
-    /**
662
-     * @param string $isShown
663
-     * @return $this
664
-     */
665
-    public function isShown($isShown): self
666
-    {
667
-        $this->isShown = $isShown;
668
-        return $this;
669
-    }
670
-
671
-    /**
672
-     * @return $array
673
-     */
674
-    public function getDocHeaderTopLeftComponents()
675
-    {
676
-        $configuration = $this->getModuleConfiguration();
677
-        return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT];
678
-    }
679
-
680
-    /**
681
-     * @param array $components
682
-     * @return $this
683
-     */
684
-    public function setDocHeaderTopLeftComponents(array $components): self
685
-    {
686
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT] = $components;
687
-        return $this;
688
-    }
689
-
690
-    /**
691
-     * @param string|array $components
692
-     * @return $this
693
-     */
694
-    public function addDocHeaderTopLeftComponents($components): self
695
-    {
696
-        if (is_string($components)) {
697
-            $components = [$components];
698
-        }
699
-        $currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT];
700
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT] = array_merge($currentComponents, $components);
701
-        return $this;
702
-    }
703
-
704
-    /**
705
-     * @return $array
706
-     */
707
-    public function getDocHeaderTopRightComponents()
708
-    {
709
-        $configuration = $this->getModuleConfiguration();
710
-        return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT];
711
-    }
712
-
713
-    /**
714
-     * @param array $components
715
-     * @return $this
716
-     */
717
-    public function setDocHeaderTopRightComponents(array $components): self
718
-    {
719
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT] = $components;
720
-        return $this;
721
-    }
722
-
723
-    /**
724
-     * @param string|array $components
725
-     * @return $this
726
-     */
727
-    public function addDocHeaderTopRightComponents($components): self
728
-    {
729
-        if (is_string($components)) {
730
-            $components = [$components];
731
-        }
732
-        $currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT];
733
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT] = array_merge($currentComponents, $components);
734
-        return $this;
735
-    }
736
-
737
-    /**
738
-     * @return $array
739
-     */
740
-    public function getDocHeaderBottomLeftComponents()
741
-    {
742
-        $configuration = $this->getModuleConfiguration();
743
-        return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT];
744
-    }
745
-
746
-    /**
747
-     * @param array $components
748
-     * @return $this
749
-     */
750
-    public function setDocHeaderBottomLeftComponents(array $components): self
751
-    {
752
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT] = $components;
753
-        return $this;
754
-    }
755
-
756
-    /**
757
-     * @param string|array $components
758
-     * @return $this
759
-     */
760
-    public function addDocHeaderBottomLeftComponents($components): self
761
-    {
762
-        if (is_string($components)) {
763
-            $components = [$components];
764
-        }
765
-        $currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT];
766
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT] = array_merge($currentComponents, $components);
767
-        return $this;
768
-    }
769
-
770
-    /**
771
-     * @return $array
772
-     */
773
-    public function getDocHeaderBottomRightComponents()
774
-    {
775
-        $configuration = $this->getModuleConfiguration();
776
-        return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT];
777
-    }
778
-
779
-    /**
780
-     * @param array $components
781
-     * @return $this
782
-     */
783
-    public function setDocHeaderBottomRightComponents(array $components): self
784
-    {
785
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT] = $components;
786
-        return $this;
787
-    }
788
-
789
-    /**
790
-     * @param string|array $components
791
-     * @return $this
792
-     */
793
-    public function addDocHeaderBottomRightComponents($components): self
794
-    {
795
-        if (is_string($components)) {
796
-            $components = [$components];
797
-        }
798
-        $currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT];
799
-        $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT] = array_merge($currentComponents, $components);
800
-        return $this;
801
-    }
802
-
803
-    /**
804
-     * @return $array
805
-     */
806
-    public function getGridTopComponents()
807
-    {
808
-        $configuration = $this->getModuleConfiguration();
809
-        return $configuration['components'][ModulePosition::GRID][ModulePosition::TOP];
810
-    }
811
-
812
-    /**
813
-     * @param array $components
814
-     * @return $this
815
-     */
816
-    public function setGridTopComponents(array $components): self
817
-    {
818
-        $this->components[ModulePosition::GRID][ModulePosition::TOP] = $components;
819
-        return $this;
820
-    }
821
-
822
-    /**
823
-     * @param string|array $components
824
-     * @return $this
825
-     */
826
-    public function addGridTopComponents($components): self
827
-    {
828
-        if (is_string($components)) {
829
-            $components = [$components];
830
-        }
831
-        $currentComponents = $this->components[ModulePosition::GRID][ModulePosition::TOP];
832
-        $this->components[ModulePosition::GRID][ModulePosition::TOP] = array_merge($currentComponents, $components);
833
-        return $this;
834
-    }
835
-
836
-    /**
837
-     * @return mixed $array
838
-     */
839
-    public function getGridBottomComponents()
840
-    {
841
-        $configuration = $this->getModuleConfiguration();
842
-        return $configuration['components'][ModulePosition::GRID][ModulePosition::BOTTOM];
843
-    }
844
-
845
-    /**
846
-     * @param array $components
847
-     * @return $this
848
-     */
849
-    public function setGridBottomComponents(array $components): self
850
-    {
851
-        $this->components[ModulePosition::GRID][ModulePosition::BOTTOM] = $components;
852
-        return $this;
853
-    }
854
-
855
-    /**
856
-     * @param string|array $components
857
-     * @return $this
858
-     */
859
-    public function addGridBottomComponents($components): self
860
-    {
861
-        if (is_string($components)) {
862
-            $components = [$components];
863
-        }
864
-        $currentComponents = $this->components[ModulePosition::GRID][ModulePosition::BOTTOM];
865
-        $this->components[ModulePosition::GRID][ModulePosition::BOTTOM] = array_merge($currentComponents, $components);
866
-        return $this;
867
-    }
868
-
869
-    /**
870
-     * @return $array
871
-     */
872
-    public function getGridButtonsComponents()
873
-    {
874
-        $configuration = $this->getModuleConfiguration();
875
-        return $configuration['components'][ModulePosition::GRID][ModulePosition::BUTTONS];
876
-    }
877
-
878
-    /**
879
-     * @param array $components
880
-     * @return $this
881
-     */
882
-    public function setGridButtonsComponents(array $components): self
883
-    {
884
-        $this->components[ModulePosition::GRID][ModulePosition::BUTTONS] = $components;
885
-        return $this;
886
-    }
887
-
888
-    /**
889
-     * @param string|array $components
890
-     * @return $this
891
-     */
892
-    public function addGridButtonsComponents($components): self
893
-    {
894
-        if (is_string($components)) {
895
-            $components = [$components];
896
-        }
897
-        $currentComponents = $this->components[ModulePosition::GRID][ModulePosition::BUTTONS];
898
-        $this->components[ModulePosition::GRID][ModulePosition::BUTTONS] = array_merge($components, $currentComponents);
899
-        return $this;
900
-    }
901
-
902
-    /**
903
-     * @return $array
904
-     */
905
-    public function getMenuMassActionComponents()
906
-    {
907
-        $configuration = $this->getModuleConfiguration();
908
-        return $configuration['components'][ModulePosition::MENU_MASS_ACTION];
909
-    }
910
-
911
-    /**
912
-     * @param array $components
913
-     * @return $this
914
-     */
915
-    public function setMenuMassActionComponents(array $components): self
916
-    {
917
-        $this->components[ModulePosition::MENU_MASS_ACTION] = $components;
918
-        return $this;
919
-    }
920
-
921
-    /**
922
-     * @param string|array $components
923
-     * @return $this
924
-     */
925
-    public function addMenuMassActionComponents($components): self
926
-    {
927
-        if (is_string($components)) {
928
-            $components = [$components];
929
-        }
930
-        $currentComponents = $this->components[ModulePosition::MENU_MASS_ACTION];
931
-        $this->components[ModulePosition::MENU_MASS_ACTION] = array_merge($components, $currentComponents);
932
-        return $this;
933
-    }
934
-
935
-    /**
936
-     * @return string
937
-     */
938
-    protected function getAccess(): string
939
-    {
940
-        $moduleConfiguration = $this->getExistingMainConfiguration();
941
-
942
-        if ($this->access !== null) {
943
-            $access = $this->access;
944
-        } elseif ($moduleConfiguration['access']) { // existing configuration may override.
945
-            $access = $moduleConfiguration['access'];
946
-        } else {
947
-            $access = Access::USER; //default value.
948
-        }
949
-        return $access;
950
-    }
951
-
952
-    /**
953
-     * @param string $access
954
-     * @return $this
955
-     */
956
-    public function setAccess($access): self
957
-    {
958
-        $this->access = $access;
959
-        return $this;
960
-    }
961
-
962
-    /**
963
-     * @return \string[]
964
-     */
965
-    public function getAdditionalJavaScriptFiles(): array
966
-    {
967
-        if (empty($this->additionalJavaScriptFiles)) {
968
-            $this->additionalJavaScriptFiles = $this->getModuleConfiguration('additionalJavaScriptFiles');
969
-        }
970
-        return $this->additionalJavaScriptFiles;
971
-    }
972
-
973
-    /**
974
-     * @return \string[]
975
-     */
976
-    public function getAdditionalStyleSheetFiles(): array
977
-    {
978
-        if (empty($this->additionalStyleSheetFiles)) {
979
-            $this->additionalStyleSheetFiles = $this->getModuleConfiguration('additionalStyleSheetFiles');
980
-        }
981
-        return $this->additionalStyleSheetFiles;
982
-    }
983
-
984
-    /**
985
-     * @return array
986
-     */
987
-    public function getComponents(): array
988
-    {
989
-        return $this->components;
990
-    }
991
-
992
-    /**
993
-     * @param string $pluginName
994
-     * @return bool
995
-     */
996
-    public function hasPlugin($pluginName = ''): bool
997
-    {
998
-        $parameterPrefix = $this->getParameterPrefix();
999
-        $parameters = GeneralUtility::_GET($parameterPrefix);
1000
-
1001
-        $hasPlugin = !empty($parameters['plugins']) && is_array($parameters['plugins']);
1002
-        if ($hasPlugin && $pluginName) {
1003
-            $hasPlugin = in_array($pluginName, $parameters['plugins']);
1004
-        }
1005
-        return $hasPlugin;
1006
-    }
1007
-
1008
-    /**
1009
-     * Compute the internal module code
1010
-     *
1011
-     * @param null|string $dataType
1012
-     * @return string
1013
-     */
1014
-    protected function getInternalModuleSignature($dataType = null): string
1015
-    {
1016
-        // Else we forge the module signature
1017
-        if ($dataType === null) {
1018
-            $dataType = $this->dataType;
1019
-        }
1020
-        $subModuleName = $dataType . '_' . $this->moduleKey;
1021
-
1022
-        $mainModule = $this->mainModule ? : self::DEFAULT_MAIN_MODULE;
1023
-        return $mainModule . '_Vidi' . GeneralUtility::underscoredToUpperCamelCase($subModuleName);
1024
-    }
23
+	/**
24
+	 * Define the default main module
25
+	 */
26
+	const DEFAULT_MAIN_MODULE = 'content';
27
+
28
+	/**
29
+	 * Define the default pid
30
+	 */
31
+	const DEFAULT_PID = 0;
32
+
33
+	/**
34
+	 * The type of data being listed (which corresponds to a table name in TCA)
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $dataType;
39
+
40
+	/**
41
+	 * @var string
42
+	 */
43
+	protected $defaultPid;
44
+
45
+	/**
46
+	 * @var bool
47
+	 */
48
+	protected $isPidIgnored = false;
49
+
50
+	/**
51
+	 * @var bool
52
+	 */
53
+	protected $showPageTree = false;
54
+
55
+	/**
56
+	 * @var bool
57
+	 */
58
+	protected $isShown = true;
59
+
60
+	/**
61
+	 * @var string
62
+	 */
63
+	protected $access;
64
+
65
+	/**
66
+	 * @var string
67
+	 */
68
+	protected $mainModule;
69
+
70
+	/**
71
+	 * @var string
72
+	 */
73
+	protected $position = '';
74
+
75
+	/**
76
+	 * @var string
77
+	 */
78
+	protected $icon;
79
+
80
+	/**
81
+	 * @var string
82
+	 */
83
+	protected $moduleLanguageFile;
84
+
85
+	/**
86
+	 * The module key such as m1, m2.
87
+	 *
88
+	 * @var string
89
+	 */
90
+	protected $moduleKey = 'm1';
91
+
92
+	/**
93
+	 * @var string[]
94
+	 */
95
+	protected $additionalJavaScriptFiles = [];
96
+
97
+	/**
98
+	 * @var string[]
99
+	 */
100
+	protected $additionalStyleSheetFiles = [];
101
+
102
+	/**
103
+	 * @var array
104
+	 */
105
+	protected $components = [];
106
+
107
+	/**
108
+	 * @param string $dataType
109
+	 */
110
+	public function __construct($dataType = null)
111
+	{
112
+		$this->dataType = $dataType;
113
+
114
+		// Initialize components
115
+		$this->components = [
116
+			ModulePosition::DOC_HEADER => [
117
+				ModulePosition::TOP => [
118
+					ModulePosition::LEFT => [],
119
+					ModulePosition::RIGHT => [
120
+						\Fab\Vidi\View\Button\ToolButton::class,
121
+					],
122
+				],
123
+				ModulePosition::BOTTOM => [
124
+					ModulePosition::LEFT => [
125
+						\Fab\Vidi\View\Button\NewButton::class,
126
+						\Fab\Vidi\ViewHelpers\Link\BackViewHelper::class,
127
+					],
128
+					ModulePosition::RIGHT => [],
129
+				],
130
+			],
131
+			ModulePosition::GRID => [
132
+				ModulePosition::TOP => [
133
+					\Fab\Vidi\View\Check\PidCheck::class,
134
+					\Fab\Vidi\View\Check\RelationsCheck::class,
135
+					#\Fab\Vidi\View\Tab\DataTypeTab::class,
136
+				],
137
+				ModulePosition::BUTTONS => [
138
+					\Fab\Vidi\View\Button\EditButton::class,
139
+					\Fab\Vidi\View\Button\DeleteButton::class,
140
+				],
141
+				ModulePosition::BOTTOM => [],
142
+			],
143
+			ModulePosition::MENU_MASS_ACTION => [
144
+				\Fab\Vidi\View\MenuItem\ExportXlsMenuItem::class,
145
+				\Fab\Vidi\View\MenuItem\ExportXmlMenuItem::class,
146
+				\Fab\Vidi\View\MenuItem\ExportCsvMenuItem::class,
147
+				\Fab\Vidi\View\MenuItem\DividerMenuItem::class,
148
+				\Fab\Vidi\View\MenuItem\MassDeleteMenuItem::class,
149
+				#\Fab\Vidi\View\MenuItem\MassEditMenuItem::class,
150
+			],
151
+		];
152
+	}
153
+
154
+	/**
155
+	 * Tell whether a module is already registered.
156
+	 *
157
+	 * @param string $dataType
158
+	 * @return bool
159
+	 */
160
+	public function isRegistered($dataType): bool
161
+	{
162
+		$internalModuleSignature = $this->getInternalModuleSignature($dataType);
163
+		return !empty($GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature]);
164
+	}
165
+
166
+	/**
167
+	 * @return array
168
+	 */
169
+	protected function getExistingInternalConfiguration(): array
170
+	{
171
+		$internalModuleSignature = $this->getInternalModuleSignature();
172
+		return is_array($GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature])
173
+			? $GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature]
174
+			: [];
175
+	}
176
+
177
+	/**
178
+	 * @return array
179
+	 */
180
+	protected function getExistingMainConfiguration(): array
181
+	{
182
+		$possibleConfiguration = $GLOBALS['TBE_MODULES']['_configuration'][$this->computeMainModule() . '_' . $this->getInternalModuleSignature()];
183
+		return is_array($possibleConfiguration) ? $possibleConfiguration : [];
184
+	}
185
+
186
+	/**
187
+	 * @return string
188
+	 */
189
+	protected function computeMainModule(): string
190
+	{
191
+		$existingConfiguration = $this->getExistingInternalConfiguration();
192
+
193
+		if ($this->mainModule !== null) {
194
+			$mainModule = $this->mainModule;
195
+		} elseif ($existingConfiguration['mainModule']) { // existing configuration may override.
196
+			$mainModule = $existingConfiguration['mainModule'];
197
+		} else {
198
+			$mainModule = self::DEFAULT_MAIN_MODULE; //default value.
199
+		}
200
+		return $mainModule;
201
+	}
202
+
203
+	/**
204
+	 * @return string
205
+	 */
206
+	protected function computeDefaultPid(): string
207
+	{
208
+		$existingConfiguration = $this->getExistingInternalConfiguration();
209
+
210
+		if ($this->defaultPid !== null) {
211
+			$defaultPid = $this->defaultPid;
212
+		} elseif ($existingConfiguration['defaultPid']) { // existing configuration may override.
213
+			$defaultPid = $existingConfiguration['defaultPid'];
214
+		} else {
215
+			$defaultPid = self::DEFAULT_PID; //default value.
216
+		}
217
+		return $defaultPid;
218
+	}
219
+
220
+	/**
221
+	 * @return array
222
+	 */
223
+	protected function computeAdditionalJavaScriptFiles(): array
224
+	{
225
+		$additionalJavaScriptFiles = $this->additionalJavaScriptFiles;
226
+
227
+		// Possible merge of existing javascript files.
228
+		$existingConfiguration = $this->getExistingInternalConfiguration();
229
+		if ($existingConfiguration['additionalJavaScriptFiles']) {
230
+			$additionalJavaScriptFiles = array_merge($additionalJavaScriptFiles, $existingConfiguration['additionalJavaScriptFiles']);
231
+		}
232
+
233
+		return $additionalJavaScriptFiles;
234
+	}
235
+
236
+	/**
237
+	 * @return array
238
+	 */
239
+	protected function computeAdditionalStyleSheetFiles(): array
240
+	{
241
+		$additionalStyleSheetFiles = $this->additionalStyleSheetFiles;
242
+
243
+		// Possible merge of existing style sheets.
244
+		$existingConfiguration = $this->getExistingInternalConfiguration();
245
+		if ($existingConfiguration['additionalStyleSheetFiles']) {
246
+			$additionalStyleSheetFiles = array_merge($additionalStyleSheetFiles, $existingConfiguration['additionalStyleSheetFiles']);
247
+		}
248
+
249
+		return $additionalStyleSheetFiles;
250
+	}
251
+
252
+	/**
253
+	 * @return array
254
+	 */
255
+	protected function computeComponents(): array
256
+	{
257
+		// We override the config in any case. See if we need more than that.
258
+		return $this->components;
259
+	}
260
+
261
+	/**
262
+	 * Register the module in two places: core + vidi internal.
263
+	 *
264
+	 * @return void
265
+	 */
266
+	public function register(): void
267
+	{
268
+		// Internal Vidi module registration.
269
+		$configuration = [];
270
+		$configuration['dataType'] = $this->dataType;
271
+		$configuration['mainModule'] = $this->computeMainModule();
272
+		$configuration['defaultPid'] = $this->computeDefaultPid();
273
+		$configuration['additionalJavaScriptFiles'] = $this->computeAdditionalJavaScriptFiles();
274
+		$configuration['additionalStyleSheetFiles'] = $this->computeAdditionalStyleSheetFiles();
275
+		$configuration['components'] = $this->computeComponents();
276
+		$configuration['isPidIgnored'] = $this->isPidIgnored;
277
+
278
+		$internalModuleSignature = $this->getInternalModuleSignature();
279
+		$GLOBALS['TBE_MODULES_EXT']['vidi'][$internalModuleSignature] = $configuration;
280
+
281
+		// Core module registration.
282
+		// Register and displays module in the BE only if told, default is "true".
283
+		if ($this->isShown) {
284
+
285
+			$moduleConfiguration = [];
286
+			#$moduleConfiguration['routeTarget'] = \Fab\Vidi\Controller\ContentController::class . '::mainAction', // what to do here?
287
+			$moduleConfiguration['access'] = $this->getAccess();
288
+			$moduleConfiguration['labels'] = $this->getModuleLanguageFile();
289
+			$icon = $this->getIcon();
290
+			if ($icon) {
291
+				$moduleConfiguration['icon'] = $icon;
292
+			}
293
+
294
+			if ($this->showPageTree) {
295
+				$moduleConfiguration['navigationComponentId'] = 'TYPO3/CMS/Backend/PageTree/PageTreeElement';
296
+				$moduleConfiguration['inheritNavigationComponentFromMainModule'] = true;
297
+			} else {
298
+				$moduleConfiguration['inheritNavigationComponentFromMainModule'] = true;
299
+			}
300
+
301
+			ExtensionUtility::registerModule(
302
+				'Fab.vidi',
303
+				$this->computeMainModule(),
304
+				$this->dataType . '_' . $this->moduleKey,
305
+				$this->position,
306
+				[
307
+					'Content' => 'index, list, delete, update, edit, copy, move, localize, sort, copyClipboard, moveClipboard',
308
+					'Tool' => 'welcome, work',
309
+					'Facet' => 'autoSuggest, autoSuggests',
310
+					'Selection' => 'edit, update, create, delete, list, show',
311
+					'UserPreferences' => 'save',
312
+					'Clipboard' => 'save, flush, show',
313
+				],
314
+				$moduleConfiguration
315
+			);
316
+		}
317
+	}
318
+
319
+	/**
320
+	 * Return the module code for a BE module.
321
+	 *
322
+	 * @return string
323
+	 */
324
+	public function getSignature(): string
325
+	{
326
+		$signature = GeneralUtility::_GP(Parameter::MODULE);
327
+		$trimmedSignature = trim($signature, '/');
328
+		return str_replace('/', '_', $trimmedSignature);
329
+	}
330
+
331
+	/**
332
+	 * Returns the current pid.
333
+	 *
334
+	 * @return bool
335
+	 */
336
+	public function getCurrentPid(): bool
337
+	{
338
+		return GeneralUtility::_GET(Parameter::PID) > 0 ? (int)GeneralUtility::_GET(Parameter::PID) : 0;
339
+	}
340
+
341
+	/**
342
+	 * Return the module URL.
343
+	 *
344
+	 * @param array $additionalParameters
345
+	 * @return string
346
+	 */
347
+	public function getModuleUrl(array $additionalParameters = []): string
348
+	{
349
+		$moduleCode = $this->getSignature();
350
+
351
+		// And don't forget the pid!
352
+		if (GeneralUtility::_GET(Parameter::PID)) {
353
+			$additionalParameters[Parameter::PID] = GeneralUtility::_GET(Parameter::PID);
354
+		}
355
+
356
+		return BackendUtility::getModuleUrl($moduleCode, $additionalParameters);
357
+	}
358
+
359
+	/**
360
+	 * Return the parameter prefix for a BE module.
361
+	 *
362
+	 * @return string
363
+	 */
364
+	public function getParameterPrefix(): string
365
+	{
366
+		return 'tx_vidi_' . strtolower($this->getSignature());
367
+	}
368
+
369
+	/**
370
+	 * Return a configuration key or the entire module configuration array if not key is given.
371
+	 *
372
+	 * @param string $key
373
+	 * @return mixed
374
+	 */
375
+	public function getModuleConfiguration($key = '')
376
+	{
377
+
378
+		$vidiModuleCode = $this->getSignature();
379
+
380
+		// Module code must exist
381
+		if (empty($GLOBALS['TBE_MODULES_EXT']['vidi'][$vidiModuleCode])) {
382
+			$message = sprintf('Invalid or not existing module code "%s"', $vidiModuleCode);
383
+			throw new InvalidKeyInArrayException($message, 1375092053);
384
+		}
385
+
386
+		$result = $GLOBALS['TBE_MODULES_EXT']['vidi'][$vidiModuleCode];
387
+
388
+		if (!empty($key)) {
389
+			if (isset($result[$key])) {
390
+				$result = $result[$key];
391
+			} else {
392
+				// key must exist
393
+				$message = sprintf('Invalid key configuration "%s"', $key);
394
+				throw new InvalidKeyInArrayException($message, 1375092054);
395
+			}
396
+		}
397
+		return $result;
398
+	}
399
+
400
+	/**
401
+	 * @param string $icon
402
+	 * @return $this
403
+	 */
404
+	public function setIcon($icon): self
405
+	{
406
+		$this->icon = $icon;
407
+		return $this;
408
+	}
409
+
410
+	/**
411
+	 * @return string
412
+	 */
413
+	protected function getIcon(): string
414
+	{
415
+		$moduleConfiguration = $this->getExistingMainConfiguration();
416
+
417
+
418
+		if ($this->icon) {
419
+			$icon = $this->icon;
420
+		} elseif ($moduleConfiguration['icon']) { // existing configuration may override.
421
+			$icon = $moduleConfiguration['icon'];
422
+		} else {
423
+			$icon = ''; //default value.
424
+		}
425
+
426
+		return $icon;
427
+	}
428
+
429
+	/**
430
+	 * @param string $mainModule
431
+	 * @return $this
432
+	 */
433
+	public function setMainModule($mainModule): self
434
+	{
435
+		$this->mainModule = $mainModule;
436
+		return $this;
437
+	}
438
+
439
+	/**
440
+	 * @return string
441
+	 */
442
+	public function getMainModule(): string
443
+	{
444
+		if ($this->mainModule === null) {
445
+			$this->mainModule = $this->getModuleConfiguration('mainModule');
446
+		}
447
+		return $this->mainModule;
448
+	}
449
+
450
+	/**
451
+	 * @param string $moduleLanguageFile
452
+	 * @return $this
453
+	 */
454
+	public function setModuleLanguageFile($moduleLanguageFile): self
455
+	{
456
+		$this->moduleLanguageFile = $moduleLanguageFile;
457
+		return $this;
458
+	}
459
+
460
+	/**
461
+	 * @param string $component
462
+	 * @return $this
463
+	 */
464
+	public function removeComponentFromDocHeader(string $component): self
465
+	{
466
+		foreach ($this->components[ModulePosition::DOC_HEADER] as $verticalPosition => $docHeaders) {
467
+			foreach ($docHeaders as $horizontalPosition => $docHeader) {
468
+
469
+				$index = array_search($component, $docHeader, true);
470
+				if ($index !== false) {
471
+					// $verticalPosition: top or bottom
472
+					// $horizontalPosition: left or right
473
+					unset($this->components[ModulePosition::DOC_HEADER][$verticalPosition][$horizontalPosition][$index]);
474
+				}
475
+			}
476
+		}
477
+		return $this;
478
+	}
479
+
480
+	/**
481
+	 * @param bool $isPidIgnored
482
+	 * @return $this
483
+	 */
484
+	public function ignorePid(bool $isPidIgnored): self
485
+	{
486
+		$this->isPidIgnored = $isPidIgnored;
487
+		return $this;
488
+	}
489
+
490
+	/**
491
+	 * @return bool
492
+	 */
493
+	public function isPidIgnored(): bool
494
+	{
495
+		return $this->getModuleConfiguration('isPidIgnored');
496
+	}
497
+
498
+	/**
499
+	 * @param string $component
500
+	 * @return bool
501
+	 */
502
+	public function hasComponentInDocHeader(string $component): bool
503
+	{
504
+		foreach ($this->getModuleConfiguration('components')[ModulePosition::DOC_HEADER] as $verticalPosition => $docHeaders) {
505
+			foreach ($docHeaders as $horizontalPosition => $docHeader) {
506
+
507
+				$index = array_search($component, $docHeader, true);
508
+				if ($index !== false) {
509
+					return true;
510
+				}
511
+			}
512
+		}
513
+		return false;
514
+	}
515
+
516
+	/**
517
+	 * @return string
518
+	 */
519
+	protected function getModuleLanguageFile(): string
520
+	{
521
+		$moduleConfiguration = $this->getExistingMainConfiguration();
522
+
523
+		if ($this->moduleLanguageFile) {
524
+			$moduleLanguageFile = $this->moduleLanguageFile;
525
+		} elseif ($moduleConfiguration['labels']) { // existing configuration may override.
526
+			$moduleLanguageFile = $moduleConfiguration['labels'];
527
+		}
528
+		else {
529
+			$moduleLanguageFile = ''; //default value.
530
+		}
531
+
532
+		return $moduleLanguageFile;
533
+	}
534
+
535
+	/**
536
+	 * @param string $position
537
+	 * @return $this
538
+	 */
539
+	public function setPosition($position): self
540
+	{
541
+		$this->position = $position;
542
+		return $this;
543
+	}
544
+
545
+	/**
546
+	 * @return string
547
+	 */
548
+	public function getPosition(): string
549
+	{
550
+		return $this->position;
551
+	}
552
+
553
+	/**
554
+	 * @param array $files
555
+	 * @return $this
556
+	 */
557
+	public function addJavaScriptFiles(array $files): self
558
+	{
559
+		foreach ($files as $file) {
560
+			$this->additionalJavaScriptFiles[] = $file;
561
+		}
562
+		return $this;
563
+	}
564
+
565
+	/**
566
+	 * @param string $fileNameAndPath
567
+	 * @return $this
568
+	 */
569
+	public function addJavaScriptFile($fileNameAndPath): self
570
+	{
571
+		$this->additionalJavaScriptFiles[] = $fileNameAndPath;
572
+		return $this;
573
+	}
574
+
575
+	/**
576
+	 * @param array $files
577
+	 * @return $this
578
+	 */
579
+	public function addStyleSheetFiles(array $files): self
580
+	{
581
+		foreach ($files as $file) {
582
+			$this->additionalStyleSheetFiles[] = $file;
583
+		}
584
+		return $this;
585
+	}
586
+
587
+	/**
588
+	 * @param string $fileNameAndPath
589
+	 * @return $this
590
+	 */
591
+	public function addStyleSheetFile($fileNameAndPath): self
592
+	{
593
+		$this->additionalStyleSheetFiles[] = $fileNameAndPath;
594
+		return $this;
595
+	}
596
+
597
+	/**
598
+	 * @return string
599
+	 */
600
+	public function getDataType(): string
601
+	{
602
+		if ($this->dataType === null) {
603
+			$this->dataType = $this->getModuleConfiguration('dataType');
604
+		}
605
+		return $this->dataType;
606
+	}
607
+
608
+	/**
609
+	 * @return array
610
+	 */
611
+	public function getDataTypes(): array
612
+	{
613
+		$dataTypes = [];
614
+		foreach ($GLOBALS['TBE_MODULES_EXT']['vidi'] as $module) {
615
+			$dataTypes[] = $module['dataType'];
616
+		}
617
+		return $dataTypes;
618
+	}
619
+
620
+	/**
621
+	 * @param string $dataType
622
+	 * @return $this
623
+	 */
624
+	public function setDataType($dataType): self
625
+	{
626
+		$this->dataType = $dataType;
627
+		return $this;
628
+	}
629
+
630
+	/**
631
+	 * @return string
632
+	 */
633
+	public function getDefaultPid(): string
634
+	{
635
+		if (empty($this->defaultPid)) {
636
+			$this->defaultPid = $this->getModuleConfiguration('defaultPid');
637
+		}
638
+		return $this->defaultPid;
639
+	}
640
+
641
+	/**
642
+	 * @param string $defaultPid
643
+	 * @return $this
644
+	 */
645
+	public function setDefaultPid($defaultPid): self
646
+	{
647
+		$this->defaultPid = $defaultPid;
648
+		return $this;
649
+	}
650
+
651
+	/**
652
+	 * @param bool $isPageTreeShown
653
+	 * @return $this
654
+	 */
655
+	public function showPageTree($isPageTreeShown): self
656
+	{
657
+		$this->showPageTree = $isPageTreeShown;
658
+		return $this;
659
+	}
660
+
661
+	/**
662
+	 * @param string $isShown
663
+	 * @return $this
664
+	 */
665
+	public function isShown($isShown): self
666
+	{
667
+		$this->isShown = $isShown;
668
+		return $this;
669
+	}
670
+
671
+	/**
672
+	 * @return $array
673
+	 */
674
+	public function getDocHeaderTopLeftComponents()
675
+	{
676
+		$configuration = $this->getModuleConfiguration();
677
+		return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT];
678
+	}
679
+
680
+	/**
681
+	 * @param array $components
682
+	 * @return $this
683
+	 */
684
+	public function setDocHeaderTopLeftComponents(array $components): self
685
+	{
686
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT] = $components;
687
+		return $this;
688
+	}
689
+
690
+	/**
691
+	 * @param string|array $components
692
+	 * @return $this
693
+	 */
694
+	public function addDocHeaderTopLeftComponents($components): self
695
+	{
696
+		if (is_string($components)) {
697
+			$components = [$components];
698
+		}
699
+		$currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT];
700
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::LEFT] = array_merge($currentComponents, $components);
701
+		return $this;
702
+	}
703
+
704
+	/**
705
+	 * @return $array
706
+	 */
707
+	public function getDocHeaderTopRightComponents()
708
+	{
709
+		$configuration = $this->getModuleConfiguration();
710
+		return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT];
711
+	}
712
+
713
+	/**
714
+	 * @param array $components
715
+	 * @return $this
716
+	 */
717
+	public function setDocHeaderTopRightComponents(array $components): self
718
+	{
719
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT] = $components;
720
+		return $this;
721
+	}
722
+
723
+	/**
724
+	 * @param string|array $components
725
+	 * @return $this
726
+	 */
727
+	public function addDocHeaderTopRightComponents($components): self
728
+	{
729
+		if (is_string($components)) {
730
+			$components = [$components];
731
+		}
732
+		$currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT];
733
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::TOP][ModulePosition::RIGHT] = array_merge($currentComponents, $components);
734
+		return $this;
735
+	}
736
+
737
+	/**
738
+	 * @return $array
739
+	 */
740
+	public function getDocHeaderBottomLeftComponents()
741
+	{
742
+		$configuration = $this->getModuleConfiguration();
743
+		return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT];
744
+	}
745
+
746
+	/**
747
+	 * @param array $components
748
+	 * @return $this
749
+	 */
750
+	public function setDocHeaderBottomLeftComponents(array $components): self
751
+	{
752
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT] = $components;
753
+		return $this;
754
+	}
755
+
756
+	/**
757
+	 * @param string|array $components
758
+	 * @return $this
759
+	 */
760
+	public function addDocHeaderBottomLeftComponents($components): self
761
+	{
762
+		if (is_string($components)) {
763
+			$components = [$components];
764
+		}
765
+		$currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT];
766
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::LEFT] = array_merge($currentComponents, $components);
767
+		return $this;
768
+	}
769
+
770
+	/**
771
+	 * @return $array
772
+	 */
773
+	public function getDocHeaderBottomRightComponents()
774
+	{
775
+		$configuration = $this->getModuleConfiguration();
776
+		return $configuration['components'][ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT];
777
+	}
778
+
779
+	/**
780
+	 * @param array $components
781
+	 * @return $this
782
+	 */
783
+	public function setDocHeaderBottomRightComponents(array $components): self
784
+	{
785
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT] = $components;
786
+		return $this;
787
+	}
788
+
789
+	/**
790
+	 * @param string|array $components
791
+	 * @return $this
792
+	 */
793
+	public function addDocHeaderBottomRightComponents($components): self
794
+	{
795
+		if (is_string($components)) {
796
+			$components = [$components];
797
+		}
798
+		$currentComponents = $this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT];
799
+		$this->components[ModulePosition::DOC_HEADER][ModulePosition::BOTTOM][ModulePosition::RIGHT] = array_merge($currentComponents, $components);
800
+		return $this;
801
+	}
802
+
803
+	/**
804
+	 * @return $array
805
+	 */
806
+	public function getGridTopComponents()
807
+	{
808
+		$configuration = $this->getModuleConfiguration();
809
+		return $configuration['components'][ModulePosition::GRID][ModulePosition::TOP];
810
+	}
811
+
812
+	/**
813
+	 * @param array $components
814
+	 * @return $this
815
+	 */
816
+	public function setGridTopComponents(array $components): self
817
+	{
818
+		$this->components[ModulePosition::GRID][ModulePosition::TOP] = $components;
819
+		return $this;
820
+	}
821
+
822
+	/**
823
+	 * @param string|array $components
824
+	 * @return $this
825
+	 */
826
+	public function addGridTopComponents($components): self
827
+	{
828
+		if (is_string($components)) {
829
+			$components = [$components];
830
+		}
831
+		$currentComponents = $this->components[ModulePosition::GRID][ModulePosition::TOP];
832
+		$this->components[ModulePosition::GRID][ModulePosition::TOP] = array_merge($currentComponents, $components);
833
+		return $this;
834
+	}
835
+
836
+	/**
837
+	 * @return mixed $array
838
+	 */
839
+	public function getGridBottomComponents()
840
+	{
841
+		$configuration = $this->getModuleConfiguration();
842
+		return $configuration['components'][ModulePosition::GRID][ModulePosition::BOTTOM];
843
+	}
844
+
845
+	/**
846
+	 * @param array $components
847
+	 * @return $this
848
+	 */
849
+	public function setGridBottomComponents(array $components): self
850
+	{
851
+		$this->components[ModulePosition::GRID][ModulePosition::BOTTOM] = $components;
852
+		return $this;
853
+	}
854
+
855
+	/**
856
+	 * @param string|array $components
857
+	 * @return $this
858
+	 */
859
+	public function addGridBottomComponents($components): self
860
+	{
861
+		if (is_string($components)) {
862
+			$components = [$components];
863
+		}
864
+		$currentComponents = $this->components[ModulePosition::GRID][ModulePosition::BOTTOM];
865
+		$this->components[ModulePosition::GRID][ModulePosition::BOTTOM] = array_merge($currentComponents, $components);
866
+		return $this;
867
+	}
868
+
869
+	/**
870
+	 * @return $array
871
+	 */
872
+	public function getGridButtonsComponents()
873
+	{
874
+		$configuration = $this->getModuleConfiguration();
875
+		return $configuration['components'][ModulePosition::GRID][ModulePosition::BUTTONS];
876
+	}
877
+
878
+	/**
879
+	 * @param array $components
880
+	 * @return $this
881
+	 */
882
+	public function setGridButtonsComponents(array $components): self
883
+	{
884
+		$this->components[ModulePosition::GRID][ModulePosition::BUTTONS] = $components;
885
+		return $this;
886
+	}
887
+
888
+	/**
889
+	 * @param string|array $components
890
+	 * @return $this
891
+	 */
892
+	public function addGridButtonsComponents($components): self
893
+	{
894
+		if (is_string($components)) {
895
+			$components = [$components];
896
+		}
897
+		$currentComponents = $this->components[ModulePosition::GRID][ModulePosition::BUTTONS];
898
+		$this->components[ModulePosition::GRID][ModulePosition::BUTTONS] = array_merge($components, $currentComponents);
899
+		return $this;
900
+	}
901
+
902
+	/**
903
+	 * @return $array
904
+	 */
905
+	public function getMenuMassActionComponents()
906
+	{
907
+		$configuration = $this->getModuleConfiguration();
908
+		return $configuration['components'][ModulePosition::MENU_MASS_ACTION];
909
+	}
910
+
911
+	/**
912
+	 * @param array $components
913
+	 * @return $this
914
+	 */
915
+	public function setMenuMassActionComponents(array $components): self
916
+	{
917
+		$this->components[ModulePosition::MENU_MASS_ACTION] = $components;
918
+		return $this;
919
+	}
920
+
921
+	/**
922
+	 * @param string|array $components
923
+	 * @return $this
924
+	 */
925
+	public function addMenuMassActionComponents($components): self
926
+	{
927
+		if (is_string($components)) {
928
+			$components = [$components];
929
+		}
930
+		$currentComponents = $this->components[ModulePosition::MENU_MASS_ACTION];
931
+		$this->components[ModulePosition::MENU_MASS_ACTION] = array_merge($components, $currentComponents);
932
+		return $this;
933
+	}
934
+
935
+	/**
936
+	 * @return string
937
+	 */
938
+	protected function getAccess(): string
939
+	{
940
+		$moduleConfiguration = $this->getExistingMainConfiguration();
941
+
942
+		if ($this->access !== null) {
943
+			$access = $this->access;
944
+		} elseif ($moduleConfiguration['access']) { // existing configuration may override.
945
+			$access = $moduleConfiguration['access'];
946
+		} else {
947
+			$access = Access::USER; //default value.
948
+		}
949
+		return $access;
950
+	}
951
+
952
+	/**
953
+	 * @param string $access
954
+	 * @return $this
955
+	 */
956
+	public function setAccess($access): self
957
+	{
958
+		$this->access = $access;
959
+		return $this;
960
+	}
961
+
962
+	/**
963
+	 * @return \string[]
964
+	 */
965
+	public function getAdditionalJavaScriptFiles(): array
966
+	{
967
+		if (empty($this->additionalJavaScriptFiles)) {
968
+			$this->additionalJavaScriptFiles = $this->getModuleConfiguration('additionalJavaScriptFiles');
969
+		}
970
+		return $this->additionalJavaScriptFiles;
971
+	}
972
+
973
+	/**
974
+	 * @return \string[]
975
+	 */
976
+	public function getAdditionalStyleSheetFiles(): array
977
+	{
978
+		if (empty($this->additionalStyleSheetFiles)) {
979
+			$this->additionalStyleSheetFiles = $this->getModuleConfiguration('additionalStyleSheetFiles');
980
+		}
981
+		return $this->additionalStyleSheetFiles;
982
+	}
983
+
984
+	/**
985
+	 * @return array
986
+	 */
987
+	public function getComponents(): array
988
+	{
989
+		return $this->components;
990
+	}
991
+
992
+	/**
993
+	 * @param string $pluginName
994
+	 * @return bool
995
+	 */
996
+	public function hasPlugin($pluginName = ''): bool
997
+	{
998
+		$parameterPrefix = $this->getParameterPrefix();
999
+		$parameters = GeneralUtility::_GET($parameterPrefix);
1000
+
1001
+		$hasPlugin = !empty($parameters['plugins']) && is_array($parameters['plugins']);
1002
+		if ($hasPlugin && $pluginName) {
1003
+			$hasPlugin = in_array($pluginName, $parameters['plugins']);
1004
+		}
1005
+		return $hasPlugin;
1006
+	}
1007
+
1008
+	/**
1009
+	 * Compute the internal module code
1010
+	 *
1011
+	 * @param null|string $dataType
1012
+	 * @return string
1013
+	 */
1014
+	protected function getInternalModuleSignature($dataType = null): string
1015
+	{
1016
+		// Else we forge the module signature
1017
+		if ($dataType === null) {
1018
+			$dataType = $this->dataType;
1019
+		}
1020
+		$subModuleName = $dataType . '_' . $this->moduleKey;
1021
+
1022
+		$mainModule = $this->mainModule ? : self::DEFAULT_MAIN_MODULE;
1023
+		return $mainModule . '_Vidi' . GeneralUtility::underscoredToUpperCamelCase($subModuleName);
1024
+	}
1025 1025
 
1026 1026
 }
Please login to merge, or discard this patch.
Classes/Persistence/MatcherObjectFactory.php 1 patch
Indentation   +272 added lines, -272 removed lines patch added patch discarded remove patch
@@ -25,276 +25,276 @@
 block discarded – undo
25 25
 class MatcherObjectFactory implements SingletonInterface
26 26
 {
27 27
 
28
-    /**
29
-     * Gets a singleton instance of this class.
30
-     *
31
-     * @return $this
32
-     */
33
-    static public function getInstance(): self
34
-    {
35
-        return GeneralUtility::makeInstance(self::class);
36
-    }
37
-
38
-    /**
39
-     * Returns a matcher object.
40
-     *
41
-     * @param array $matches
42
-     * @param string $dataType
43
-     * @return Matcher
44
-     */
45
-    public function getMatcher(array $matches = [], $dataType = ''): Matcher
46
-    {
47
-        if ($dataType === '') {
48
-            $dataType = $this->getModuleLoader()->getDataType();
49
-        }
50
-
51
-        /** @var $matcher Matcher */
52
-        $matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType);
53
-
54
-        $matcher = $this->applyCriteriaFromDataTables($matcher);
55
-        $matcher = $this->applyCriteriaFromMatchesArgument($matcher, $matches);
56
-
57
-        if ($this->isBackendMode()) {
58
-            $matcher = $this->applyCriteriaFromUrl($matcher);
59
-            $matcher = $this->applyCriteriaFromTSConfig($matcher);
60
-        }
61
-
62
-        // Trigger signal for post processing Matcher Object.
63
-        $this->emitPostProcessMatcherObjectSignal($matcher);
64
-
65
-        return $matcher;
66
-    }
67
-
68
-    /**
69
-     * Get a possible id from the URL and apply as filter criteria.
70
-     * Except if the main module belongs to the File. The id would be a combined identifier
71
-     * including the storage and a mount point.
72
-     *
73
-     * @param Matcher $matcher
74
-     * @return Matcher $matcher
75
-     */
76
-    protected function applyCriteriaFromUrl(Matcher $matcher): Matcher
77
-    {
78
-        if (GeneralUtility::_GP('id')
79
-            && !$this->getModuleLoader()->isPidIgnored()
80
-            && $this->getModuleLoader()->getMainModule() !== ModuleName::FILE) {
81
-            $matcher->equals('pid', GeneralUtility::_GP('id'));
82
-        }
83
-
84
-        return $matcher;
85
-    }
86
-
87
-    /**
88
-     * @param Matcher $matcher
89
-     * @return Matcher $matcher
90
-     */
91
-    protected function applyCriteriaFromTSConfig(Matcher $matcher): Matcher
92
-    {
93
-        $dataType = $matcher->getDataType();
94
-        $tsConfigPath = sprintf('tx_vidi.dataType.%s.constraints', $dataType);
95
-        $tsConfig = $this->getBackendUser()->getTSConfig($tsConfigPath);
96
-
97
-        if (is_array($tsConfig['properties']) && !empty($tsConfig['properties'])) {
98
-
99
-            foreach ($tsConfig['properties'] as $constraint) {
100
-
101
-                if (preg_match('/(.+) (>=|>|<|<=|=|like) (.+)/is', $constraint, $matches) && count($matches) === 4) {
102
-
103
-                    $operator = $matcher->getSupportedOperators()[strtolower(trim($matches[2]))];
104
-                    $operand = trim($matches[1]);
105
-                    $value = trim($matches[3]);
106
-
107
-                    $matcher->$operator($operand, $value);
108
-                } elseif (preg_match('/(.+) (in) (.+)/is', $constraint, $matches) && count($matches) === 4) {
109
-
110
-                    $operator = $matcher->getSupportedOperators()[trim($matches[2])];
111
-                    $operand = trim($matches[1]);
112
-                    $value = trim($matches[3]);
113
-                    $matcher->$operator($operand, GeneralUtility::trimExplode(',', $value, true));
114
-                }
115
-            }
116
-        }
117
-
118
-        return $matcher;
119
-    }
120
-
121
-    /**
122
-     * @param Matcher $matcher
123
-     * @param array $matches
124
-     * @return Matcher $matcher
125
-     */
126
-    protected function applyCriteriaFromMatchesArgument(Matcher $matcher, $matches): Matcher
127
-    {
128
-        foreach ($matches as $fieldNameAndPath => $value) {
129
-            // CSV values should be considered as "in" operator in the query, otherwise "equals".
130
-            $explodedValues = GeneralUtility::trimExplode(',', $value, true);
131
-            if (count($explodedValues) > 1) {
132
-                $matcher->in($fieldNameAndPath, $explodedValues);
133
-            } else {
134
-                $matcher->equals($fieldNameAndPath, $explodedValues[0]);
135
-            }
136
-        }
137
-
138
-        return $matcher;
139
-    }
140
-
141
-    /**
142
-     * Apply criteria specific to jQuery plugin DataTable.
143
-     *
144
-     * @param Matcher $matcher
145
-     * @return Matcher $matcher
146
-     */
147
-    protected function applyCriteriaFromDataTables(Matcher $matcher): Matcher
148
-    {
149
-
150
-        // Special case for Grid in the BE using jQuery DataTables plugin.
151
-        // Retrieve a possible search term from GP.
152
-        $query = GeneralUtility::_GP('search');
153
-        if (is_array($query)) {
154
-            if (!empty($query['value'])) {
155
-                $query = $query['value'];
156
-            } else {
157
-                $query = '';
158
-            }
159
-        }
160
-
161
-        if (strlen($query) > 0) {
162
-
163
-            // Parse the json query coming from the Visual Search.
164
-            $query = rawurldecode($query);
165
-            $queryParts = json_decode($query, true);
166
-
167
-            if (is_array($queryParts)) {
168
-                $matcher = $this->parseQuery($queryParts, $matcher);
169
-            } else {
170
-                $matcher->setSearchTerm($query);
171
-            }
172
-        }
173
-        return $matcher;
174
-    }
175
-
176
-    /**
177
-     * @param array $queryParts
178
-     * @param Matcher $matcher
179
-     * @return Matcher $matcher
180
-     */
181
-    protected function parseQuery(array $queryParts, Matcher $matcher): Matcher
182
-    {
183
-        $dataType = $matcher->getDataType();
184
-        foreach ($queryParts as $term) {
185
-            $fieldNameAndPath = key($term);
186
-
187
-            $resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
188
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
189
-
190
-            // Retrieve the value.
191
-            $value = current($term);
192
-
193
-            if (Tca::grid($resolvedDataType)->hasFacet($fieldName) && Tca::grid($resolvedDataType)->facet($fieldName)->canModifyMatcher()) {
194
-                $matcher = Tca::grid($resolvedDataType)->facet($fieldName)->modifyMatcher($matcher, $value);
195
-            } elseif (Tca::table($resolvedDataType)->hasField($fieldName)) {
196
-                // Check whether the field exists and set it as "equal" or "like".
197
-                if ($this->isOperatorEquals($fieldNameAndPath, $dataType, $value)) {
198
-                    $matcher->equals($fieldNameAndPath, $value);
199
-                } else {
200
-                    $matcher->like($fieldNameAndPath, $value);
201
-                }
202
-            } elseif ($fieldNameAndPath === 'text') {
203
-                // Special case if field is "text" which is a pseudo field in this case.
204
-                // Set the search term which means Vidi will
205
-                // search in various fields with operator "like". The fields come from key "searchFields" in the TCA.
206
-                $matcher->setSearchTerm($value);
207
-            }
208
-        }
209
-        return $matcher;
210
-    }
211
-
212
-    /**
213
-     * Tell whether the operator should be equals instead of like for a search, e.g. if the value is numerical.
214
-     *
215
-     * @param string $fieldName
216
-     * @param string $dataType
217
-     * @param string $value
218
-     * @return bool
219
-     */
220
-    protected function isOperatorEquals($fieldName, $dataType, $value): bool
221
-    {
222
-        return (Tca::table($dataType)->field($fieldName)->hasRelation() && MathUtility::canBeInterpretedAsInteger($value))
223
-            || Tca::table($dataType)->field($fieldName)->isNumerical();
224
-    }
225
-
226
-    /**
227
-     * Signal that is called for post-processing a matcher object.
228
-     *
229
-     * @param Matcher $matcher
230
-     * @signal
231
-     */
232
-    protected function emitPostProcessMatcherObjectSignal(Matcher $matcher): void
233
-    {
234
-
235
-        if (strlen($matcher->getDataType()) <= 0) {
236
-
237
-            /** @var ModuleLoader $moduleLoader */
238
-            $moduleLoader = $this->getObjectManager()->get(ModuleLoader::class);
239
-            $matcher->setDataType($moduleLoader->getDataType());
240
-        }
241
-
242
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'postProcessMatcherObject', array($matcher, $matcher->getDataType()));
243
-    }
244
-
245
-    /**
246
-     * Get the SignalSlot dispatcher
247
-     *
248
-     * @return Dispatcher|object
249
-     */
250
-    protected function getSignalSlotDispatcher()
251
-    {
252
-        return $this->getObjectManager()->get(Dispatcher::class);
253
-    }
254
-
255
-    /**
256
-     * @return ObjectManager|object
257
-     */
258
-    protected function getObjectManager()
259
-    {
260
-        return GeneralUtility::makeInstance(ObjectManager::class);
261
-    }
262
-
263
-    /**
264
-     * Get the Vidi Module Loader.
265
-     *
266
-     * @return ModuleLoader|object
267
-     */
268
-    protected function getModuleLoader()
269
-    {
270
-        return GeneralUtility::makeInstance(ModuleLoader::class);
271
-    }
272
-
273
-    /**
274
-     * @return FieldPathResolver|object
275
-     */
276
-    protected function getFieldPathResolver()
277
-    {
278
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
279
-    }
280
-
281
-    /**
282
-     * Returns an instance of the current Backend User.
283
-     *
284
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
285
-     */
286
-    protected function getBackendUser(): \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
287
-    {
288
-        return $GLOBALS['BE_USER'];
289
-    }
290
-
291
-    /**
292
-     * Returns whether the current mode is Backend
293
-     *
294
-     * @return bool
295
-     */
296
-    protected function isBackendMode(): bool
297
-    {
298
-        return TYPO3_MODE === 'BE';
299
-    }
28
+	/**
29
+	 * Gets a singleton instance of this class.
30
+	 *
31
+	 * @return $this
32
+	 */
33
+	static public function getInstance(): self
34
+	{
35
+		return GeneralUtility::makeInstance(self::class);
36
+	}
37
+
38
+	/**
39
+	 * Returns a matcher object.
40
+	 *
41
+	 * @param array $matches
42
+	 * @param string $dataType
43
+	 * @return Matcher
44
+	 */
45
+	public function getMatcher(array $matches = [], $dataType = ''): Matcher
46
+	{
47
+		if ($dataType === '') {
48
+			$dataType = $this->getModuleLoader()->getDataType();
49
+		}
50
+
51
+		/** @var $matcher Matcher */
52
+		$matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType);
53
+
54
+		$matcher = $this->applyCriteriaFromDataTables($matcher);
55
+		$matcher = $this->applyCriteriaFromMatchesArgument($matcher, $matches);
56
+
57
+		if ($this->isBackendMode()) {
58
+			$matcher = $this->applyCriteriaFromUrl($matcher);
59
+			$matcher = $this->applyCriteriaFromTSConfig($matcher);
60
+		}
61
+
62
+		// Trigger signal for post processing Matcher Object.
63
+		$this->emitPostProcessMatcherObjectSignal($matcher);
64
+
65
+		return $matcher;
66
+	}
67
+
68
+	/**
69
+	 * Get a possible id from the URL and apply as filter criteria.
70
+	 * Except if the main module belongs to the File. The id would be a combined identifier
71
+	 * including the storage and a mount point.
72
+	 *
73
+	 * @param Matcher $matcher
74
+	 * @return Matcher $matcher
75
+	 */
76
+	protected function applyCriteriaFromUrl(Matcher $matcher): Matcher
77
+	{
78
+		if (GeneralUtility::_GP('id')
79
+			&& !$this->getModuleLoader()->isPidIgnored()
80
+			&& $this->getModuleLoader()->getMainModule() !== ModuleName::FILE) {
81
+			$matcher->equals('pid', GeneralUtility::_GP('id'));
82
+		}
83
+
84
+		return $matcher;
85
+	}
86
+
87
+	/**
88
+	 * @param Matcher $matcher
89
+	 * @return Matcher $matcher
90
+	 */
91
+	protected function applyCriteriaFromTSConfig(Matcher $matcher): Matcher
92
+	{
93
+		$dataType = $matcher->getDataType();
94
+		$tsConfigPath = sprintf('tx_vidi.dataType.%s.constraints', $dataType);
95
+		$tsConfig = $this->getBackendUser()->getTSConfig($tsConfigPath);
96
+
97
+		if (is_array($tsConfig['properties']) && !empty($tsConfig['properties'])) {
98
+
99
+			foreach ($tsConfig['properties'] as $constraint) {
100
+
101
+				if (preg_match('/(.+) (>=|>|<|<=|=|like) (.+)/is', $constraint, $matches) && count($matches) === 4) {
102
+
103
+					$operator = $matcher->getSupportedOperators()[strtolower(trim($matches[2]))];
104
+					$operand = trim($matches[1]);
105
+					$value = trim($matches[3]);
106
+
107
+					$matcher->$operator($operand, $value);
108
+				} elseif (preg_match('/(.+) (in) (.+)/is', $constraint, $matches) && count($matches) === 4) {
109
+
110
+					$operator = $matcher->getSupportedOperators()[trim($matches[2])];
111
+					$operand = trim($matches[1]);
112
+					$value = trim($matches[3]);
113
+					$matcher->$operator($operand, GeneralUtility::trimExplode(',', $value, true));
114
+				}
115
+			}
116
+		}
117
+
118
+		return $matcher;
119
+	}
120
+
121
+	/**
122
+	 * @param Matcher $matcher
123
+	 * @param array $matches
124
+	 * @return Matcher $matcher
125
+	 */
126
+	protected function applyCriteriaFromMatchesArgument(Matcher $matcher, $matches): Matcher
127
+	{
128
+		foreach ($matches as $fieldNameAndPath => $value) {
129
+			// CSV values should be considered as "in" operator in the query, otherwise "equals".
130
+			$explodedValues = GeneralUtility::trimExplode(',', $value, true);
131
+			if (count($explodedValues) > 1) {
132
+				$matcher->in($fieldNameAndPath, $explodedValues);
133
+			} else {
134
+				$matcher->equals($fieldNameAndPath, $explodedValues[0]);
135
+			}
136
+		}
137
+
138
+		return $matcher;
139
+	}
140
+
141
+	/**
142
+	 * Apply criteria specific to jQuery plugin DataTable.
143
+	 *
144
+	 * @param Matcher $matcher
145
+	 * @return Matcher $matcher
146
+	 */
147
+	protected function applyCriteriaFromDataTables(Matcher $matcher): Matcher
148
+	{
149
+
150
+		// Special case for Grid in the BE using jQuery DataTables plugin.
151
+		// Retrieve a possible search term from GP.
152
+		$query = GeneralUtility::_GP('search');
153
+		if (is_array($query)) {
154
+			if (!empty($query['value'])) {
155
+				$query = $query['value'];
156
+			} else {
157
+				$query = '';
158
+			}
159
+		}
160
+
161
+		if (strlen($query) > 0) {
162
+
163
+			// Parse the json query coming from the Visual Search.
164
+			$query = rawurldecode($query);
165
+			$queryParts = json_decode($query, true);
166
+
167
+			if (is_array($queryParts)) {
168
+				$matcher = $this->parseQuery($queryParts, $matcher);
169
+			} else {
170
+				$matcher->setSearchTerm($query);
171
+			}
172
+		}
173
+		return $matcher;
174
+	}
175
+
176
+	/**
177
+	 * @param array $queryParts
178
+	 * @param Matcher $matcher
179
+	 * @return Matcher $matcher
180
+	 */
181
+	protected function parseQuery(array $queryParts, Matcher $matcher): Matcher
182
+	{
183
+		$dataType = $matcher->getDataType();
184
+		foreach ($queryParts as $term) {
185
+			$fieldNameAndPath = key($term);
186
+
187
+			$resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
188
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
189
+
190
+			// Retrieve the value.
191
+			$value = current($term);
192
+
193
+			if (Tca::grid($resolvedDataType)->hasFacet($fieldName) && Tca::grid($resolvedDataType)->facet($fieldName)->canModifyMatcher()) {
194
+				$matcher = Tca::grid($resolvedDataType)->facet($fieldName)->modifyMatcher($matcher, $value);
195
+			} elseif (Tca::table($resolvedDataType)->hasField($fieldName)) {
196
+				// Check whether the field exists and set it as "equal" or "like".
197
+				if ($this->isOperatorEquals($fieldNameAndPath, $dataType, $value)) {
198
+					$matcher->equals($fieldNameAndPath, $value);
199
+				} else {
200
+					$matcher->like($fieldNameAndPath, $value);
201
+				}
202
+			} elseif ($fieldNameAndPath === 'text') {
203
+				// Special case if field is "text" which is a pseudo field in this case.
204
+				// Set the search term which means Vidi will
205
+				// search in various fields with operator "like". The fields come from key "searchFields" in the TCA.
206
+				$matcher->setSearchTerm($value);
207
+			}
208
+		}
209
+		return $matcher;
210
+	}
211
+
212
+	/**
213
+	 * Tell whether the operator should be equals instead of like for a search, e.g. if the value is numerical.
214
+	 *
215
+	 * @param string $fieldName
216
+	 * @param string $dataType
217
+	 * @param string $value
218
+	 * @return bool
219
+	 */
220
+	protected function isOperatorEquals($fieldName, $dataType, $value): bool
221
+	{
222
+		return (Tca::table($dataType)->field($fieldName)->hasRelation() && MathUtility::canBeInterpretedAsInteger($value))
223
+			|| Tca::table($dataType)->field($fieldName)->isNumerical();
224
+	}
225
+
226
+	/**
227
+	 * Signal that is called for post-processing a matcher object.
228
+	 *
229
+	 * @param Matcher $matcher
230
+	 * @signal
231
+	 */
232
+	protected function emitPostProcessMatcherObjectSignal(Matcher $matcher): void
233
+	{
234
+
235
+		if (strlen($matcher->getDataType()) <= 0) {
236
+
237
+			/** @var ModuleLoader $moduleLoader */
238
+			$moduleLoader = $this->getObjectManager()->get(ModuleLoader::class);
239
+			$matcher->setDataType($moduleLoader->getDataType());
240
+		}
241
+
242
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'postProcessMatcherObject', array($matcher, $matcher->getDataType()));
243
+	}
244
+
245
+	/**
246
+	 * Get the SignalSlot dispatcher
247
+	 *
248
+	 * @return Dispatcher|object
249
+	 */
250
+	protected function getSignalSlotDispatcher()
251
+	{
252
+		return $this->getObjectManager()->get(Dispatcher::class);
253
+	}
254
+
255
+	/**
256
+	 * @return ObjectManager|object
257
+	 */
258
+	protected function getObjectManager()
259
+	{
260
+		return GeneralUtility::makeInstance(ObjectManager::class);
261
+	}
262
+
263
+	/**
264
+	 * Get the Vidi Module Loader.
265
+	 *
266
+	 * @return ModuleLoader|object
267
+	 */
268
+	protected function getModuleLoader()
269
+	{
270
+		return GeneralUtility::makeInstance(ModuleLoader::class);
271
+	}
272
+
273
+	/**
274
+	 * @return FieldPathResolver|object
275
+	 */
276
+	protected function getFieldPathResolver()
277
+	{
278
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
279
+	}
280
+
281
+	/**
282
+	 * Returns an instance of the current Backend User.
283
+	 *
284
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
285
+	 */
286
+	protected function getBackendUser(): \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
287
+	{
288
+		return $GLOBALS['BE_USER'];
289
+	}
290
+
291
+	/**
292
+	 * Returns whether the current mode is Backend
293
+	 *
294
+	 * @return bool
295
+	 */
296
+	protected function isBackendMode(): bool
297
+	{
298
+		return TYPO3_MODE === 'BE';
299
+	}
300 300
 }
Please login to merge, or discard this patch.