Completed
Push — master ( 74614d...b8d895 )
by Fabien
09:51
created
Classes/Tca/FieldService.php 1 patch
Indentation   +772 added lines, -772 removed lines patch added patch discarded remove patch
@@ -17,777 +17,777 @@
 block discarded – undo
17 17
 class FieldService extends AbstractTca
18 18
 {
19 19
 
20
-    /**
21
-     * @var string
22
-     */
23
-    protected $fieldName;
24
-
25
-    /**
26
-     * @var string
27
-     */
28
-    protected $compositeField;
29
-
30
-    /**
31
-     * @var string
32
-     */
33
-    protected $tableName;
34
-
35
-    /**
36
-     * @var array
37
-     */
38
-    protected $tca;
39
-
40
-    /**
41
-     * @param string $fieldName
42
-     * @param array $tca
43
-     * @param string $tableName
44
-     * @param string $compositeField
45
-     * @return \Fab\Vidi\Tca\FieldService
46
-     */
47
-    public function __construct($fieldName, array $tca, $tableName, $compositeField = '')
48
-    {
49
-        $this->fieldName = $fieldName;
50
-        $this->tca = $tca;
51
-        $this->tableName = $tableName;
52
-        $this->compositeField = $compositeField;
53
-    }
54
-
55
-    /**
56
-     * Tells whether the field is considered as system field, e.g. uid, crdate, tstamp, etc...
57
-     *
58
-     * @return bool
59
-     */
60
-    public function isSystem()
61
-    {
62
-        return in_array($this->fieldName, Tca::getSystemFields());
63
-    }
64
-
65
-    /**
66
-     * Tells the opposition of isSystem()
67
-     *
68
-     * @return bool
69
-     */
70
-    public function isNotSystem()
71
-    {
72
-        return !$this->isSystem();
73
-    }
74
-
75
-    /**
76
-     * Returns the configuration for a $field
77
-     *
78
-     * @throws \Exception
79
-     * @return array
80
-     */
81
-    public function getConfiguration()
82
-    {
83
-        return empty($this->tca['config']) ? [] : $this->tca['config'];
84
-    }
85
-
86
-    /**
87
-     * Returns a key of the configuration.
88
-     * If the key can not to be found, returns null.
89
-     *
90
-     * @param string $key
91
-     * @return mixed
92
-     */
93
-    public function get($key)
94
-    {
95
-        $configuration = $this->getConfiguration();
96
-        return empty($configuration[$key]) ? null : $configuration[$key];
97
-    }
98
-
99
-    /**
100
-     * Returns the foreign field of a given field (opposite relational field).
101
-     * If no relation exists, returns null.
102
-     *
103
-     * @return string|null
104
-     */
105
-    public function getForeignField()
106
-    {
107
-        $result = null;
108
-        $configuration = $this->getConfiguration();
109
-
110
-        if (!empty($configuration['foreign_field'])) {
111
-            $result = $configuration['foreign_field'];
112
-        } elseif ($this->hasRelationManyToMany()) {
113
-
114
-            $foreignTable = $this->getForeignTable();
115
-            $manyToManyTable = $this->getManyToManyTable();
116
-
117
-            // Load TCA service of foreign field.
118
-            $tcaForeignTableService = Tca::table($foreignTable);
119
-
120
-            // Look into the MM relations checking for the opposite field
121
-            foreach ($tcaForeignTableService->getFields() as $fieldName) {
122
-                if ($manyToManyTable == $tcaForeignTableService->field($fieldName)->getManyToManyTable()) {
123
-                    $result = $fieldName;
124
-                    break;
125
-                }
126
-            }
127
-        }
128
-        return $result;
129
-    }
130
-
131
-    /**
132
-     * Returns the foreign table of a given field (opposite relational table).
133
-     * If no relation exists, returns null.
134
-     *
135
-     * @return string|null
136
-     */
137
-    public function getForeignTable()
138
-    {
139
-        $result = null;
140
-        $configuration = $this->getConfiguration();
141
-
142
-        if (!empty($configuration['foreign_table'])) {
143
-            $result = $configuration['foreign_table'];
144
-        } elseif ($this->isGroup()) {
145
-            $fieldParts = explode('.', $this->compositeField, 2);
146
-            $result = $fieldParts[1];
147
-        }
148
-        return $result;
149
-    }
150
-
151
-    /**
152
-     * Returns the foreign clause.
153
-     * If no foreign order exists, returns empty string.
154
-     *
155
-     * @return string
156
-     */
157
-    public function getForeignClause()
158
-    {
159
-        $result = '';
160
-        $configuration = $this->getConfiguration();
161
-
162
-        if (!empty($configuration['foreign_table_where'])) {
163
-            $parts = explode('ORDER BY', $configuration['foreign_table_where']);
164
-            if (!empty($parts[0])) {
165
-                $result = $parts[0];
166
-            }
167
-        }
168
-
169
-        // Substitute some variables
170
-        return $this->substituteKnownMarkers($result);
171
-    }
172
-
173
-    /**
174
-     * Substitute some known markers from the where clause in the Frontend Context.
175
-     *
176
-     * @param string $clause
177
-     * @return string
178
-     */
179
-    protected function substituteKnownMarkers($clause)
180
-    {
181
-        if ($clause && $this->isFrontendMode()) {
182
-
183
-            $searches = array(
184
-                '###CURRENT_PID###',
185
-                '###REC_FIELD_sys_language_uid###'
186
-            );
187
-
188
-            $replaces = array(
189
-                $this->getFrontendObject()->id,
190
-                $this->getFrontendObject()->sys_language_uid,
191
-            );
192
-
193
-            $clause = str_replace($searches, $replaces, $clause);
194
-        }
195
-        return $clause;
196
-    }
197
-
198
-    /**
199
-     * Returns the foreign order of the current field.
200
-     * If no foreign order exists, returns empty string.
201
-     *
202
-     * @return string
203
-     */
204
-    public function getForeignOrder()
205
-    {
206
-        $result = '';
207
-        $configuration = $this->getConfiguration();
208
-
209
-        if (!empty($configuration['foreign_table_where'])) {
210
-            $parts = explode('ORDER BY', $configuration['foreign_table_where']);
211
-            if (!empty($parts[1])) {
212
-                $result = $parts[1];
213
-            }
214
-        }
215
-        return $result;
216
-    }
217
-
218
-    /**
219
-     * Returns the MM table of a field.
220
-     * If no relation exists, returns null.
221
-     *
222
-     * @return string|null
223
-     */
224
-    public function getManyToManyTable()
225
-    {
226
-        $configuration = $this->getConfiguration();
227
-        return empty($configuration['MM']) ? null : $configuration['MM'];
228
-    }
229
-
230
-    /**
231
-     * Returns a possible additional table name used in MM relations.
232
-     * If no table name exists, returns null.
233
-     *
234
-     * @return string|null
235
-     */
236
-    public function getAdditionalTableNameCondition()
237
-    {
238
-        $result = null;
239
-        $configuration = $this->getConfiguration();
240
-
241
-        if (!empty($configuration['MM_match_fields']['tablenames'])) {
242
-            $result = $configuration['MM_match_fields']['tablenames'];
243
-        } elseif ($this->isGroup()) {
244
-
245
-            // @todo check if $this->fieldName could be simply used as $result
246
-            $fieldParts = explode('.', $this->compositeField, 2);
247
-            $result = $fieldParts[1];
248
-        }
249
-
250
-        return $result;
251
-    }
252
-
253
-    /**
254
-     * Returns a possible additional conditions for MM tables such as "tablenames", "fieldname", etc...
255
-     *
256
-     * @return array
257
-     */
258
-    public function getAdditionalMMCondition()
259
-    {
260
-        $additionalMMConditions = [];
261
-        $configuration = $this->getConfiguration();
262
-
263
-        if (!empty($configuration['MM_match_fields'])) {
264
-            $additionalMMConditions = $configuration['MM_match_fields'];
265
-        }
266
-
267
-        // Add in any case a table name for "group"
268
-        if ($this->isGroup()) {
269
-
270
-            // @todo check if $this->fieldName could be simply used as $result
271
-            $fieldParts = explode('.', $this->compositeField, 2);
272
-            $additionalMMConditions = array(
273
-                'tablenames' => $fieldParts[1],
274
-            );
275
-        }
276
-        return $additionalMMConditions;
277
-    }
278
-
279
-    /**
280
-     * Returns whether the field name is the opposite in MM relation.
281
-     *
282
-     * @return bool
283
-     */
284
-    public function isOppositeRelation()
285
-    {
286
-        $configuration = $this->getConfiguration();
287
-        return isset($configuration['MM_opposite_field']);
288
-    }
289
-
290
-    /**
291
-     * Returns the configuration for a $field.
292
-     *
293
-     * @throws \Exception
294
-     * @return string
295
-     */
296
-    public function getType()
297
-    {
298
-
299
-        if ($this->isSystem()) {
300
-            $fieldType = FieldType::NUMBER;
301
-        } else {
302
-            $configuration = $this->getConfiguration();
303
-
304
-            if (empty($configuration['type'])) {
305
-                throw new \Exception(sprintf('No field type found for "%s" in table "%s"', $this->fieldName, $this->tableName), 1385556627);
306
-            }
307
-
308
-            $fieldType = $configuration['type'];
309
-
310
-            if ($configuration['type'] === FieldType::SELECT && !empty($configuration['size']) && $configuration['size'] > 1) {
311
-                $fieldType = FieldType::MULTISELECT;
312
-            } elseif (!empty($configuration['foreign_table'])
313
-                && ($configuration['foreign_table'] == 'sys_file_reference' || $configuration['foreign_table'] == 'sys_file')
314
-            ) {
315
-                $fieldType = FieldType::FILE;
316
-            } elseif (!empty($configuration['eval'])) {
317
-                $parts = GeneralUtility::trimExplode(',', $configuration['eval']);
318
-                if (in_array('datetime', $parts)) {
319
-                    $fieldType = FieldType::DATETIME;
320
-                } elseif (in_array('date', $parts)) {
321
-                    $fieldType = FieldType::DATE;
322
-                } elseif (in_array('email', $parts)) {
323
-                    $fieldType = FieldType::EMAIL;
324
-                } elseif (in_array('int', $parts) || in_array('double2', $parts)) {
325
-                    $fieldType = FieldType::NUMBER;
326
-                }
327
-            }
328
-
329
-            // Do some legacy conversion
330
-            if ($fieldType === 'input') {
331
-                $fieldType = FieldType::TEXT;
332
-            } elseif ($fieldType === 'text') {
333
-                $fieldType = FieldType::TEXTAREA;
334
-            }
335
-        }
336
-        return $fieldType;
337
-    }
338
-
339
-    /**
340
-     * Return the default value.
341
-     *
342
-     * @return bool
343
-     */
344
-    public function getDefaultValue()
345
-    {
346
-        $configuration = $this->getConfiguration();
347
-        return isset($configuration['default']) ? $configuration['default'] : null;
348
-    }
349
-
350
-    /**
351
-     * Get the translation of a label given a column.
352
-     *
353
-     * @return string
354
-     */
355
-    public function getLabel()
356
-    {
357
-        $label = '';
358
-        if ($this->hasLabel()) {
359
-            try {
360
-                $label = LocalizationUtility::translate($this->tca['label'], '');
361
-            } catch (\InvalidArgumentException $e) {
362
-            }
363
-            if (empty($label)) {
364
-                $label = $this->tca['label'];
365
-            }
366
-        }
367
-        return $label;
368
-    }
369
-
370
-    /**
371
-     * Get the translation of a label given a column.
372
-     *
373
-     * @param string $itemValue the item value to search for.
374
-     * @return string
375
-     */
376
-    public function getLabelForItem($itemValue)
377
-    {
378
-
379
-        // Early return whether there is nothing to be translated as label.
380
-        if (is_null($itemValue)) {
381
-            return '';
382
-        } elseif (is_string($itemValue) && $itemValue === '') {
383
-            return $itemValue;
384
-        }
385
-
386
-        $configuration = $this->getConfiguration();
387
-        if (!empty($configuration['items']) && is_array($configuration['items'])) {
388
-            foreach ($configuration['items'] as $item) {
389
-                if ($item[1] == $itemValue) {
390
-                    try {
391
-                        $label = LocalizationUtility::translate($item[0], '');
392
-                    } catch (\InvalidArgumentException $e) {
393
-                    }
394
-                    if (empty($label)) {
395
-                        $label = $item[0];
396
-                    }
397
-                    break;
398
-                }
399
-            }
400
-        }
401
-
402
-        // Try fetching a label from a possible itemsProcFunc
403
-        if (!isset($label) && is_scalar($itemValue)) {
404
-            $items = $this->fetchItemsFromUserFunction();
405
-            if (!empty($items[$itemValue])) {
406
-                $label = $items[$itemValue];
407
-            }
408
-        }
409
-
410
-        // Returns a label if it has been found, otherwise returns the item value as fallback.
411
-        return isset($label) ? $label : $itemValue;
412
-    }
413
-
414
-    /**
415
-     * Retrieve items from User Function.
416
-     *
417
-     * @return array
418
-     */
419
-    protected function fetchItemsFromUserFunction()
420
-    {
421
-        $values = [];
422
-
423
-        $configuration = $this->getConfiguration();
424
-        if (!empty($configuration['itemsProcFunc'])) {
425
-            $parts = explode('php:', $configuration['itemsProcFunc']);
426
-            if (!empty($parts[1])) {
427
-
428
-                list($class, $method) = explode('->', $parts[1]);
429
-
430
-                $parameters['items'] = [];
431
-                $object = GeneralUtility::makeInstance($class);
432
-                $object->$method($parameters);
433
-
434
-                foreach ($parameters['items'] as $items) {
435
-                    $values[$items[1]] = $items[0];
436
-                }
437
-            }
438
-        }
439
-        return $values;
440
-    }
441
-
442
-    /**
443
-     * Get a possible icon given a field name an an item.
444
-     *
445
-     * @param string $itemValue the item value to search for.
446
-     * @return string
447
-     */
448
-    public function getIconForItem($itemValue)
449
-    {
450
-        $result = '';
451
-        $configuration = $this->getConfiguration();
452
-        if (!empty($configuration['items']) && is_array($configuration['items'])) {
453
-            foreach ($configuration['items'] as $item) {
454
-                if ($item[1] == $itemValue) {
455
-                    $result = empty($item[2]) ? '' : $item[2];
456
-                    break;
457
-                }
458
-            }
459
-        }
460
-        return $result;
461
-    }
462
-
463
-    /**
464
-     * Returns whether the field has a label.
465
-     *
466
-     * @return bool
467
-     */
468
-    public function hasLabel()
469
-    {
470
-        return empty($this->tca['label']) ? false : true;
471
-    }
472
-
473
-    /**
474
-     * Tell whether the current BE User has access to this field.
475
-     *
476
-     * @return bool
477
-     */
478
-    public function hasAccess()
479
-    {
480
-        $hasAccess = true;
481
-        if ($this->isBackendMode()
482
-            && Tca::table($this->tableName)->hasAccess()
483
-            && isset($this->tca['exclude'])
484
-            && $this->tca['exclude']
485
-        ) {
486
-            $hasAccess = $this->getBackendUser()->check('non_exclude_fields', $this->tableName . ':' . $this->fieldName);
487
-        }
488
-        return $hasAccess;
489
-    }
490
-
491
-    /**
492
-     * Returns whether the field is numerical.
493
-     *
494
-     * @return bool
495
-     */
496
-    public function isNumerical()
497
-    {
498
-        $result = $this->isSystem();
499
-        if ($result === false) {
500
-            $configuration = $this->getConfiguration();
501
-            $parts = [];
502
-            if (!empty($configuration['eval'])) {
503
-                $parts = GeneralUtility::trimExplode(',', $configuration['eval']);
504
-            }
505
-            $result = in_array('int', $parts) || in_array('float', $parts);
506
-        }
507
-        return $result;
508
-    }
509
-
510
-    /**
511
-     * Returns whether the field is of type text area.
512
-     *
513
-     * @return bool
514
-     */
515
-    public function isTextArea()
516
-    {
517
-        return $this->getType() === FieldType::TEXTAREA;
518
-    }
519
-    /**
520
-     * Returns whether the field is of type text area.
521
-     *
522
-     * @return bool
523
-     */
524
-    public function isText()
525
-    {
526
-        return $this->getType() === FieldType::TEXT;
527
-    }
528
-
529
-    /**
530
-     * Returns whether the field is displayed as a tree.
531
-     *
532
-     * @return bool
533
-     */
534
-    public function isRenderModeTree()
535
-    {
536
-        $configuration = $this->getConfiguration();
537
-        return isset($configuration['renderMode']) && $configuration['renderMode'] == FieldType::TREE;
538
-    }
539
-
540
-    /**
541
-     * Returns whether the field is of type select.
542
-     *
543
-     * @return bool
544
-     */
545
-    public function isSelect()
546
-    {
547
-        return $this->getType() === FieldType::SELECT;
548
-    }
549
-
550
-    /**
551
-     * Returns whether the field is of type select.
552
-     *
553
-     * @return bool
554
-     */
555
-    public function isMultipleSelect()
556
-    {
557
-        return $this->getType() === FieldType::MULTISELECT;
558
-    }
559
-
560
-    /**
561
-     * Returns whether the field is of type select.
562
-     *
563
-     * @return bool
564
-     */
565
-    public function isCheckBox()
566
-    {
567
-        return $this->getType() === FieldType::CHECKBOX;
568
-    }
569
-
570
-    /**
571
-     * Returns whether the field is of type db.
572
-     *
573
-     * @return bool
574
-     */
575
-    public function isGroup()
576
-    {
577
-        return $this->getType() === 'group';
578
-    }
579
-
580
-    /**
581
-     * Returns whether the field is language aware.
582
-     *
583
-     * @return bool
584
-     */
585
-    public function isLocalized()
586
-    {
587
-        $isLocalized = false;
588
-        if (isset($this->tca['l10n_mode'])) {
589
-
590
-            if ($this->tca['l10n_mode'] == 'prefixLangTitle' || $this->tca['l10n_mode'] == 'mergeIfNotBlank') {
591
-                $isLocalized = true;
592
-            }
593
-        }
594
-        return $isLocalized;
595
-    }
596
-
597
-    /**
598
-     * Returns whether the field is required.
599
-     *
600
-     * @return bool
601
-     */
602
-    public function isRequired()
603
-    {
604
-        $configuration = $this->getConfiguration();
605
-
606
-        $isRequired = false;
607
-        if (isset($configuration['minitems'])) {
608
-            // is required of a select?
609
-            $isRequired = $configuration['minitems'] == 1 ? true : false;
610
-        } elseif (isset($configuration['eval'])) {
611
-            $parts = GeneralUtility::trimExplode(',', $configuration['eval'], true);
612
-            $isRequired = in_array('required', $parts);
613
-        }
614
-        return $isRequired;
615
-    }
616
-
617
-    /**
618
-     * Returns an array containing the configuration of a column.
619
-     *
620
-     * @return array
621
-     */
622
-    public function getField()
623
-    {
624
-        return $this->tca;
625
-    }
626
-
627
-    /**
628
-     * Returns the relation type
629
-     *
630
-     * @return string
631
-     */
632
-    public function relationDataType()
633
-    {
634
-        $configuration = $this->getConfiguration();
635
-        return empty($configuration['foreign_table']) ? '' : $configuration['foreign_table'];
636
-    }
637
-
638
-    /**
639
-     * Returns whether the field has relation (one to many, many to many)
640
-     *
641
-     * @return bool
642
-     */
643
-    public function hasRelation()
644
-    {
645
-        return null !== $this->getForeignTable();
646
-    }
647
-
648
-    /**
649
-     * Returns whether the field has no relation (one to many, many to many)
650
-     *
651
-     * @return bool
652
-     */
653
-    public function hasNoRelation()
654
-    {
655
-        return !$this->hasRelation();
656
-    }
657
-
658
-    /**
659
-     * Returns whether the field has a "many" objects connected including "many-to-many" or "one-to-many".
660
-     *
661
-     * @return bool
662
-     */
663
-    public function hasMany()
664
-    {
665
-        $configuration = $this->getConfiguration();
666
-        return $this->hasRelation() && ($configuration['maxitems'] > 1 || isset($configuration['foreign_table_field']));
667
-    }
668
-
669
-    /**
670
-     * Returns whether the field has relation "one" object connected including of "one-to-one" or "many-to-one".
671
-     *
672
-     * @return bool
673
-     */
674
-    public function hasOne()
675
-    {
676
-        $configuration = $this->getConfiguration();
677
-        return !isset($configuration['MM']) && $this->hasRelation() && ($configuration['maxitems'] == 1 || !isset($configuration['maxitems']));
678
-    }
679
-
680
-    /**
681
-     * Returns whether the field has many-to-one relation.
682
-     *
683
-     * @return bool
684
-     */
685
-    public function hasRelationManyToOne()
686
-    {
687
-        $result = false;
688
-
689
-        $foreignField = $this->getForeignField();
690
-        if (!empty($foreignField)) {
691
-
692
-            // Load TCA service of the foreign field.
693
-            $foreignTable = $this->getForeignTable();
694
-            $result = $this->hasOne() && Tca::table($foreignTable)->field($foreignField)->hasMany();
695
-        }
696
-        return $result;
697
-    }
698
-
699
-    /**
700
-     * Returns whether the field has one-to-many relation.
701
-     *
702
-     * @return bool
703
-     */
704
-    public function hasRelationOneToMany()
705
-    {
706
-        $result = false;
707
-
708
-        $foreignField = $this->getForeignField();
709
-        if (!empty($foreignField)) {
710
-
711
-            // Load TCA service of the foreign field.
712
-            $foreignTable = $this->getForeignTable();
713
-            $result = $this->hasMany() && Tca::table($foreignTable)->field($foreignField)->hasOne();
714
-        }
715
-        return $result;
716
-    }
717
-
718
-    /**
719
-     * Returns whether the field has one-to-one relation.
720
-     *
721
-     * @return bool
722
-     */
723
-    public function hasRelationOneToOne()
724
-    {
725
-        $result = false;
726
-
727
-        $foreignField = $this->getForeignField();
728
-        if (!empty($foreignField)) {
729
-
730
-            // Load TCA service of foreign field.
731
-            $foreignTable = $this->getForeignTable();
732
-            $result = $this->hasOne() && Tca::table($foreignTable)->field($foreignField)->hasOne();
733
-        }
734
-        return $result;
735
-    }
736
-
737
-    /**
738
-     * Returns whether the field has many to many relation.
739
-     *
740
-     * @return bool
741
-     */
742
-    public function hasRelationManyToMany()
743
-    {
744
-        $configuration = $this->getConfiguration();
745
-        return $this->hasRelation() && (isset($configuration['MM']) || isset($configuration['foreign_table_field']));
746
-    }
747
-
748
-    /**
749
-     * Returns whether the field has many to many relation using comma separated values (legacy).
750
-     *
751
-     * @return bool
752
-     */
753
-    public function hasRelationWithCommaSeparatedValues()
754
-    {
755
-        $configuration = $this->getConfiguration();
756
-        return $this->hasRelation() && !isset($configuration['MM']) && !isset($configuration['foreign_field']) && $configuration['maxitems'] > 1;
757
-    }
758
-
759
-    /**
760
-     * @return array
761
-     */
762
-    public function getTca()
763
-    {
764
-        return $this->tca['columns'];
765
-    }
766
-
767
-    /**
768
-     * @return string
769
-     */
770
-    public function getCompositeField()
771
-    {
772
-        return $this->compositeField;
773
-    }
774
-
775
-    /**
776
-     * @param string $compositeField
777
-     */
778
-    public function setCompositeField($compositeField)
779
-    {
780
-        $this->compositeField = $compositeField;
781
-    }
782
-
783
-    /**
784
-     * Returns an instance of the Frontend object.
785
-     *
786
-     * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
787
-     */
788
-    protected function getFrontendObject()
789
-    {
790
-        return $GLOBALS['TSFE'];
791
-    }
20
+	/**
21
+	 * @var string
22
+	 */
23
+	protected $fieldName;
24
+
25
+	/**
26
+	 * @var string
27
+	 */
28
+	protected $compositeField;
29
+
30
+	/**
31
+	 * @var string
32
+	 */
33
+	protected $tableName;
34
+
35
+	/**
36
+	 * @var array
37
+	 */
38
+	protected $tca;
39
+
40
+	/**
41
+	 * @param string $fieldName
42
+	 * @param array $tca
43
+	 * @param string $tableName
44
+	 * @param string $compositeField
45
+	 * @return \Fab\Vidi\Tca\FieldService
46
+	 */
47
+	public function __construct($fieldName, array $tca, $tableName, $compositeField = '')
48
+	{
49
+		$this->fieldName = $fieldName;
50
+		$this->tca = $tca;
51
+		$this->tableName = $tableName;
52
+		$this->compositeField = $compositeField;
53
+	}
54
+
55
+	/**
56
+	 * Tells whether the field is considered as system field, e.g. uid, crdate, tstamp, etc...
57
+	 *
58
+	 * @return bool
59
+	 */
60
+	public function isSystem()
61
+	{
62
+		return in_array($this->fieldName, Tca::getSystemFields());
63
+	}
64
+
65
+	/**
66
+	 * Tells the opposition of isSystem()
67
+	 *
68
+	 * @return bool
69
+	 */
70
+	public function isNotSystem()
71
+	{
72
+		return !$this->isSystem();
73
+	}
74
+
75
+	/**
76
+	 * Returns the configuration for a $field
77
+	 *
78
+	 * @throws \Exception
79
+	 * @return array
80
+	 */
81
+	public function getConfiguration()
82
+	{
83
+		return empty($this->tca['config']) ? [] : $this->tca['config'];
84
+	}
85
+
86
+	/**
87
+	 * Returns a key of the configuration.
88
+	 * If the key can not to be found, returns null.
89
+	 *
90
+	 * @param string $key
91
+	 * @return mixed
92
+	 */
93
+	public function get($key)
94
+	{
95
+		$configuration = $this->getConfiguration();
96
+		return empty($configuration[$key]) ? null : $configuration[$key];
97
+	}
98
+
99
+	/**
100
+	 * Returns the foreign field of a given field (opposite relational field).
101
+	 * If no relation exists, returns null.
102
+	 *
103
+	 * @return string|null
104
+	 */
105
+	public function getForeignField()
106
+	{
107
+		$result = null;
108
+		$configuration = $this->getConfiguration();
109
+
110
+		if (!empty($configuration['foreign_field'])) {
111
+			$result = $configuration['foreign_field'];
112
+		} elseif ($this->hasRelationManyToMany()) {
113
+
114
+			$foreignTable = $this->getForeignTable();
115
+			$manyToManyTable = $this->getManyToManyTable();
116
+
117
+			// Load TCA service of foreign field.
118
+			$tcaForeignTableService = Tca::table($foreignTable);
119
+
120
+			// Look into the MM relations checking for the opposite field
121
+			foreach ($tcaForeignTableService->getFields() as $fieldName) {
122
+				if ($manyToManyTable == $tcaForeignTableService->field($fieldName)->getManyToManyTable()) {
123
+					$result = $fieldName;
124
+					break;
125
+				}
126
+			}
127
+		}
128
+		return $result;
129
+	}
130
+
131
+	/**
132
+	 * Returns the foreign table of a given field (opposite relational table).
133
+	 * If no relation exists, returns null.
134
+	 *
135
+	 * @return string|null
136
+	 */
137
+	public function getForeignTable()
138
+	{
139
+		$result = null;
140
+		$configuration = $this->getConfiguration();
141
+
142
+		if (!empty($configuration['foreign_table'])) {
143
+			$result = $configuration['foreign_table'];
144
+		} elseif ($this->isGroup()) {
145
+			$fieldParts = explode('.', $this->compositeField, 2);
146
+			$result = $fieldParts[1];
147
+		}
148
+		return $result;
149
+	}
150
+
151
+	/**
152
+	 * Returns the foreign clause.
153
+	 * If no foreign order exists, returns empty string.
154
+	 *
155
+	 * @return string
156
+	 */
157
+	public function getForeignClause()
158
+	{
159
+		$result = '';
160
+		$configuration = $this->getConfiguration();
161
+
162
+		if (!empty($configuration['foreign_table_where'])) {
163
+			$parts = explode('ORDER BY', $configuration['foreign_table_where']);
164
+			if (!empty($parts[0])) {
165
+				$result = $parts[0];
166
+			}
167
+		}
168
+
169
+		// Substitute some variables
170
+		return $this->substituteKnownMarkers($result);
171
+	}
172
+
173
+	/**
174
+	 * Substitute some known markers from the where clause in the Frontend Context.
175
+	 *
176
+	 * @param string $clause
177
+	 * @return string
178
+	 */
179
+	protected function substituteKnownMarkers($clause)
180
+	{
181
+		if ($clause && $this->isFrontendMode()) {
182
+
183
+			$searches = array(
184
+				'###CURRENT_PID###',
185
+				'###REC_FIELD_sys_language_uid###'
186
+			);
187
+
188
+			$replaces = array(
189
+				$this->getFrontendObject()->id,
190
+				$this->getFrontendObject()->sys_language_uid,
191
+			);
192
+
193
+			$clause = str_replace($searches, $replaces, $clause);
194
+		}
195
+		return $clause;
196
+	}
197
+
198
+	/**
199
+	 * Returns the foreign order of the current field.
200
+	 * If no foreign order exists, returns empty string.
201
+	 *
202
+	 * @return string
203
+	 */
204
+	public function getForeignOrder()
205
+	{
206
+		$result = '';
207
+		$configuration = $this->getConfiguration();
208
+
209
+		if (!empty($configuration['foreign_table_where'])) {
210
+			$parts = explode('ORDER BY', $configuration['foreign_table_where']);
211
+			if (!empty($parts[1])) {
212
+				$result = $parts[1];
213
+			}
214
+		}
215
+		return $result;
216
+	}
217
+
218
+	/**
219
+	 * Returns the MM table of a field.
220
+	 * If no relation exists, returns null.
221
+	 *
222
+	 * @return string|null
223
+	 */
224
+	public function getManyToManyTable()
225
+	{
226
+		$configuration = $this->getConfiguration();
227
+		return empty($configuration['MM']) ? null : $configuration['MM'];
228
+	}
229
+
230
+	/**
231
+	 * Returns a possible additional table name used in MM relations.
232
+	 * If no table name exists, returns null.
233
+	 *
234
+	 * @return string|null
235
+	 */
236
+	public function getAdditionalTableNameCondition()
237
+	{
238
+		$result = null;
239
+		$configuration = $this->getConfiguration();
240
+
241
+		if (!empty($configuration['MM_match_fields']['tablenames'])) {
242
+			$result = $configuration['MM_match_fields']['tablenames'];
243
+		} elseif ($this->isGroup()) {
244
+
245
+			// @todo check if $this->fieldName could be simply used as $result
246
+			$fieldParts = explode('.', $this->compositeField, 2);
247
+			$result = $fieldParts[1];
248
+		}
249
+
250
+		return $result;
251
+	}
252
+
253
+	/**
254
+	 * Returns a possible additional conditions for MM tables such as "tablenames", "fieldname", etc...
255
+	 *
256
+	 * @return array
257
+	 */
258
+	public function getAdditionalMMCondition()
259
+	{
260
+		$additionalMMConditions = [];
261
+		$configuration = $this->getConfiguration();
262
+
263
+		if (!empty($configuration['MM_match_fields'])) {
264
+			$additionalMMConditions = $configuration['MM_match_fields'];
265
+		}
266
+
267
+		// Add in any case a table name for "group"
268
+		if ($this->isGroup()) {
269
+
270
+			// @todo check if $this->fieldName could be simply used as $result
271
+			$fieldParts = explode('.', $this->compositeField, 2);
272
+			$additionalMMConditions = array(
273
+				'tablenames' => $fieldParts[1],
274
+			);
275
+		}
276
+		return $additionalMMConditions;
277
+	}
278
+
279
+	/**
280
+	 * Returns whether the field name is the opposite in MM relation.
281
+	 *
282
+	 * @return bool
283
+	 */
284
+	public function isOppositeRelation()
285
+	{
286
+		$configuration = $this->getConfiguration();
287
+		return isset($configuration['MM_opposite_field']);
288
+	}
289
+
290
+	/**
291
+	 * Returns the configuration for a $field.
292
+	 *
293
+	 * @throws \Exception
294
+	 * @return string
295
+	 */
296
+	public function getType()
297
+	{
298
+
299
+		if ($this->isSystem()) {
300
+			$fieldType = FieldType::NUMBER;
301
+		} else {
302
+			$configuration = $this->getConfiguration();
303
+
304
+			if (empty($configuration['type'])) {
305
+				throw new \Exception(sprintf('No field type found for "%s" in table "%s"', $this->fieldName, $this->tableName), 1385556627);
306
+			}
307
+
308
+			$fieldType = $configuration['type'];
309
+
310
+			if ($configuration['type'] === FieldType::SELECT && !empty($configuration['size']) && $configuration['size'] > 1) {
311
+				$fieldType = FieldType::MULTISELECT;
312
+			} elseif (!empty($configuration['foreign_table'])
313
+				&& ($configuration['foreign_table'] == 'sys_file_reference' || $configuration['foreign_table'] == 'sys_file')
314
+			) {
315
+				$fieldType = FieldType::FILE;
316
+			} elseif (!empty($configuration['eval'])) {
317
+				$parts = GeneralUtility::trimExplode(',', $configuration['eval']);
318
+				if (in_array('datetime', $parts)) {
319
+					$fieldType = FieldType::DATETIME;
320
+				} elseif (in_array('date', $parts)) {
321
+					$fieldType = FieldType::DATE;
322
+				} elseif (in_array('email', $parts)) {
323
+					$fieldType = FieldType::EMAIL;
324
+				} elseif (in_array('int', $parts) || in_array('double2', $parts)) {
325
+					$fieldType = FieldType::NUMBER;
326
+				}
327
+			}
328
+
329
+			// Do some legacy conversion
330
+			if ($fieldType === 'input') {
331
+				$fieldType = FieldType::TEXT;
332
+			} elseif ($fieldType === 'text') {
333
+				$fieldType = FieldType::TEXTAREA;
334
+			}
335
+		}
336
+		return $fieldType;
337
+	}
338
+
339
+	/**
340
+	 * Return the default value.
341
+	 *
342
+	 * @return bool
343
+	 */
344
+	public function getDefaultValue()
345
+	{
346
+		$configuration = $this->getConfiguration();
347
+		return isset($configuration['default']) ? $configuration['default'] : null;
348
+	}
349
+
350
+	/**
351
+	 * Get the translation of a label given a column.
352
+	 *
353
+	 * @return string
354
+	 */
355
+	public function getLabel()
356
+	{
357
+		$label = '';
358
+		if ($this->hasLabel()) {
359
+			try {
360
+				$label = LocalizationUtility::translate($this->tca['label'], '');
361
+			} catch (\InvalidArgumentException $e) {
362
+			}
363
+			if (empty($label)) {
364
+				$label = $this->tca['label'];
365
+			}
366
+		}
367
+		return $label;
368
+	}
369
+
370
+	/**
371
+	 * Get the translation of a label given a column.
372
+	 *
373
+	 * @param string $itemValue the item value to search for.
374
+	 * @return string
375
+	 */
376
+	public function getLabelForItem($itemValue)
377
+	{
378
+
379
+		// Early return whether there is nothing to be translated as label.
380
+		if (is_null($itemValue)) {
381
+			return '';
382
+		} elseif (is_string($itemValue) && $itemValue === '') {
383
+			return $itemValue;
384
+		}
385
+
386
+		$configuration = $this->getConfiguration();
387
+		if (!empty($configuration['items']) && is_array($configuration['items'])) {
388
+			foreach ($configuration['items'] as $item) {
389
+				if ($item[1] == $itemValue) {
390
+					try {
391
+						$label = LocalizationUtility::translate($item[0], '');
392
+					} catch (\InvalidArgumentException $e) {
393
+					}
394
+					if (empty($label)) {
395
+						$label = $item[0];
396
+					}
397
+					break;
398
+				}
399
+			}
400
+		}
401
+
402
+		// Try fetching a label from a possible itemsProcFunc
403
+		if (!isset($label) && is_scalar($itemValue)) {
404
+			$items = $this->fetchItemsFromUserFunction();
405
+			if (!empty($items[$itemValue])) {
406
+				$label = $items[$itemValue];
407
+			}
408
+		}
409
+
410
+		// Returns a label if it has been found, otherwise returns the item value as fallback.
411
+		return isset($label) ? $label : $itemValue;
412
+	}
413
+
414
+	/**
415
+	 * Retrieve items from User Function.
416
+	 *
417
+	 * @return array
418
+	 */
419
+	protected function fetchItemsFromUserFunction()
420
+	{
421
+		$values = [];
422
+
423
+		$configuration = $this->getConfiguration();
424
+		if (!empty($configuration['itemsProcFunc'])) {
425
+			$parts = explode('php:', $configuration['itemsProcFunc']);
426
+			if (!empty($parts[1])) {
427
+
428
+				list($class, $method) = explode('->', $parts[1]);
429
+
430
+				$parameters['items'] = [];
431
+				$object = GeneralUtility::makeInstance($class);
432
+				$object->$method($parameters);
433
+
434
+				foreach ($parameters['items'] as $items) {
435
+					$values[$items[1]] = $items[0];
436
+				}
437
+			}
438
+		}
439
+		return $values;
440
+	}
441
+
442
+	/**
443
+	 * Get a possible icon given a field name an an item.
444
+	 *
445
+	 * @param string $itemValue the item value to search for.
446
+	 * @return string
447
+	 */
448
+	public function getIconForItem($itemValue)
449
+	{
450
+		$result = '';
451
+		$configuration = $this->getConfiguration();
452
+		if (!empty($configuration['items']) && is_array($configuration['items'])) {
453
+			foreach ($configuration['items'] as $item) {
454
+				if ($item[1] == $itemValue) {
455
+					$result = empty($item[2]) ? '' : $item[2];
456
+					break;
457
+				}
458
+			}
459
+		}
460
+		return $result;
461
+	}
462
+
463
+	/**
464
+	 * Returns whether the field has a label.
465
+	 *
466
+	 * @return bool
467
+	 */
468
+	public function hasLabel()
469
+	{
470
+		return empty($this->tca['label']) ? false : true;
471
+	}
472
+
473
+	/**
474
+	 * Tell whether the current BE User has access to this field.
475
+	 *
476
+	 * @return bool
477
+	 */
478
+	public function hasAccess()
479
+	{
480
+		$hasAccess = true;
481
+		if ($this->isBackendMode()
482
+			&& Tca::table($this->tableName)->hasAccess()
483
+			&& isset($this->tca['exclude'])
484
+			&& $this->tca['exclude']
485
+		) {
486
+			$hasAccess = $this->getBackendUser()->check('non_exclude_fields', $this->tableName . ':' . $this->fieldName);
487
+		}
488
+		return $hasAccess;
489
+	}
490
+
491
+	/**
492
+	 * Returns whether the field is numerical.
493
+	 *
494
+	 * @return bool
495
+	 */
496
+	public function isNumerical()
497
+	{
498
+		$result = $this->isSystem();
499
+		if ($result === false) {
500
+			$configuration = $this->getConfiguration();
501
+			$parts = [];
502
+			if (!empty($configuration['eval'])) {
503
+				$parts = GeneralUtility::trimExplode(',', $configuration['eval']);
504
+			}
505
+			$result = in_array('int', $parts) || in_array('float', $parts);
506
+		}
507
+		return $result;
508
+	}
509
+
510
+	/**
511
+	 * Returns whether the field is of type text area.
512
+	 *
513
+	 * @return bool
514
+	 */
515
+	public function isTextArea()
516
+	{
517
+		return $this->getType() === FieldType::TEXTAREA;
518
+	}
519
+	/**
520
+	 * Returns whether the field is of type text area.
521
+	 *
522
+	 * @return bool
523
+	 */
524
+	public function isText()
525
+	{
526
+		return $this->getType() === FieldType::TEXT;
527
+	}
528
+
529
+	/**
530
+	 * Returns whether the field is displayed as a tree.
531
+	 *
532
+	 * @return bool
533
+	 */
534
+	public function isRenderModeTree()
535
+	{
536
+		$configuration = $this->getConfiguration();
537
+		return isset($configuration['renderMode']) && $configuration['renderMode'] == FieldType::TREE;
538
+	}
539
+
540
+	/**
541
+	 * Returns whether the field is of type select.
542
+	 *
543
+	 * @return bool
544
+	 */
545
+	public function isSelect()
546
+	{
547
+		return $this->getType() === FieldType::SELECT;
548
+	}
549
+
550
+	/**
551
+	 * Returns whether the field is of type select.
552
+	 *
553
+	 * @return bool
554
+	 */
555
+	public function isMultipleSelect()
556
+	{
557
+		return $this->getType() === FieldType::MULTISELECT;
558
+	}
559
+
560
+	/**
561
+	 * Returns whether the field is of type select.
562
+	 *
563
+	 * @return bool
564
+	 */
565
+	public function isCheckBox()
566
+	{
567
+		return $this->getType() === FieldType::CHECKBOX;
568
+	}
569
+
570
+	/**
571
+	 * Returns whether the field is of type db.
572
+	 *
573
+	 * @return bool
574
+	 */
575
+	public function isGroup()
576
+	{
577
+		return $this->getType() === 'group';
578
+	}
579
+
580
+	/**
581
+	 * Returns whether the field is language aware.
582
+	 *
583
+	 * @return bool
584
+	 */
585
+	public function isLocalized()
586
+	{
587
+		$isLocalized = false;
588
+		if (isset($this->tca['l10n_mode'])) {
589
+
590
+			if ($this->tca['l10n_mode'] == 'prefixLangTitle' || $this->tca['l10n_mode'] == 'mergeIfNotBlank') {
591
+				$isLocalized = true;
592
+			}
593
+		}
594
+		return $isLocalized;
595
+	}
596
+
597
+	/**
598
+	 * Returns whether the field is required.
599
+	 *
600
+	 * @return bool
601
+	 */
602
+	public function isRequired()
603
+	{
604
+		$configuration = $this->getConfiguration();
605
+
606
+		$isRequired = false;
607
+		if (isset($configuration['minitems'])) {
608
+			// is required of a select?
609
+			$isRequired = $configuration['minitems'] == 1 ? true : false;
610
+		} elseif (isset($configuration['eval'])) {
611
+			$parts = GeneralUtility::trimExplode(',', $configuration['eval'], true);
612
+			$isRequired = in_array('required', $parts);
613
+		}
614
+		return $isRequired;
615
+	}
616
+
617
+	/**
618
+	 * Returns an array containing the configuration of a column.
619
+	 *
620
+	 * @return array
621
+	 */
622
+	public function getField()
623
+	{
624
+		return $this->tca;
625
+	}
626
+
627
+	/**
628
+	 * Returns the relation type
629
+	 *
630
+	 * @return string
631
+	 */
632
+	public function relationDataType()
633
+	{
634
+		$configuration = $this->getConfiguration();
635
+		return empty($configuration['foreign_table']) ? '' : $configuration['foreign_table'];
636
+	}
637
+
638
+	/**
639
+	 * Returns whether the field has relation (one to many, many to many)
640
+	 *
641
+	 * @return bool
642
+	 */
643
+	public function hasRelation()
644
+	{
645
+		return null !== $this->getForeignTable();
646
+	}
647
+
648
+	/**
649
+	 * Returns whether the field has no relation (one to many, many to many)
650
+	 *
651
+	 * @return bool
652
+	 */
653
+	public function hasNoRelation()
654
+	{
655
+		return !$this->hasRelation();
656
+	}
657
+
658
+	/**
659
+	 * Returns whether the field has a "many" objects connected including "many-to-many" or "one-to-many".
660
+	 *
661
+	 * @return bool
662
+	 */
663
+	public function hasMany()
664
+	{
665
+		$configuration = $this->getConfiguration();
666
+		return $this->hasRelation() && ($configuration['maxitems'] > 1 || isset($configuration['foreign_table_field']));
667
+	}
668
+
669
+	/**
670
+	 * Returns whether the field has relation "one" object connected including of "one-to-one" or "many-to-one".
671
+	 *
672
+	 * @return bool
673
+	 */
674
+	public function hasOne()
675
+	{
676
+		$configuration = $this->getConfiguration();
677
+		return !isset($configuration['MM']) && $this->hasRelation() && ($configuration['maxitems'] == 1 || !isset($configuration['maxitems']));
678
+	}
679
+
680
+	/**
681
+	 * Returns whether the field has many-to-one relation.
682
+	 *
683
+	 * @return bool
684
+	 */
685
+	public function hasRelationManyToOne()
686
+	{
687
+		$result = false;
688
+
689
+		$foreignField = $this->getForeignField();
690
+		if (!empty($foreignField)) {
691
+
692
+			// Load TCA service of the foreign field.
693
+			$foreignTable = $this->getForeignTable();
694
+			$result = $this->hasOne() && Tca::table($foreignTable)->field($foreignField)->hasMany();
695
+		}
696
+		return $result;
697
+	}
698
+
699
+	/**
700
+	 * Returns whether the field has one-to-many relation.
701
+	 *
702
+	 * @return bool
703
+	 */
704
+	public function hasRelationOneToMany()
705
+	{
706
+		$result = false;
707
+
708
+		$foreignField = $this->getForeignField();
709
+		if (!empty($foreignField)) {
710
+
711
+			// Load TCA service of the foreign field.
712
+			$foreignTable = $this->getForeignTable();
713
+			$result = $this->hasMany() && Tca::table($foreignTable)->field($foreignField)->hasOne();
714
+		}
715
+		return $result;
716
+	}
717
+
718
+	/**
719
+	 * Returns whether the field has one-to-one relation.
720
+	 *
721
+	 * @return bool
722
+	 */
723
+	public function hasRelationOneToOne()
724
+	{
725
+		$result = false;
726
+
727
+		$foreignField = $this->getForeignField();
728
+		if (!empty($foreignField)) {
729
+
730
+			// Load TCA service of foreign field.
731
+			$foreignTable = $this->getForeignTable();
732
+			$result = $this->hasOne() && Tca::table($foreignTable)->field($foreignField)->hasOne();
733
+		}
734
+		return $result;
735
+	}
736
+
737
+	/**
738
+	 * Returns whether the field has many to many relation.
739
+	 *
740
+	 * @return bool
741
+	 */
742
+	public function hasRelationManyToMany()
743
+	{
744
+		$configuration = $this->getConfiguration();
745
+		return $this->hasRelation() && (isset($configuration['MM']) || isset($configuration['foreign_table_field']));
746
+	}
747
+
748
+	/**
749
+	 * Returns whether the field has many to many relation using comma separated values (legacy).
750
+	 *
751
+	 * @return bool
752
+	 */
753
+	public function hasRelationWithCommaSeparatedValues()
754
+	{
755
+		$configuration = $this->getConfiguration();
756
+		return $this->hasRelation() && !isset($configuration['MM']) && !isset($configuration['foreign_field']) && $configuration['maxitems'] > 1;
757
+	}
758
+
759
+	/**
760
+	 * @return array
761
+	 */
762
+	public function getTca()
763
+	{
764
+		return $this->tca['columns'];
765
+	}
766
+
767
+	/**
768
+	 * @return string
769
+	 */
770
+	public function getCompositeField()
771
+	{
772
+		return $this->compositeField;
773
+	}
774
+
775
+	/**
776
+	 * @param string $compositeField
777
+	 */
778
+	public function setCompositeField($compositeField)
779
+	{
780
+		$this->compositeField = $compositeField;
781
+	}
782
+
783
+	/**
784
+	 * Returns an instance of the Frontend object.
785
+	 *
786
+	 * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
787
+	 */
788
+	protected function getFrontendObject()
789
+	{
790
+		return $GLOBALS['TSFE'];
791
+	}
792 792
 
793 793
 }
Please login to merge, or discard this patch.