Completed
Pull Request — master (#85)
by
unknown
06:05
created

EntityDefinition::checkFieldNames()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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