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