Completed
Push — master ( 6f54ca...9f3086 )
by Philip
04:28 queued 01:57
created

EntityDefinition::setPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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