EntityDefinition   F
last analyzed

Complexity

Total Complexity 68

Size/Duplication

Total Lines 760
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 68
c 0
b 0
f 0
lcom 2
cbo 0
dl 0
loc 760
ccs 174
cts 174
cp 1
rs 2.8

45 Methods

Rating   Name   Duplication   Size   Complexity  
A getFilteredFieldNames() 0 11 3
A checkFieldNames() 0 13 4
A __construct() 0 21 1
A getFieldNames() 0 10 4
A setListFields() 0 5 1
A getListFields() 0 7 2
A getChildrenLabelFields() 0 4 1
A setChildrenLabelFields() 0 4 1
A isDeleteCascade() 0 4 1
A setDeleteCascade() 0 4 1
A getPageSize() 0 4 1
A setPageSize() 0 4 1
A getFilter() 0 4 1
A setFilter() 0 5 1
A getService() 0 4 1
A setService() 0 4 1
A getPublicFieldNames() 0 6 1
A getEditableFieldNames() 0 5 1
A getReadOnlyFields() 0 11 3
A getType() 0 13 4
A setType() 0 4 1
A getFieldLabel() 0 14 4
A setFieldLabel() 0 4 1
A getTable() 0 4 1
A setTable() 0 4 1
A getLabel() 0 7 3
A setLabel() 0 4 1
A addChild() 0 4 1
A getChildren() 0 4 1
A setStandardFieldLabels() 0 3 1
A setLocale() 0 4 1
A getLocale() 0 4 1
A setInitialSortField() 0 4 1
A getInitialSortField() 0 4 1
A setInitialSortAscending() 0 4 1
A isInitialSortAscending() 0 4 1
A setHardDeletion() 0 4 1
A isHardDeletion() 0 4 1
A getNavBarGroup() 0 4 1
A setNavBarGroup() 0 4 1
A hasOptimisticLocking() 0 4 1
A setOptimisticLocking() 0 4 1
A getSubTypeField() 0 9 2
A getField() 0 7 3
A setField() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like EntityDefinition often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EntityDefinition, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the CRUDlex package.
5
 *
6
 * (c) Philip Lehmann-Böhm <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace CRUDlex;
13
14
/**
15
 * The class for defining a single entity.
16
 */
17
class EntityDefinition
18
{
19
20
    /**
21
     * The table where the data is stored.
22
     * @var string
23
     */
24
    protected $table;
25
26
    /**
27
     * Holds all fields in the same structure as in the CRUD YAML file.
28
     * @var array
29
     */
30
    protected $fields;
31
32
    /**
33
     * The label for the entity.
34
     * @var string
35
     */
36
    protected $label;
37
38
    /**
39
     * The labels  of the entity in the locales.
40
     * @var array
41
     */
42
    protected $localeLabels;
43
44
    /**
45
     * An array with the children referencing the entity. All entries are
46
     * arrays with three referencing elements: table, fieldName, entity
47
     * @var array
48
     */
49
    protected $children;
50
51
    /**
52
     * Labels for the fields "id", "created_at" and "updated_at".
53
     * @var array
54
     */
55
    protected $standardFieldLabels;
56
57
    /**
58
     * An array containing the fields which should appear in the list view
59
     * of the entity.
60
     * @var array
61
     */
62
    protected $listFields;
63
64
    /**
65
     * The fields used to display the children on the details page of an entity.
66
     * The keys are the entity names as in the CRUD YAML and the values are the
67
     * field names.
68
     * @var array
69
     */
70
    protected $childrenLabelFields;
71
72
    /**
73
     * Whether to delete its children when an instance is deleted.
74
     * @var bool
75
     */
76
    protected $deleteCascade;
77
78
    /**
79
     * The amount of items to display per page on the listview.
80
     * @var int
81
     */
82
    protected $pageSize;
83
84
    /**
85
     * The fields offering to be filtered.
86
     * @var array
87
     */
88
    protected $filter;
89
90
    /**
91
     * Holds the service.
92
     * @var Service
93
     */
94
    protected $service;
95
96
    /**
97
     * Holds the locale.
98
     * @var string
99
     */
100
    protected $locale;
101
102
    /**
103
     * Holds the initial sort field.
104
     * @var string
105
     */
106
    protected $initialSortField;
107
108
    /**
109
     * Holds the initial sort order.
110
     * @var bool
111
     */
112
    protected $initialSortAscending;
113
114
    /**
115
     * Holds whether hard deletion is activated.
116
     * @var bool
117
     */
118
    protected $hardDeletion;
119
120
    /**
121
     * Holds if the entity must be displayed grouped in the nav bar.
122
     * @var string
123
     */
124
    protected $navBarGroup;
125
126
    /**
127
     * Holds whether optimistic locking is switched on.
128
     * @var bool
129
     */
130
    protected $optimisticLocking;
131
132
    /**
133
     * Gets the field names exluding the given ones.
134
     *
135
     * @param string[] $exclude
136
     * the field names to exclude
137
     *
138
     * @return array
139
     * all field names excluding the given ones
140
     */
141 79
    protected function getFilteredFieldNames(array $exclude)
142
    {
143 79
        $fieldNames = $this->getFieldNames(true);
144 79
        $result     = [];
145 79
        foreach ($fieldNames as $fieldName) {
146 79
            if (!in_array($fieldName, $exclude)) {
147 79
                $result[] = $fieldName;
148
            }
149
        }
150 79
        return $result;
151
    }
152
153
    /**
154
     * Checks whether the given field names are declared and existing.
155
     *
156
     * @param string $reference
157
     * a hint towards the source of an invalid field name
158
     * @param array $fieldNames
159
     * the field names to check
160
     * @throws \InvalidArgumentException
161
     * thrown with all invalid field names
162
     */
163 79
    protected function checkFieldNames($reference, $fieldNames)
164
    {
165 79
        $validFieldNames   = $this->getPublicFieldNames();
166 79
        $invalidFieldNames = [];
167 79
        foreach ($fieldNames as $fieldName) {
168 79
            if (!in_array($fieldName, $validFieldNames)) {
169 1
                $invalidFieldNames[] = $fieldName;
170
            }
171
        }
172 79
        if (!empty($invalidFieldNames)) {
173 1
            throw new \InvalidArgumentException('Invalid fields ('.join(', ', $invalidFieldNames).') in '.$reference.', valid ones are: '.join(', ', $validFieldNames));
174
        }
175 79
    }
176
177
    /**
178
     * Constructor.
179
     *
180
     * @param string $table
181
     * the table of the entity
182
     * @param array $fields
183
     * the field structure just like the CRUD YAML
184
     * @param string $label
185
     * the label of the entity
186
     * @param array $localeLabels
187
     * the labels  of the entity in the locales
188
     * @param array $standardFieldLabels
189
     * labels for the fields "id", "created_at" and "updated_at"
190
     * @param Service $service
191
     * The current service provider
192
     */
193 79
    public function __construct($table, array $fields, $label, $localeLabels, array $standardFieldLabels, Service $service)
194
    {
195 79
        $this->table                = $table;
196 79
        $this->fields               = $fields;
197 79
        $this->label                = $label;
198 79
        $this->localeLabels         = $localeLabels;
199 79
        $this->standardFieldLabels  = $standardFieldLabels;
200 79
        $this->service              = $service;
201 79
        $this->children             = [];
202 79
        $this->listFields           = [];
203 79
        $this->childrenLabelFields  = [];
204 79
        $this->filter               = [];
205 79
        $this->deleteCascade        = false;
206 79
        $this->pageSize             = 25;
207 79
        $this->locale               = null;
208 79
        $this->initialSortField     = 'created_at';
209 79
        $this->initialSortAscending = true;
210 79
        $this->hardDeletion         = false;
211 79
        $this->navBarGroup          = 'main';
212 79
        $this->optimisticLocking    = true;
213 79
    }
214
215
    /**
216
     * Gets all field names, including the implicit ones like "id" or
217
     * "created_at".
218
     *
219
     * @param boolean $includeMany
220
     * whether to include the many fields as well
221
     *
222
     * @return string[]
223
     * the field names
224
     */
225 79
    public function getFieldNames($includeMany = false)
226
    {
227 79
        $fieldNames = $this->getReadOnlyFields();
228 79
        foreach ($this->fields as $field => $value) {
229 79
            if ($includeMany || $this->getType($field) !== 'many') {
230 79
                $fieldNames[] = $field;
231
            }
232
        }
233 79
        return $fieldNames;
234
    }
235
236
    /**
237
     * Sets the field names to be used in the listview.
238
     *
239
     * @param array $listFields
240
     * the field names to be used in the listview
241
     */
242 79
    public function setListFields(array $listFields)
243
    {
244 79
        $this->checkFieldNames('listFields', $listFields);
245 79
        $this->listFields = $listFields;
246 79
    }
247
248
    /**
249
     * Gets the field names to be used in the listview. If they were not specified,
250
     * all public field names are returned.
251
     *
252
     * @return array
253
     * the field names to be used in the listview
254
     */
255 3
    public function getListFields()
256
    {
257 3
        if (!empty($this->listFields)) {
258 3
            return $this->listFields;
259
        }
260 2
        return $this->getPublicFieldNames();
261
    }
262
263
    /**
264
     * Gets the fields used to display the children on the details page of an
265
     * entity. The keys are the entity names as in the CRUD YAML and the values
266
     * are the field names.
267
     *
268
     * @return array
269
     * the fields used to display the children on the details page
270
     */
271 2
    public function getChildrenLabelFields()
272
    {
273 2
        return $this->childrenLabelFields;
274
    }
275
276
    /**
277
     * Sets the fields used to display the children on the details page of an
278
     * entity. The keys are the entity names as in the CRUD YAML and the values
279
     * are the field names.
280
     *
281
     * @param array $childrenLabelFields
282
     * the fields used to display the children on the details page
283
     */
284 79
    public function setChildrenLabelFields(array $childrenLabelFields)
285
    {
286 79
        $this->childrenLabelFields = $childrenLabelFields;
287 79
    }
288
289
    /**
290
     * Gets whether to delete its children when an instance is deleted.
291
     *
292
     * @return boolean
293
     * true if so
294
     */
295 6
    public function isDeleteCascade()
296
    {
297 6
        return $this->deleteCascade;
298
    }
299
300
    /**
301
     * Sets whether to delete its children when an instance is deleted.
302
     *
303
     * @param boolean $deleteCascade
304
     * whether to delete its children when an instance is deleted
305
     */
306 79
    public function setDeleteCascade($deleteCascade)
307
    {
308 79
        $this->deleteCascade = $deleteCascade;
309 79
    }
310
311
    /**
312
     * Gets the amount of items to display per page on the listview.
313
     *
314
     * @return integer
315
     * the amount of items to display per page on the listview
316
     */
317 3
    public function getPageSize()
318
    {
319 3
        return $this->pageSize;
320
    }
321
322
    /**
323
     * Sets the amount of items to display per page on the listview.
324
     *
325
     * @param integer $pageSize
326
     * the amount of items to display per page on the listview
327
     */
328 79
    public function setPageSize($pageSize)
329
    {
330 79
        $this->pageSize = $pageSize;
331 79
    }
332
333
    /**
334
     * Gets the fields offering a filter.
335
     *
336
     * @return array
337
     * the fields to filter
338
     */
339 3
    public function getFilter()
340
    {
341 3
        return $this->filter;
342
    }
343
344
    /**
345
     * Sets the fields offering a filter.
346
     *
347
     * @param array $filter
348
     * the fields to filter
349
     */
350 79
    public function setFilter(array $filter)
351
    {
352 79
        $this->checkFieldNames('filter', $filter);
353 79
        $this->filter = $filter;
354 79
    }
355
356
    /**
357
     * Gets the service.
358
     *
359
     * @return Service
360
     * the service provider
361
     */
362 35
    public function getService()
363
    {
364 35
        return $this->service;
365
    }
366
367
    /**
368
     * Sets the service.
369
     *
370
     * @param Service $service
371
     * the new service
372
     */
373 1
    public function setService(Service $service)
374
    {
375 1
        $this->service = $service;
376 1
    }
377
378
    /**
379
     * Gets the public field names. The internal fields "version" and
380
     * "deleted_at" are filtered.
381
     *
382
     * @return array
383
     * the public field names
384
     */
385 79
    public function getPublicFieldNames()
386
    {
387 79
        $exclude = ['version', 'deleted_at'];
388 79
        $result  = $this->getFilteredFieldNames($exclude);
389 79
        return $result;
390
    }
391
392
    /**
393
     * Gets the field names which are editable. Not editable are fields like the
394
     * id or the created_at.
395
     *
396
     * @return array
397
     * the editable field names
398
     */
399 39
    public function getEditableFieldNames()
400
    {
401 39
        $result = $this->getFilteredFieldNames($this->getReadOnlyFields());
402 39
        return $result;
403
    }
404
405
    /**
406
     * Gets the read only field names like the id or the created_at.
407
     *
408
     * @return string[]
409
     * the read only field names
410
     */
411 79
    public function getReadOnlyFields()
412
    {
413 79
        $result = ['id', 'created_at', 'updated_at'];
414 79
        if ($this->optimisticLocking) {
415 79
            $result[] = 'version';
416
        }
417 79
        if (!$this->hardDeletion) {
418 79
            $result[] = 'deleted_at';
419
        }
420 79
        return $result;
421
    }
422
423
    /**
424
     * Gets the type of a field.
425
     *
426
     * @param string $fieldName
427
     * the field name
428
     *
429
     * @return string
430
     * the type or null on invalid field name
431
     */
432 79
    public function getType($fieldName)
433
    {
434 79
        if ($fieldName === 'id') {
435 79
            return 'string';
436
        }
437 79
        if ($fieldName === 'version') {
438 79
            return 'integer';
439
        }
440 79
        if (in_array($fieldName, ['created_at', 'updated_at', 'deleted_at'])) {
441 79
            return 'datetime';
442
        }
443 79
        return $this->getField($fieldName, 'type');
444
    }
445
446
    /**
447
     * Sets the type of a field.
448
     *
449
     * @param string $fieldName
450
     * the field name
451
     * @param string $value
452
     * the new field type
453
     */
454 1
    public function setType($fieldName, $value)
455
    {
456 1
        $this->setField($fieldName, 'type', $value);
457 1
    }
458
459
    /**
460
     * Gets the label of a field.
461
     *
462
     * @param string $fieldName
463
     * the field name
464
     *
465
     * @return string
466
     * the label of the field or the field name if no label is set in the CRUD
467
     * YAML
468
     */
469 7
    public function getFieldLabel($fieldName)
470
    {
471 7
        $result = $this->getField($fieldName, 'label_'.$this->locale, $this->getField($fieldName, 'label'));
472
473 7
        if ($result === null && array_key_exists($fieldName, $this->standardFieldLabels)) {
474 5
            $result = $this->standardFieldLabels[$fieldName];
475
        }
476
477 7
        if ($result === null) {
478 1
            $result = $fieldName;
479
        }
480
481 7
        return $result;
482
    }
483
484
    /**
485
     * Gets the label of a field.
486
     *
487
     * @param string $fieldName
488
     * the field name
489
     * @param string $value
490
     * the new label of the field
491
     */
492 1
    public function setFieldLabel($fieldName, $value)
493
    {
494 1
        $this->setField($fieldName, 'label', $value);
495 1
    }
496
497
    /**
498
     * Gets the table where the data is stored.
499
     *
500
     * @return string
501
     * the table where the data is stored
502
     */
503 79
    public function getTable()
504
    {
505 79
        return $this->table;
506
    }
507
508
    /**
509
     * Sets the table where the data is stored.
510
     *
511
     * @param string $table
512
     * the new table where the data is stored
513
     */
514 1
    public function setTable($table)
515
    {
516 1
        $this->table = $table;
517 1
    }
518
519
    /**
520
     * Gets the label for the entity.
521
     *
522
     * @return string
523
     * the label for the entity
524
     */
525 11
    public function getLabel()
526
    {
527 11
        if ($this->locale && array_key_exists($this->locale, $this->localeLabels)) {
528 2
            return $this->localeLabels[$this->locale];
529
        }
530 11
        return $this->label;
531
    }
532
533
    /**
534
     * Sets the label for the entity.
535
     *
536
     * @param string $label
537
     * the new label for the entity
538
     */
539 1
    public function setLabel($label)
540
    {
541 1
        $this->label = $label;
542 1
    }
543
544
    /**
545
     * Adds a child to this definition in case the other
546
     * definition has a reference to this one.
547
     *
548
     * @param string $table
549
     * the table of the referencing definition
550
     * @param string $fieldName
551
     * the field name of the referencing definition
552
     * @param string $entity
553
     * the entity of the referencing definition
554
     */
555 79
    public function addChild($table, $fieldName, $entity)
556
    {
557 79
        $this->children[] = [$table, $fieldName, $entity];
558 79
    }
559
560
    /**
561
     * Gets the referencing children to this definition.
562
     *
563
     * @return array
564
     * an array with the children referencing the entity. All entries are arrays
565
     * with three referencing elements: table, fieldName, entity
566
     */
567 7
    public function getChildren()
568
    {
569 7
        return $this->children;
570
    }
571
572
573
    /**
574
     * Sets the labels for the fields "id", "created_at" and "updated_at".
575
     * @param array $standardFieldLabels
576
     * labels for the fields "id", "created_at" and "updated_at"
577
     */
578 1
    public function setStandardFieldLabels(array $standardFieldLabels) {
579 1
        $this->standardFieldLabels = $standardFieldLabels;
580 1
    }
581
582
    /**
583
     * Sets the locale to be used.
584
     *
585
     * @param string $locale
586
     * the locale to be used.
587
     */
588 6
    public function setLocale($locale)
589
    {
590 6
        $this->locale = $locale;
591 6
    }
592
593
    /**
594
     * Gets the locale to be used.
595
     *
596
     * @return null|string
597
     * the locale to be used.
598
     */
599 2
    public function getLocale()
600
    {
601 2
        return $this->locale;
602
    }
603
604
    /**
605
     * Sets the initial sort field.
606
     *
607
     * @param string $initialSortField
608
     * the new initial sort field
609
     */
610 79
    public function setInitialSortField($initialSortField)
611
    {
612 79
        $this->initialSortField = $initialSortField;
613 79
    }
614
615
    /**
616
     * Gets the initial sort field.
617
     *
618
     * @return string
619
     * the initial sort field
620
     */
621 4
    public function getInitialSortField()
622
    {
623 4
        return $this->initialSortField;
624
    }
625
626
    /**
627
     * Sets whether the initial sort order is ascending.
628
     *
629
     * @param boolean $initialSortAscending
630
     * the initial sort order, true if ascending
631
     */
632 79
    public function setInitialSortAscending($initialSortAscending)
633
    {
634 79
        $this->initialSortAscending = $initialSortAscending;
635 79
    }
636
637
    /**
638
     * Gets whether the initial sort order is ascending.
639
     *
640
     * @return boolean
641
     * the initial sort order, true if ascending
642
     */
643 4
    public function isInitialSortAscending()
644
    {
645 4
        return $this->initialSortAscending;
646
    }
647
648
    /**
649
     * Sets the hard deletion state.
650
     *
651
     * @param boolean $hardDeletion
652
     * the hard deletion state
653
     */
654 79
    public function setHardDeletion($hardDeletion)
655
    {
656 79
        $this->hardDeletion = $hardDeletion;
657 79
    }
658
659
    /**
660
     * Gets the hard deletion state.
661
     *
662
     * @return boolean
663
     * the hard deletion state
664
     */
665 35
    public function isHardDeletion()
666
    {
667 35
        return $this->hardDeletion;
668
    }
669
670
    /**
671
     * Gets the navigation bar group where the entity belongs.
672
     *
673
     * @return string
674
     * the navigation bar group where the entity belongs
675
     */
676 12
    public function getNavBarGroup()
677
    {
678 12
        return $this->navBarGroup;
679
    }
680
681
    /**
682
     * Sets the navigation bar group where the entity belongs.
683
     *
684
     * @param string $navBarGroup
685
     * the navigation bar group where the entity belongs
686
     */
687 79
    public function setNavBarGroup($navBarGroup)
688
    {
689 79
        $this->navBarGroup = $navBarGroup;
690 79
    }
691
692
    /**
693
     * Returns whether optimistic locking via the version field is activated.
694
     * @return boolean
695
     * true if optimistic locking is activated
696
     */
697 34
    public function hasOptimisticLocking()
698
    {
699 34
        return $this->optimisticLocking;
700
    }
701
702
703
    /**
704
     * Sets whether optimistic locking via the version field is activated.
705
     * @param boolean $optimisticLocking
706
     * true if optimistic locking is activated
707
     */
708 79
    public function setOptimisticLocking($optimisticLocking)
709
    {
710 79
        $this->optimisticLocking = $optimisticLocking;
711 79
    }
712
713
    /**
714
     * Gets a sub field of an field.
715
     *
716
     * @param string $fieldName
717
     * the field name of the sub type
718
     * @param string $subType
719
     * the sub type like "reference" or "many"
720
     * @param string $key
721
     * the key of the value
722
     *
723
     * @return string
724
     * the value of the sub field
725
     */
726 79
    public function getSubTypeField($fieldName, $subType, $key)
727
    {
728
729 79
        if (!isset($this->fields[$fieldName][$subType][$key])) {
730 24
            return null;
731
        }
732
733 79
        return $this->fields[$fieldName][$subType][$key];
734
    }
735
736
    /**
737
     * Gets the value of a field key.
738
     *
739
     * @param string $name
740
     * the name of the field
741
     * @param string $key
742
     * the value of the key
743
     * @param mixed $default
744
     * the default value to return if nothing is found
745
     *
746
     * @return mixed
747
     * the value of the field key or null if not existing
748
     */
749 79
    public function getField($name, $key, $default = null)
750
    {
751 79
        if (array_key_exists($name, $this->fields) && array_key_exists($key, $this->fields[$name])) {
752 79
            return $this->fields[$name][$key];
753
        }
754 40
        return $default;
755
    }
756
757
    /**
758
     * Sets the value of a field key. If the field or the key in the field
759
     * don't exist, they get created.
760
     *
761
     * @param string $name
762
     * the name of the field
763
     * @param string $key
764
     * the value of the key
765
     * @param mixed $value
766
     * the new value
767
     */
768 6
    public function setField($name, $key, $value)
769
    {
770 6
        if (!array_key_exists($name, $this->fields)) {
771 1
            $this->fields[$name] = [];
772
        }
773 6
        $this->fields[$name][$key] = $value;
774 6
    }
775
776
}
777