Completed
Push — master ( 5cda12...99b8e2 )
by Philip
02:31
created

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