Completed
Push — master ( 9bbc4e...53fe6d )
by Fabien
53:58
created
Classes/Tca/GridService.php 1 patch
Indentation   +703 added lines, -703 removed lines patch added patch discarded remove patch
@@ -23,708 +23,708 @@
 block discarded – undo
23 23
 class GridService extends AbstractTca
24 24
 {
25 25
 
26
-    /**
27
-     * @var array
28
-     */
29
-    protected $tca;
30
-
31
-    /**
32
-     * @var string
33
-     */
34
-    protected $tableName;
35
-
36
-    /**
37
-     * All fields available in the Grid.
38
-     *
39
-     * @var array
40
-     */
41
-    protected $fields;
42
-
43
-    /**
44
-     * All fields regardless whether they have been excluded or not.
45
-     *
46
-     * @var array
47
-     */
48
-    protected $allFields;
49
-
50
-    /**
51
-     * @var array
52
-     */
53
-    protected $instances;
54
-
55
-    /**
56
-     * @var array
57
-     */
58
-    protected $facets;
59
-
60
-    /**
61
-     * __construct
62
-     *
63
-     * @param string $tableName
64
-     */
65
-    public function __construct($tableName)
66
-    {
67
-
68
-        $this->tableName = $tableName;
69
-
70
-        if (empty($GLOBALS['TCA'][$this->tableName])) {
71
-            throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
72
-        }
73
-
74
-        $this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
75
-    }
76
-
77
-    /**
78
-     * Returns an array containing column names.
79
-     *
80
-     * @return array
81
-     */
82
-    public function getFieldNames(): array
83
-    {
84
-        $fields = $this->getFields();
85
-        return array_keys($fields) ?: [];
86
-    }
87
-
88
-    /**
89
-     * Returns an array containing column names.
90
-     *
91
-     * @return array
92
-     */
93
-    public function getAllFieldNames(): array
94
-    {
95
-        $allFields = $this->getAllFields();
96
-        return array_keys($allFields);
97
-    }
98
-
99
-    /**
100
-     * Get the label key.
101
-     *
102
-     * @param string $fieldNameAndPath
103
-     * @return string
104
-     */
105
-    public function getLabelKey($fieldNameAndPath): string
106
-    {
107
-
108
-        $field = $this->getField($fieldNameAndPath);
109
-
110
-        // First option is to get the label from the Grid TCA.
111
-        $rawLabel = '';
112
-        if (isset($field['label'])) {
113
-            $rawLabel = $field['label'];
114
-        }
115
-
116
-        // Second option is to fetch the label from the Column Renderer object.
117
-        if (!$rawLabel && $this->hasRenderers($fieldNameAndPath)) {
118
-            $renderers = $this->getRenderers($fieldNameAndPath);
119
-            /** @var $renderer ColumnRendererInterface */
120
-            foreach ($renderers as $renderer) {
121
-                if (isset($renderer['label'])) {
122
-                    $rawLabel = $renderer['label'];
123
-                    break;
124
-                }
125
-            }
126
-        }
127
-        return $rawLabel;
128
-    }
129
-
130
-    /**
131
-     * Get the translation of a label given a column name.
132
-     *
133
-     * @param string $fieldNameAndPath
134
-     * @return string
135
-     */
136
-    public function getLabel($fieldNameAndPath)
137
-    {
138
-        $label = '';
139
-        if ($this->hasLabel($fieldNameAndPath)) {
140
-            $labelKey = $this->getLabelKey($fieldNameAndPath);
141
-            try {
142
-                $label = $this->getLanguageService()->sL($labelKey);
143
-            } catch (\InvalidArgumentException $e) {
144
-            }
145
-            if (empty($label)) {
146
-                $label = $labelKey;
147
-            }
148
-        } else {
149
-
150
-            // Important to notice the label can contains a path, e.g. metadata.categories and must be resolved.
151
-            $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->tableName);
152
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->tableName);
153
-            $table = Tca::table($dataType);
154
-
155
-            if ($table->hasField($fieldName) && $table->field($fieldName)->hasLabel()) {
156
-                $label = $table->field($fieldName)->getLabel();
157
-            }
158
-        }
159
-
160
-        return $label;
161
-    }
162
-
163
-    /**
164
-     * Returns the field name given its position.
165
-     *
166
-     * @param string $position the position of the field in the grid
167
-     * @return int
168
-     */
169
-    public function getFieldNameByPosition($position): int
170
-    {
171
-        $fields = array_keys($this->getFields());
172
-        if (empty($fields[$position])) {
173
-            throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
174
-        }
175
-
176
-        return $fields[$position];
177
-    }
178
-
179
-    /**
180
-     * Returns a field name.
181
-     *
182
-     * @param string $fieldName
183
-     * @return array
184
-     */
185
-    public function getField($fieldName): array
186
-    {
187
-        $fields = $this->getFields();
188
-        return $fields[$fieldName] ?: [];
189
-    }
190
-
191
-    /**
192
-     * Returns an array containing column names for the Grid.
193
-     *
194
-     * @return array
195
-     */
196
-    public function getFields(): array
197
-    {
198
-        // Cache this operation since it can take some time.
199
-        if ($this->fields === null) {
200
-
201
-            // Fetch all available fields first.
202
-            $fields = $this->getAllFields();
203
-
204
-            if ($this->isBackendMode()) {
205
-
206
-                // Then remove the not allowed.
207
-                $fields = $this->filterByIncludedFields($fields);
208
-                $fields = $this->filterByBackendUser($fields);
209
-                $fields = $this->filterByExcludedFields($fields);
210
-            }
211
-
212
-            $this->fields = $fields;
213
-        }
214
-
215
-        return $this->fields;
216
-    }
217
-
218
-    /**
219
-     * Remove fields according to Grid configuration.
220
-     *
221
-     * @param $fields
222
-     * @return array
223
-     */
224
-    protected function filterByIncludedFields($fields): array
225
-    {
226
-
227
-        $filteredFields = $fields;
228
-        $includedFields = $this->getIncludedFields();
229
-        if (count($includedFields) > 0) {
230
-            $filteredFields = [];
231
-            foreach ($fields as $fieldNameAndPath => $configuration) {
232
-                if (in_array($fieldNameAndPath, $includedFields, true) || !Tca::table($this->tableName)->hasField($fieldNameAndPath)) {
233
-                    $filteredFields[$fieldNameAndPath] = $configuration;
234
-                }
235
-            }
236
-        }
237
-        return $filteredFields;
238
-    }
239
-
240
-    /**
241
-     * Remove fields according to BE User permission.
242
-     *
243
-     * @param $fields
244
-     * @return array
245
-     */
246
-    protected function filterByBackendUser($fields): array
247
-    {
248
-        if (!$this->getBackendUser()->isAdmin()) {
249
-            foreach ($fields as $fieldName => $field) {
250
-                if (Tca::table($this->tableName)->hasField($fieldName) && !Tca::table($this->tableName)->field($fieldName)->hasAccess()) {
251
-                    unset($fields[$fieldName]);
252
-                }
253
-            }
254
-        }
255
-        return $fields;
256
-    }
257
-
258
-    /**
259
-     * Remove fields according to Grid configuration.
260
-     *
261
-     * @param $fields
262
-     * @return array
263
-     */
264
-    protected function filterByExcludedFields($fields): array
265
-    {
266
-
267
-        // Unset excluded fields.
268
-        foreach ($this->getExcludedFields() as $excludedField) {
269
-            if (isset($fields[$excludedField])) {
270
-                unset($fields[$excludedField]);
271
-            }
272
-        }
273
-
274
-        return $fields;
275
-    }
276
-
277
-    /**
278
-     * Returns an array containing column names for the Grid.
279
-     *
280
-     * @return array
281
-     */
282
-    public function getAllFields(): array
283
-    {
284
-
285
-        // Cache this operation since it can take some time.
286
-        if ($this->allFields === null) {
287
-
288
-            $fields = is_array($this->tca['columns']) ? $this->tca['columns'] : [];
289
-            $gridFieldNames = array_keys($fields);
290
-
291
-            // Fetch all fields of the TCA and merge it back to the fields configured for Grid.
292
-            $tableFieldNames = Tca::table($this->tableName)->getFields();
293
-
294
-            // Just remove system fields from the Grid.
295
-            foreach ($tableFieldNames as $key => $fieldName) {
296
-                if (in_array($fieldName, Tca::getSystemFields())) {
297
-                    unset($tableFieldNames[$key]);
298
-                }
299
-            }
300
-
301
-            $additionalFields = array_diff($tableFieldNames, $gridFieldNames);
302
-
303
-            if (!empty($additionalFields)) {
304
-
305
-                // Pop out last element of the key
306
-                // Idea is to place new un-configured columns in between. By default, they will be hidden.
307
-                end($fields);
308
-                $lastColumnKey = key($fields);
309
-                $lastColumn = array_pop($fields);
310
-
311
-                // Feed up the grid fields with un configured elements
312
-                foreach ($additionalFields as $additionalField) {
313
-                    $fields[$additionalField] = array(
314
-                        'visible' => false
315
-                    );
316
-
317
-                    // Try to guess the format of the field.
318
-                    $fieldType = Tca::table($this->tableName)->field($additionalField)->getType();
319
-                    if ($fieldType === FieldType::DATE) {
320
-                        $fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Date';
321
-                    } elseif ($fieldType === FieldType::DATETIME) {
322
-                        $fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Datetime';
323
-                    }
324
-                }
325
-                $fields[$lastColumnKey] = $lastColumn;
326
-            }
327
-
328
-            $this->allFields = $fields;
329
-        }
330
-
331
-        return $this->allFields;
332
-    }
333
-
334
-    /**
335
-     * Tell whether the field exists in the grid or not.
336
-     *
337
-     * @param string $fieldName
338
-     * @return bool
339
-     */
340
-    public function hasField($fieldName): bool
341
-    {
342
-        $fields = $this->getFields();
343
-        return isset($fields[$fieldName]);
344
-    }
345
-
346
-    /**
347
-     * Tell whether the facet exists in the grid or not.
348
-     *
349
-     * @param string $facetName
350
-     * @return bool
351
-     */
352
-    public function hasFacet($facetName): bool
353
-    {
354
-        $facets = $this->getFacets();
355
-        return isset($facets[$facetName]);
356
-    }
357
-
358
-    /**
359
-     * Returns an array containing facets fields.
360
-     *
361
-     * @return FacetInterface[]
362
-     */
363
-    public function getFacets(): array
364
-    {
365
-        if ($this->facets === null) {
366
-            $this->facets = [];
367
-
368
-            if (is_array($this->tca['facets'])) {
369
-                foreach ($this->tca['facets'] as $key => $facetNameOrArray) {
370
-                    if (is_array($facetNameOrArray)) {
371
-
372
-                        $name = $facetNameOrArray['name'] ?? '';
373
-
374
-                        $label = isset($facetNameOrArray['label'])
375
-                            ? $this->getLanguageService()->sL($facetNameOrArray['label'])
376
-                            : '';
377
-
378
-                        $suggestions = $facetNameOrArray['suggestions'] ?? [];
379
-                        $configuration = $facetNameOrArray['configuration'] ?? [];
380
-
381
-                        /** @var FacetInterface $facetObject */
382
-                        $facetObject = GeneralUtility::makeInstance($key, $name, $label, $suggestions, $configuration);
383
-                        $this->facets[$facetObject->getName()] = $facetObject;
384
-                    } else {
385
-                        $this->facets[$facetNameOrArray] = $this->instantiateStandardFacet($facetNameOrArray);
386
-                    }
387
-                }
388
-            }
389
-        }
390
-        return $this->facets;
391
-    }
392
-
393
-    /**
394
-     * Returns the "sortable" value of the column.
395
-     *
396
-     * @param string $fieldName
397
-     * @return int|string
398
-     */
399
-    public function isSortable($fieldName)
400
-    {
401
-        $defaultValue = true;
402
-        $hasSortableField = Tca::table($this->tableName)->hasSortableField();
403
-        if ($hasSortableField) {
404
-            $isSortable = false;
405
-        } else {
406
-            $isSortable = $this->get($fieldName, 'sortable', $defaultValue);
407
-        }
408
-        return $isSortable;
409
-    }
410
-
411
-    /**
412
-     * Returns the "canBeHidden" value of the column.
413
-     *
414
-     * @param string $fieldName
415
-     * @return bool
416
-     */
417
-    public function canBeHidden($fieldName): bool
418
-    {
419
-        $defaultValue = true;
420
-        return $this->get($fieldName, 'canBeHidden', $defaultValue);
421
-    }
422
-
423
-    /**
424
-     * Returns the "width" value of the column.
425
-     *
426
-     * @param string $fieldName
427
-     * @return int|string
428
-     */
429
-    public function getWidth($fieldName)
430
-    {
431
-        $defaultValue = 'auto';
432
-        return $this->get($fieldName, 'width', $defaultValue);
433
-    }
434
-
435
-    /**
436
-     * Returns the "visible" value of the column.
437
-     *
438
-     * @param string $fieldName
439
-     * @return bool
440
-     */
441
-    public function isVisible($fieldName): bool
442
-    {
443
-        $defaultValue = true;
444
-        return $this->get($fieldName, 'visible', $defaultValue);
445
-    }
446
-
447
-    /**
448
-     * Returns the "editable" value of the column.
449
-     *
450
-     * @param string $columnName
451
-     * @return bool
452
-     */
453
-    public function isEditable($columnName): bool
454
-    {
455
-        $defaultValue = false;
456
-        return $this->get($columnName, 'editable', $defaultValue);
457
-    }
458
-
459
-    /**
460
-     * Returns the "localized" value of the column.
461
-     *
462
-     * @param string $columnName
463
-     * @return bool
464
-     */
465
-    public function isLocalized($columnName): bool
466
-    {
467
-        $defaultValue = true;
468
-        return $this->get($columnName, 'localized', $defaultValue);
469
-    }
470
-
471
-    /**
472
-     *
473
-     * Returns the "html" value of the column.
474
-     *
475
-     * @param string $fieldName
476
-     * @return string
477
-     */
478
-    public function getHeader($fieldName): string
479
-    {
480
-        $defaultValue = '';
481
-        return $this->get($fieldName, 'html', $defaultValue);
482
-    }
483
-
484
-    /**
485
-     * Fetch a possible from a Grid Renderer. If no value is found, returns null
486
-     *
487
-     * @param string $fieldName
488
-     * @param string $key
489
-     * @param mixed $defaultValue
490
-     * @return null|mixed
491
-     */
492
-    public function get($fieldName, $key, $defaultValue = null)
493
-    {
494
-        $value = $defaultValue;
495
-
496
-        $field = $this->getField($fieldName);
497
-        if (isset($field[$key])) {
498
-            $value = $field[$key];
499
-        } elseif ($this->hasRenderers($fieldName)) {
500
-            $renderers = $this->getRenderers($fieldName);
501
-            foreach ($renderers as $rendererConfiguration) {
502
-                if (isset($rendererConfiguration[$key])) {
503
-                    $value = $rendererConfiguration[$key];
504
-                }
505
-            }
506
-        }
507
-        return $value;
508
-    }
509
-
510
-    /**
511
-     * Returns whether the column has a renderer.
512
-     *
513
-     * @param string $fieldName
514
-     * @return bool
515
-     */
516
-    public function hasRenderers($fieldName): bool
517
-    {
518
-        $field = $this->getField($fieldName);
519
-        return empty($field['renderer']) && empty($field['renderers']) ? false : true;
520
-    }
521
-
522
-    /**
523
-     * Returns a renderer.
524
-     *
525
-     * @param string $fieldName
526
-     * @return array
527
-     */
528
-    public function getRenderers($fieldName): array
529
-    {
530
-        $field = $this->getField($fieldName);
531
-        $renderers = [];
532
-        if (!empty($field['renderer'])) {
533
-            $renderers = $this->convertRendererToArray($field['renderer'], $field);
534
-        } elseif (!empty($field['renderers']) && is_array($field['renderers'])) {
535
-            foreach ($field['renderers'] as $renderer) {
536
-                $rendererNameAndConfiguration = $this->convertRendererToArray($renderer, $field);
537
-                $renderers = array_merge($renderers, $rendererNameAndConfiguration);
538
-            }
539
-        }
540
-
541
-        return $renderers;
542
-    }
543
-
544
-    /**
545
-     * @param string $renderer
546
-     * @return array
547
-     */
548
-    protected function convertRendererToArray($renderer, array $field): array
549
-    {
550
-        $result = [];
551
-        if (is_string($renderer)) {
552
-            $configuration = empty($field['rendererConfiguration'])
553
-                ? []
554
-                : $field['rendererConfiguration'];
555
-
556
-            /** @var ColumnRendererInterface $rendererObject */
557
-            $rendererObject = GeneralUtility::makeInstance($renderer);
558
-
559
-            $result[$renderer] = array_merge($rendererObject->getConfiguration(), $configuration);
560
-            // TODO: throw alert message because this is not compatible anymore as of TYPO3 8.7.7
561
-        } elseif ($renderer instanceof ColumnRendererInterface) {
562
-            /** @var ColumnRendererInterface $renderer */
563
-            $result[get_class($renderer)] = $renderer->getConfiguration();
564
-        }
565
-        return $result;
566
-    }
567
-
568
-    /**
569
-     * Returns the class names applied to a cell
570
-     *
571
-     * @param string $fieldName
572
-     * @return bool
573
-     */
574
-    public function getClass($fieldName): bool
575
-    {
576
-        $field = $this->getField($fieldName);
577
-        return isset($field['class']) ? $field['class'] : '';
578
-    }
579
-
580
-    /**
581
-     * Returns whether the column has a label.
582
-     *
583
-     * @param string $fieldNameAndPath
584
-     * @return bool
585
-     */
586
-    public function hasLabel($fieldNameAndPath): bool
587
-    {
588
-        $field = $this->getField($fieldNameAndPath);
589
-
590
-        $hasLabel = empty($field['label']) ? false : true;
591
-
592
-        if (!$hasLabel && $this->hasRenderers($fieldNameAndPath)) {
593
-            $renderers = $this->getRenderers($fieldNameAndPath);
594
-            /** @var $renderer ColumnRendererInterface */
595
-            foreach ($renderers as $renderer) {
596
-                if (isset($renderer['label'])) {
597
-                    $hasLabel = true;
598
-                    break;
599
-                }
600
-            }
601
-        }
602
-        return $hasLabel;
603
-    }
604
-
605
-    /**
606
-     * @return array
607
-     */
608
-    public function getTca(): array
609
-    {
610
-        return $this->tca;
611
-    }
612
-
613
-    /**
614
-     * @return array
615
-     */
616
-    public function getIncludedFields(): array
617
-    {
618
-        return empty($this->tca['included_fields']) ? [] : GeneralUtility::trimExplode(',', $this->tca['included_fields'], true);
619
-    }
620
-
621
-    /**
622
-     * Return excluded fields from configuration + preferences.
623
-     *
624
-     * @return array
625
-     */
626
-    public function getExcludedFields(): array
627
-    {
628
-        $configurationFields = $this->getExcludedFieldsFromConfiguration();
629
-        $preferencesFields = $this->getExcludedFieldsFromPreferences();
630
-
631
-        return array_merge($configurationFields, $preferencesFields);
632
-    }
633
-
634
-    /**
635
-     * Fetch excluded fields from configuration.
636
-     *
637
-     * @return array
638
-     */
639
-    protected function getExcludedFieldsFromConfiguration(): array
640
-    {
641
-        $excludedFields = [];
642
-        if (!empty($this->tca['excluded_fields'])) {
643
-            $excludedFields = GeneralUtility::trimExplode(',', $this->tca['excluded_fields'], true);
644
-        } elseif (!empty($this->tca['export']['excluded_fields'])) { // only for export for legacy reason.
645
-            $excludedFields = GeneralUtility::trimExplode(',', $this->tca['export']['excluded_fields'], true);
646
-        }
647
-        return $excludedFields;
648
-
649
-    }
650
-
651
-    /**
652
-     * Fetch excluded fields from preferences.
653
-     *
654
-     * @return array
655
-     */
656
-    protected function getExcludedFieldsFromPreferences(): array
657
-    {
658
-        $excludedFields = $this->getModulePreferences()->get(ConfigurablePart::EXCLUDED_FIELDS, $this->tableName);
659
-        return is_array($excludedFields) ? $excludedFields : [];
660
-    }
661
-
662
-    /**
663
-     * @return bool
664
-     */
665
-    public function areFilesIncludedInExport(): bool
666
-    {
667
-        $isIncluded = true;
668
-
669
-        if (isset($this->tca['export']['include_files'])) {
670
-            $isIncluded = (bool)$this->tca['export']['include_files'];
671
-        }
672
-        return $isIncluded;
673
-    }
674
-
675
-    /**
676
-     * Returns a "facet" service instance.
677
-     *
678
-     * @param string|FacetInterface $facetName
679
-     * @return StandardFacet
680
-     */
681
-    protected function instantiateStandardFacet($facetName): StandardFacet
682
-    {
683
-        $label = $this->getLabel($facetName);
684
-
685
-        /** @var StandardFacet $facetName */
686
-        $facet = GeneralUtility::makeInstance(StandardFacet::class, $facetName, $label);
687
-
688
-        if (!$facet instanceof StandardFacet) {
689
-            throw new \RuntimeException('I could not instantiate a facet for facet name "' . $facetName . '""', 1445856345);
690
-        }
691
-        return $facet;
692
-    }
693
-
694
-    /**
695
-     * Returns a "facet" service instance.
696
-     *
697
-     * @param string|FacetInterface $facetName
698
-     * @return FacetInterface
699
-     */
700
-    public function facet($facetName = ''): FacetInterface
701
-    {
702
-        $facets = $this->getFacets();
703
-        return $facets[$facetName];
704
-    }
705
-
706
-    /**
707
-     * @return \Fab\Vidi\Resolver\FieldPathResolver|object
708
-     */
709
-    protected function getFieldPathResolver()
710
-    {
711
-        return GeneralUtility::makeInstance(\Fab\Vidi\Resolver\FieldPathResolver::class);
712
-    }
713
-
714
-    /**
715
-     * @return ModulePreferences|object
716
-     */
717
-    protected function getModulePreferences()
718
-    {
719
-        return GeneralUtility::makeInstance(ModulePreferences::class);
720
-    }
721
-
722
-    /**
723
-     * @return \TYPO3\CMS\Lang\LanguageService|object
724
-     */
725
-    protected function getLanguageService(): \TYPO3\CMS\Lang\LanguageService
726
-    {
727
-        return GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
728
-    }
26
+	/**
27
+	 * @var array
28
+	 */
29
+	protected $tca;
30
+
31
+	/**
32
+	 * @var string
33
+	 */
34
+	protected $tableName;
35
+
36
+	/**
37
+	 * All fields available in the Grid.
38
+	 *
39
+	 * @var array
40
+	 */
41
+	protected $fields;
42
+
43
+	/**
44
+	 * All fields regardless whether they have been excluded or not.
45
+	 *
46
+	 * @var array
47
+	 */
48
+	protected $allFields;
49
+
50
+	/**
51
+	 * @var array
52
+	 */
53
+	protected $instances;
54
+
55
+	/**
56
+	 * @var array
57
+	 */
58
+	protected $facets;
59
+
60
+	/**
61
+	 * __construct
62
+	 *
63
+	 * @param string $tableName
64
+	 */
65
+	public function __construct($tableName)
66
+	{
67
+
68
+		$this->tableName = $tableName;
69
+
70
+		if (empty($GLOBALS['TCA'][$this->tableName])) {
71
+			throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
72
+		}
73
+
74
+		$this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
75
+	}
76
+
77
+	/**
78
+	 * Returns an array containing column names.
79
+	 *
80
+	 * @return array
81
+	 */
82
+	public function getFieldNames(): array
83
+	{
84
+		$fields = $this->getFields();
85
+		return array_keys($fields) ?: [];
86
+	}
87
+
88
+	/**
89
+	 * Returns an array containing column names.
90
+	 *
91
+	 * @return array
92
+	 */
93
+	public function getAllFieldNames(): array
94
+	{
95
+		$allFields = $this->getAllFields();
96
+		return array_keys($allFields);
97
+	}
98
+
99
+	/**
100
+	 * Get the label key.
101
+	 *
102
+	 * @param string $fieldNameAndPath
103
+	 * @return string
104
+	 */
105
+	public function getLabelKey($fieldNameAndPath): string
106
+	{
107
+
108
+		$field = $this->getField($fieldNameAndPath);
109
+
110
+		// First option is to get the label from the Grid TCA.
111
+		$rawLabel = '';
112
+		if (isset($field['label'])) {
113
+			$rawLabel = $field['label'];
114
+		}
115
+
116
+		// Second option is to fetch the label from the Column Renderer object.
117
+		if (!$rawLabel && $this->hasRenderers($fieldNameAndPath)) {
118
+			$renderers = $this->getRenderers($fieldNameAndPath);
119
+			/** @var $renderer ColumnRendererInterface */
120
+			foreach ($renderers as $renderer) {
121
+				if (isset($renderer['label'])) {
122
+					$rawLabel = $renderer['label'];
123
+					break;
124
+				}
125
+			}
126
+		}
127
+		return $rawLabel;
128
+	}
129
+
130
+	/**
131
+	 * Get the translation of a label given a column name.
132
+	 *
133
+	 * @param string $fieldNameAndPath
134
+	 * @return string
135
+	 */
136
+	public function getLabel($fieldNameAndPath)
137
+	{
138
+		$label = '';
139
+		if ($this->hasLabel($fieldNameAndPath)) {
140
+			$labelKey = $this->getLabelKey($fieldNameAndPath);
141
+			try {
142
+				$label = $this->getLanguageService()->sL($labelKey);
143
+			} catch (\InvalidArgumentException $e) {
144
+			}
145
+			if (empty($label)) {
146
+				$label = $labelKey;
147
+			}
148
+		} else {
149
+
150
+			// Important to notice the label can contains a path, e.g. metadata.categories and must be resolved.
151
+			$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->tableName);
152
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->tableName);
153
+			$table = Tca::table($dataType);
154
+
155
+			if ($table->hasField($fieldName) && $table->field($fieldName)->hasLabel()) {
156
+				$label = $table->field($fieldName)->getLabel();
157
+			}
158
+		}
159
+
160
+		return $label;
161
+	}
162
+
163
+	/**
164
+	 * Returns the field name given its position.
165
+	 *
166
+	 * @param string $position the position of the field in the grid
167
+	 * @return int
168
+	 */
169
+	public function getFieldNameByPosition($position): int
170
+	{
171
+		$fields = array_keys($this->getFields());
172
+		if (empty($fields[$position])) {
173
+			throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
174
+		}
175
+
176
+		return $fields[$position];
177
+	}
178
+
179
+	/**
180
+	 * Returns a field name.
181
+	 *
182
+	 * @param string $fieldName
183
+	 * @return array
184
+	 */
185
+	public function getField($fieldName): array
186
+	{
187
+		$fields = $this->getFields();
188
+		return $fields[$fieldName] ?: [];
189
+	}
190
+
191
+	/**
192
+	 * Returns an array containing column names for the Grid.
193
+	 *
194
+	 * @return array
195
+	 */
196
+	public function getFields(): array
197
+	{
198
+		// Cache this operation since it can take some time.
199
+		if ($this->fields === null) {
200
+
201
+			// Fetch all available fields first.
202
+			$fields = $this->getAllFields();
203
+
204
+			if ($this->isBackendMode()) {
205
+
206
+				// Then remove the not allowed.
207
+				$fields = $this->filterByIncludedFields($fields);
208
+				$fields = $this->filterByBackendUser($fields);
209
+				$fields = $this->filterByExcludedFields($fields);
210
+			}
211
+
212
+			$this->fields = $fields;
213
+		}
214
+
215
+		return $this->fields;
216
+	}
217
+
218
+	/**
219
+	 * Remove fields according to Grid configuration.
220
+	 *
221
+	 * @param $fields
222
+	 * @return array
223
+	 */
224
+	protected function filterByIncludedFields($fields): array
225
+	{
226
+
227
+		$filteredFields = $fields;
228
+		$includedFields = $this->getIncludedFields();
229
+		if (count($includedFields) > 0) {
230
+			$filteredFields = [];
231
+			foreach ($fields as $fieldNameAndPath => $configuration) {
232
+				if (in_array($fieldNameAndPath, $includedFields, true) || !Tca::table($this->tableName)->hasField($fieldNameAndPath)) {
233
+					$filteredFields[$fieldNameAndPath] = $configuration;
234
+				}
235
+			}
236
+		}
237
+		return $filteredFields;
238
+	}
239
+
240
+	/**
241
+	 * Remove fields according to BE User permission.
242
+	 *
243
+	 * @param $fields
244
+	 * @return array
245
+	 */
246
+	protected function filterByBackendUser($fields): array
247
+	{
248
+		if (!$this->getBackendUser()->isAdmin()) {
249
+			foreach ($fields as $fieldName => $field) {
250
+				if (Tca::table($this->tableName)->hasField($fieldName) && !Tca::table($this->tableName)->field($fieldName)->hasAccess()) {
251
+					unset($fields[$fieldName]);
252
+				}
253
+			}
254
+		}
255
+		return $fields;
256
+	}
257
+
258
+	/**
259
+	 * Remove fields according to Grid configuration.
260
+	 *
261
+	 * @param $fields
262
+	 * @return array
263
+	 */
264
+	protected function filterByExcludedFields($fields): array
265
+	{
266
+
267
+		// Unset excluded fields.
268
+		foreach ($this->getExcludedFields() as $excludedField) {
269
+			if (isset($fields[$excludedField])) {
270
+				unset($fields[$excludedField]);
271
+			}
272
+		}
273
+
274
+		return $fields;
275
+	}
276
+
277
+	/**
278
+	 * Returns an array containing column names for the Grid.
279
+	 *
280
+	 * @return array
281
+	 */
282
+	public function getAllFields(): array
283
+	{
284
+
285
+		// Cache this operation since it can take some time.
286
+		if ($this->allFields === null) {
287
+
288
+			$fields = is_array($this->tca['columns']) ? $this->tca['columns'] : [];
289
+			$gridFieldNames = array_keys($fields);
290
+
291
+			// Fetch all fields of the TCA and merge it back to the fields configured for Grid.
292
+			$tableFieldNames = Tca::table($this->tableName)->getFields();
293
+
294
+			// Just remove system fields from the Grid.
295
+			foreach ($tableFieldNames as $key => $fieldName) {
296
+				if (in_array($fieldName, Tca::getSystemFields())) {
297
+					unset($tableFieldNames[$key]);
298
+				}
299
+			}
300
+
301
+			$additionalFields = array_diff($tableFieldNames, $gridFieldNames);
302
+
303
+			if (!empty($additionalFields)) {
304
+
305
+				// Pop out last element of the key
306
+				// Idea is to place new un-configured columns in between. By default, they will be hidden.
307
+				end($fields);
308
+				$lastColumnKey = key($fields);
309
+				$lastColumn = array_pop($fields);
310
+
311
+				// Feed up the grid fields with un configured elements
312
+				foreach ($additionalFields as $additionalField) {
313
+					$fields[$additionalField] = array(
314
+						'visible' => false
315
+					);
316
+
317
+					// Try to guess the format of the field.
318
+					$fieldType = Tca::table($this->tableName)->field($additionalField)->getType();
319
+					if ($fieldType === FieldType::DATE) {
320
+						$fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Date';
321
+					} elseif ($fieldType === FieldType::DATETIME) {
322
+						$fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Datetime';
323
+					}
324
+				}
325
+				$fields[$lastColumnKey] = $lastColumn;
326
+			}
327
+
328
+			$this->allFields = $fields;
329
+		}
330
+
331
+		return $this->allFields;
332
+	}
333
+
334
+	/**
335
+	 * Tell whether the field exists in the grid or not.
336
+	 *
337
+	 * @param string $fieldName
338
+	 * @return bool
339
+	 */
340
+	public function hasField($fieldName): bool
341
+	{
342
+		$fields = $this->getFields();
343
+		return isset($fields[$fieldName]);
344
+	}
345
+
346
+	/**
347
+	 * Tell whether the facet exists in the grid or not.
348
+	 *
349
+	 * @param string $facetName
350
+	 * @return bool
351
+	 */
352
+	public function hasFacet($facetName): bool
353
+	{
354
+		$facets = $this->getFacets();
355
+		return isset($facets[$facetName]);
356
+	}
357
+
358
+	/**
359
+	 * Returns an array containing facets fields.
360
+	 *
361
+	 * @return FacetInterface[]
362
+	 */
363
+	public function getFacets(): array
364
+	{
365
+		if ($this->facets === null) {
366
+			$this->facets = [];
367
+
368
+			if (is_array($this->tca['facets'])) {
369
+				foreach ($this->tca['facets'] as $key => $facetNameOrArray) {
370
+					if (is_array($facetNameOrArray)) {
371
+
372
+						$name = $facetNameOrArray['name'] ?? '';
373
+
374
+						$label = isset($facetNameOrArray['label'])
375
+							? $this->getLanguageService()->sL($facetNameOrArray['label'])
376
+							: '';
377
+
378
+						$suggestions = $facetNameOrArray['suggestions'] ?? [];
379
+						$configuration = $facetNameOrArray['configuration'] ?? [];
380
+
381
+						/** @var FacetInterface $facetObject */
382
+						$facetObject = GeneralUtility::makeInstance($key, $name, $label, $suggestions, $configuration);
383
+						$this->facets[$facetObject->getName()] = $facetObject;
384
+					} else {
385
+						$this->facets[$facetNameOrArray] = $this->instantiateStandardFacet($facetNameOrArray);
386
+					}
387
+				}
388
+			}
389
+		}
390
+		return $this->facets;
391
+	}
392
+
393
+	/**
394
+	 * Returns the "sortable" value of the column.
395
+	 *
396
+	 * @param string $fieldName
397
+	 * @return int|string
398
+	 */
399
+	public function isSortable($fieldName)
400
+	{
401
+		$defaultValue = true;
402
+		$hasSortableField = Tca::table($this->tableName)->hasSortableField();
403
+		if ($hasSortableField) {
404
+			$isSortable = false;
405
+		} else {
406
+			$isSortable = $this->get($fieldName, 'sortable', $defaultValue);
407
+		}
408
+		return $isSortable;
409
+	}
410
+
411
+	/**
412
+	 * Returns the "canBeHidden" value of the column.
413
+	 *
414
+	 * @param string $fieldName
415
+	 * @return bool
416
+	 */
417
+	public function canBeHidden($fieldName): bool
418
+	{
419
+		$defaultValue = true;
420
+		return $this->get($fieldName, 'canBeHidden', $defaultValue);
421
+	}
422
+
423
+	/**
424
+	 * Returns the "width" value of the column.
425
+	 *
426
+	 * @param string $fieldName
427
+	 * @return int|string
428
+	 */
429
+	public function getWidth($fieldName)
430
+	{
431
+		$defaultValue = 'auto';
432
+		return $this->get($fieldName, 'width', $defaultValue);
433
+	}
434
+
435
+	/**
436
+	 * Returns the "visible" value of the column.
437
+	 *
438
+	 * @param string $fieldName
439
+	 * @return bool
440
+	 */
441
+	public function isVisible($fieldName): bool
442
+	{
443
+		$defaultValue = true;
444
+		return $this->get($fieldName, 'visible', $defaultValue);
445
+	}
446
+
447
+	/**
448
+	 * Returns the "editable" value of the column.
449
+	 *
450
+	 * @param string $columnName
451
+	 * @return bool
452
+	 */
453
+	public function isEditable($columnName): bool
454
+	{
455
+		$defaultValue = false;
456
+		return $this->get($columnName, 'editable', $defaultValue);
457
+	}
458
+
459
+	/**
460
+	 * Returns the "localized" value of the column.
461
+	 *
462
+	 * @param string $columnName
463
+	 * @return bool
464
+	 */
465
+	public function isLocalized($columnName): bool
466
+	{
467
+		$defaultValue = true;
468
+		return $this->get($columnName, 'localized', $defaultValue);
469
+	}
470
+
471
+	/**
472
+	 *
473
+	 * Returns the "html" value of the column.
474
+	 *
475
+	 * @param string $fieldName
476
+	 * @return string
477
+	 */
478
+	public function getHeader($fieldName): string
479
+	{
480
+		$defaultValue = '';
481
+		return $this->get($fieldName, 'html', $defaultValue);
482
+	}
483
+
484
+	/**
485
+	 * Fetch a possible from a Grid Renderer. If no value is found, returns null
486
+	 *
487
+	 * @param string $fieldName
488
+	 * @param string $key
489
+	 * @param mixed $defaultValue
490
+	 * @return null|mixed
491
+	 */
492
+	public function get($fieldName, $key, $defaultValue = null)
493
+	{
494
+		$value = $defaultValue;
495
+
496
+		$field = $this->getField($fieldName);
497
+		if (isset($field[$key])) {
498
+			$value = $field[$key];
499
+		} elseif ($this->hasRenderers($fieldName)) {
500
+			$renderers = $this->getRenderers($fieldName);
501
+			foreach ($renderers as $rendererConfiguration) {
502
+				if (isset($rendererConfiguration[$key])) {
503
+					$value = $rendererConfiguration[$key];
504
+				}
505
+			}
506
+		}
507
+		return $value;
508
+	}
509
+
510
+	/**
511
+	 * Returns whether the column has a renderer.
512
+	 *
513
+	 * @param string $fieldName
514
+	 * @return bool
515
+	 */
516
+	public function hasRenderers($fieldName): bool
517
+	{
518
+		$field = $this->getField($fieldName);
519
+		return empty($field['renderer']) && empty($field['renderers']) ? false : true;
520
+	}
521
+
522
+	/**
523
+	 * Returns a renderer.
524
+	 *
525
+	 * @param string $fieldName
526
+	 * @return array
527
+	 */
528
+	public function getRenderers($fieldName): array
529
+	{
530
+		$field = $this->getField($fieldName);
531
+		$renderers = [];
532
+		if (!empty($field['renderer'])) {
533
+			$renderers = $this->convertRendererToArray($field['renderer'], $field);
534
+		} elseif (!empty($field['renderers']) && is_array($field['renderers'])) {
535
+			foreach ($field['renderers'] as $renderer) {
536
+				$rendererNameAndConfiguration = $this->convertRendererToArray($renderer, $field);
537
+				$renderers = array_merge($renderers, $rendererNameAndConfiguration);
538
+			}
539
+		}
540
+
541
+		return $renderers;
542
+	}
543
+
544
+	/**
545
+	 * @param string $renderer
546
+	 * @return array
547
+	 */
548
+	protected function convertRendererToArray($renderer, array $field): array
549
+	{
550
+		$result = [];
551
+		if (is_string($renderer)) {
552
+			$configuration = empty($field['rendererConfiguration'])
553
+				? []
554
+				: $field['rendererConfiguration'];
555
+
556
+			/** @var ColumnRendererInterface $rendererObject */
557
+			$rendererObject = GeneralUtility::makeInstance($renderer);
558
+
559
+			$result[$renderer] = array_merge($rendererObject->getConfiguration(), $configuration);
560
+			// TODO: throw alert message because this is not compatible anymore as of TYPO3 8.7.7
561
+		} elseif ($renderer instanceof ColumnRendererInterface) {
562
+			/** @var ColumnRendererInterface $renderer */
563
+			$result[get_class($renderer)] = $renderer->getConfiguration();
564
+		}
565
+		return $result;
566
+	}
567
+
568
+	/**
569
+	 * Returns the class names applied to a cell
570
+	 *
571
+	 * @param string $fieldName
572
+	 * @return bool
573
+	 */
574
+	public function getClass($fieldName): bool
575
+	{
576
+		$field = $this->getField($fieldName);
577
+		return isset($field['class']) ? $field['class'] : '';
578
+	}
579
+
580
+	/**
581
+	 * Returns whether the column has a label.
582
+	 *
583
+	 * @param string $fieldNameAndPath
584
+	 * @return bool
585
+	 */
586
+	public function hasLabel($fieldNameAndPath): bool
587
+	{
588
+		$field = $this->getField($fieldNameAndPath);
589
+
590
+		$hasLabel = empty($field['label']) ? false : true;
591
+
592
+		if (!$hasLabel && $this->hasRenderers($fieldNameAndPath)) {
593
+			$renderers = $this->getRenderers($fieldNameAndPath);
594
+			/** @var $renderer ColumnRendererInterface */
595
+			foreach ($renderers as $renderer) {
596
+				if (isset($renderer['label'])) {
597
+					$hasLabel = true;
598
+					break;
599
+				}
600
+			}
601
+		}
602
+		return $hasLabel;
603
+	}
604
+
605
+	/**
606
+	 * @return array
607
+	 */
608
+	public function getTca(): array
609
+	{
610
+		return $this->tca;
611
+	}
612
+
613
+	/**
614
+	 * @return array
615
+	 */
616
+	public function getIncludedFields(): array
617
+	{
618
+		return empty($this->tca['included_fields']) ? [] : GeneralUtility::trimExplode(',', $this->tca['included_fields'], true);
619
+	}
620
+
621
+	/**
622
+	 * Return excluded fields from configuration + preferences.
623
+	 *
624
+	 * @return array
625
+	 */
626
+	public function getExcludedFields(): array
627
+	{
628
+		$configurationFields = $this->getExcludedFieldsFromConfiguration();
629
+		$preferencesFields = $this->getExcludedFieldsFromPreferences();
630
+
631
+		return array_merge($configurationFields, $preferencesFields);
632
+	}
633
+
634
+	/**
635
+	 * Fetch excluded fields from configuration.
636
+	 *
637
+	 * @return array
638
+	 */
639
+	protected function getExcludedFieldsFromConfiguration(): array
640
+	{
641
+		$excludedFields = [];
642
+		if (!empty($this->tca['excluded_fields'])) {
643
+			$excludedFields = GeneralUtility::trimExplode(',', $this->tca['excluded_fields'], true);
644
+		} elseif (!empty($this->tca['export']['excluded_fields'])) { // only for export for legacy reason.
645
+			$excludedFields = GeneralUtility::trimExplode(',', $this->tca['export']['excluded_fields'], true);
646
+		}
647
+		return $excludedFields;
648
+
649
+	}
650
+
651
+	/**
652
+	 * Fetch excluded fields from preferences.
653
+	 *
654
+	 * @return array
655
+	 */
656
+	protected function getExcludedFieldsFromPreferences(): array
657
+	{
658
+		$excludedFields = $this->getModulePreferences()->get(ConfigurablePart::EXCLUDED_FIELDS, $this->tableName);
659
+		return is_array($excludedFields) ? $excludedFields : [];
660
+	}
661
+
662
+	/**
663
+	 * @return bool
664
+	 */
665
+	public function areFilesIncludedInExport(): bool
666
+	{
667
+		$isIncluded = true;
668
+
669
+		if (isset($this->tca['export']['include_files'])) {
670
+			$isIncluded = (bool)$this->tca['export']['include_files'];
671
+		}
672
+		return $isIncluded;
673
+	}
674
+
675
+	/**
676
+	 * Returns a "facet" service instance.
677
+	 *
678
+	 * @param string|FacetInterface $facetName
679
+	 * @return StandardFacet
680
+	 */
681
+	protected function instantiateStandardFacet($facetName): StandardFacet
682
+	{
683
+		$label = $this->getLabel($facetName);
684
+
685
+		/** @var StandardFacet $facetName */
686
+		$facet = GeneralUtility::makeInstance(StandardFacet::class, $facetName, $label);
687
+
688
+		if (!$facet instanceof StandardFacet) {
689
+			throw new \RuntimeException('I could not instantiate a facet for facet name "' . $facetName . '""', 1445856345);
690
+		}
691
+		return $facet;
692
+	}
693
+
694
+	/**
695
+	 * Returns a "facet" service instance.
696
+	 *
697
+	 * @param string|FacetInterface $facetName
698
+	 * @return FacetInterface
699
+	 */
700
+	public function facet($facetName = ''): FacetInterface
701
+	{
702
+		$facets = $this->getFacets();
703
+		return $facets[$facetName];
704
+	}
705
+
706
+	/**
707
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver|object
708
+	 */
709
+	protected function getFieldPathResolver()
710
+	{
711
+		return GeneralUtility::makeInstance(\Fab\Vidi\Resolver\FieldPathResolver::class);
712
+	}
713
+
714
+	/**
715
+	 * @return ModulePreferences|object
716
+	 */
717
+	protected function getModulePreferences()
718
+	{
719
+		return GeneralUtility::makeInstance(ModulePreferences::class);
720
+	}
721
+
722
+	/**
723
+	 * @return \TYPO3\CMS\Lang\LanguageService|object
724
+	 */
725
+	protected function getLanguageService(): \TYPO3\CMS\Lang\LanguageService
726
+	{
727
+		return GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
728
+	}
729 729
 
730 730
 }
Please login to merge, or discard this patch.