GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#10)
by Andreas
02:21
created

AbstractDbEntity::unserialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
/**
3
 * Starlit Db.
4
 *
5
 * @copyright Copyright (c) 2016 Starweb AB
6
 * @license   BSD 3-Clause
7
 */
8
9
namespace Starlit\Db;
10
11
use Starlit\Utils\Str;
12
use Starlit\Utils\Arr;
13
14
/**
15
 * Abstract class to model a single database row into an object.
16
 *
17
 * @author Andreas Nilsson <http://github.com/jandreasn>
18
 */
19
abstract class AbstractDbEntity implements \Serializable
20
{
21
    /**
22
     * The database table name (meant to be overridden).
23
     *
24
     * @var string
25
     */
26
    protected static $dbTableName;
27
28
    /**
29
     * Entity's database properties and their attributes (meant to be overridden).
30
     * Example format:
31
     *
32
     * $dbProperties = [
33
     *     'productId' => ['type' => 'int'],
34
     *     'otherId'   => ['type' => 'int', 'required' => true,],
35
     *     'name'      => ['type' => 'string', 'maxLength' => 10, 'required' => true, 'default' => 'Some name'],
36
     * ];
37
     *
38
     * 'type' => 'int'     Corresponding PHP type (required).
39
     * 'required' => true  The value have to be set (not '', null, false)
40
     * 'nonEmpty' => true  The value should not be empty ('', 0, null)
41
     *
42
     * Properties correspond to database table's columns but words are
43
     * camel cased instead of separated with underscore (_) as in the database.
44
     *
45
     * @var array
46
     */
47
    protected static $dbProperties = [];
48
49
    /**
50
     * Object database field name that is used for primary key (meant to be overridden).
51
     * Should be camel cased as it maps to the dbFields array.
52
     *
53
     * @var string|array
54
     */
55
    protected static $primaryDbPropertyKey;
56
57
    /**
58
     * @var array
59
     */
60
    private static $cachedDefaultDbData = [];
61
62
    /**
63
     * @var array
64
     */
65
    private static $cachedDbPropertyNames;
66
67
    /**
68
     * @var array
69
     */
70
    private static $cachedDbFieldNames;
71
72
    /**
73
     * @var array
74
     */
75
    private static $typeDefaults = [
76
        'string'   => '',
77
        'int'      => 0,
78
        'float'    => 0.0,
79
        'bool'     => false,
80
        'dateTime' => null,
81
    ];
82
83
    /**
84
     * Database row data with field names and their values.
85
     *
86
     * @var array
87
     */
88
    private $dbData = [];
89
90
    /**
91
     * The primary key value currently set in database. This
92
     * can be different from the value in $dbData if the primary value
93
     * is changed.
94
     *
95
     * @var mixed
96
     */
97
    private $primaryDbValue;
98
99
    /**
100
     * Database fields that has had their value modified since init/load.
101
     *
102
     * @var array
103
     */
104
    private $modifiedDbProperties = [];
105
106
    /**
107
     * @var bool
108
     */
109
    private $deleteFromDbOnSave = false;
110
111
    /**
112
     * @var bool
113
     */
114
    private $deleted = false;
115
116
    /**
117
     * @var bool
118
     */
119
    private $forceDbInsertOnSave = false;
120
121
    /**
122
     * Constructor.
123
     *
124
     * @param mixed $primaryDbValueOrRowData
125
     */
126 70
    public function __construct($primaryDbValueOrRowData = null)
127
    {
128 70
        self::checkStaticProperties();
129
130
        // Set default values
131 69
        $this->dbData = $this->getDefaultDbData();
132
133
        // Override default values with provided values
134 69
        if ($primaryDbValueOrRowData !== null) {
135 13
            $this->setPrimaryDbValueOrRowData($primaryDbValueOrRowData);
136
        }
137 69
    }
138
139
    /**
140
     * Make sure that class has all necessary static properties set.
141
     */
142 70
    private static function checkStaticProperties()
143
    {
144 70
        static $checkedClasses = [];
145 70
        if (!in_array(static::class, $checkedClasses)) {
146 8
            if (empty(static::$dbTableName)
147 7
                || empty(static::$dbProperties)
148 7
                || empty(static::$primaryDbPropertyKey)
149 7
                || (is_scalar(static::$primaryDbPropertyKey)
150 7
                    && !isset(static::$dbProperties[static::$primaryDbPropertyKey]['type']))
151 7
                || (is_array(static::$primaryDbPropertyKey)
152 8
                    && !Arr::allIn(static::$primaryDbPropertyKey, array_keys(static::$dbProperties)))
153
            ) {
154 1
                throw new \LogicException("All db entity's static properties not set");
155
            }
156 7
            $checkedClasses[] = static::class;
157
        }
158 69
    }
159
160
    /**
161
     * @param mixed $primaryDbValueOrRowData
162
     */
163 13
    public function setPrimaryDbValueOrRowData($primaryDbValueOrRowData = null)
164
    {
165
        // Row data would be an associative array (i.e. not sequential, that would
166
        // indicate a multi column primary key)
167 13
        if (is_array($primaryDbValueOrRowData) && !isset($primaryDbValueOrRowData[0])) {
168 1
            $this->setDbDataFromRow($primaryDbValueOrRowData);
169
        } else {
170 12
            $this->setPrimaryDbValue($primaryDbValueOrRowData);
171
        }
172 13
    }
173
174
    /**
175
     * Get all default database values.
176
     *
177
     * @return array
178
     */
179 69
    public function getDefaultDbData()
180
    {
181 69
        $class = get_called_class();
182 69
        if (!isset(self::$cachedDefaultDbData[$class])) {
183 7
            self::$cachedDefaultDbData[$class] = [];
184 7
            foreach (array_keys(static::$dbProperties) as $propertyName) {
185 7
                self::$cachedDefaultDbData[$class][$propertyName] = $this->getDefaultDbPropertyValue($propertyName);
186
            }
187
        }
188
189 69
        return self::$cachedDefaultDbData[$class];
190
    }
191
192
    /**
193
     * Get default db value (can be overridden if non static default values need to be used).
194
     *
195
     * @param string $propertyName
196
     * @return mixed
197
     */
198 15
    public function getDefaultDbPropertyValue($propertyName)
199
    {
200
        // A default value is set
201 15
        if (array_key_exists('default', static::$dbProperties[$propertyName])) {
202 5
            $defaultValue = static::$dbProperties[$propertyName]['default'];
203
        // No default value set, use default for type
204
        } else {
205 15
            $defaultValue = self::$typeDefaults[static::$dbProperties[$propertyName]['type']];
206
        }
207
208 15
        return $defaultValue;
209
    }
210
211
    /**
212
     * The primary key value currently set in database.
213
     *
214
     * This can be different from the value/values in $dbData
215
     * if a primary value is changed.
216
     *
217
     * @return mixed
218
     */
219 26
    public function getPrimaryDbValue()
220
    {
221 26
        return $this->primaryDbValue;
222
    }
223
224
    /**
225
     * @param mixed $primaryDbValue
226
     */
227 24
    public function setPrimaryDbValue($primaryDbValue)
228
    {
229 24
        $typedPrimaryDbValue = $this->getPrimaryDbValueWithPropertyType($primaryDbValue);
230
231 23
        $this->primaryDbValue = $typedPrimaryDbValue;
232 23
        $this->setDbDataPrimaryValue($typedPrimaryDbValue);
233 23
    }
234
235
    /**
236
     * @param mixed $primaryDbValue
237
     */
238 23
    protected function setDbDataPrimaryValue($primaryDbValue)
239
    {
240 23
        if (is_array(static::$primaryDbPropertyKey)) {
241 3
            reset($primaryDbValue);
242 3
            foreach (static::$primaryDbPropertyKey as $keyPart) {
243 3
                $this->dbData[$keyPart] = current($primaryDbValue);
244 3
                next($primaryDbValue);
245
            }
246
        } else {
247 20
            $this->dbData[static::$primaryDbPropertyKey] = $primaryDbValue;
248
        }
249 23
    }
250
251
    /**
252
     * Update primary database value with data from set database data.
253
     */
254 10
    public function updatePrimaryDbValueFromDbData()
255
    {
256 10
        $dbDataPrimaryValue = $this->getDbDataPrimaryValue();
257
258 10
        if ($dbDataPrimaryValue !== $this->getDbDataPrimaryDefaultValue()) {
259 8
            $this->setPrimaryDbValue($dbDataPrimaryValue);
260
        }
261 10
    }
262
263
    /**
264
     * @return mixed|array
265
     */
266 10 View Code Duplication
    protected function getDbDataPrimaryValue()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
267
    {
268 10
        if (is_array(static::$primaryDbPropertyKey)) {
269 1
            $primaryValues = [];
270 1
            foreach (static::$primaryDbPropertyKey as $propertyName) {
271 1
                $primaryValues[] = $this->getDbValue($propertyName);
272
            }
273
274 1
            return $primaryValues;
275
        }
276
277 9
        return $this->getDbValue(static::$primaryDbPropertyKey);
278
    }
279
280
    /**
281
     * @return mixed|array
282
     */
283 10 View Code Duplication
    private function getDbDataPrimaryDefaultValue()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
284
    {
285 10
        if (is_array(static::$primaryDbPropertyKey)) {
286 1
            $primaryValues = [];
287 1
            foreach (static::$primaryDbPropertyKey as $propertyName) {
288 1
                $primaryValues[] = $this->getDefaultDbPropertyValue($propertyName);
289
            }
290
291 1
            return $primaryValues;
292
        }
293
294 9
        return $this->getDefaultDbPropertyValue(static::$primaryDbPropertyKey);
295
    }
296
297
    /**
298
     * @return bool
299
     */
300 10
    public function isNewDbEntity()
301
    {
302 10
        if (is_array(static::$primaryDbPropertyKey)) {
303
            // Multiple column keys have to use explicit force insert because we have no way
304
            // to detect if it's a new entity (can't leave more than one primary field empty
305
            // on insert because db can't have two auto increment columns)
306 1
            throw new \LogicException("Can't detect if multi column primary key is a new entity");
307
        }
308
309 9
        return !$this->getPrimaryDbValue();
310
    }
311
312
    /**
313
     * @return bool
314
     */
315 9
    public function shouldInsertOnDbSave()
316
    {
317 9
        return (!is_array(static::$primaryDbPropertyKey) && $this->isNewDbEntity())
318 9
            || $this->shouldForceDbInsertOnSave();
319
    }
320
321
    /**
322
     * Set a row field value.
323
     *
324
     * @param string $property
325
     * @param mixed  $value
326
     * @param bool   $setAsModified
327
     * @param bool   $force
328
     */
329 29
    protected function setDbValue($property, $value, $setAsModified = true, $force = false)
330
    {
331 29
        $value = $this->getValueWithPropertyType($property, $value);
332
333 28
        if ($this->dbData[$property] !== $value || $force) {
334 24
            $this->dbData[$property] = $value;
335
336 24
            if ($setAsModified && !$this->isDbPropertyModified($property)) {
337 17
                $this->modifiedDbProperties[] = $property;
338
            }
339
        }
340 28
    }
341
342
    /**
343
     * @param string $property
344
     * @param mixed  $value
345
     * @return mixed
346
     */
347 41
    private function getValueWithPropertyType(string $property, $value) {
348 41
        if (!isset(static::$dbProperties[$property])) {
349 1
            throw new \InvalidArgumentException("No database entity property[{$property}] exists");
350
        }
351
352
         // Don't set type if value is null and allowed (allowed currently indicated by default => null)
353 40
        $nullIsAllowed = (array_key_exists('default', static::$dbProperties[$property])
354 40
            && static::$dbProperties[$property]['default'] === null);
355 40
        if (!($value === null && $nullIsAllowed)) {
356 39
            $type = static::$dbProperties[$property]['type'];
357
            // Set null when empty and default is null
358 39
            if ($value === '' && $nullIsAllowed) {
359 1
                 $value = null;
360 39
            } elseif ($type === 'dateTime') {
361 1
                if (!($value instanceof \DateTimeInterface)) {
362 1
                    $value = $this->createDateTimeDbValue($value);
363
                }
364
            } else {
365 38
                settype($value, $type);
366
            }
367
        }
368
369 40
        return $value;
370
    }
371
372
    /**
373
     * @param string $property
0 ignored issues
show
Bug introduced by
There is no parameter named $property. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
374
     * @param mixed $value
0 ignored issues
show
Bug introduced by
There is no parameter named $value. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
375
     * @return mixed
376
     */
377 24
    private function getPrimaryDbValueWithPropertyType($primaryDbValue) {
378 24
        if (is_array(static::$primaryDbPropertyKey)) {
379 4
            if (!is_array($primaryDbValue)
380 4
                || count(static::$primaryDbPropertyKey) !== count($primaryDbValue)
381
            ) {
382 1
                throw new \InvalidArgumentException(sprintf(
383 1
                    'Primary db value should be an array of length %d',
384 1
                    count(static::$primaryDbPropertyKey)
385
                ));
386
            }
387
388 3
            $primaryDbValueParts = [];
389 3
            reset($primaryDbValue);
390 3
            foreach (static::$primaryDbPropertyKey as $keyPart) {
391 3
                $partValue = current($primaryDbValue);
392 3
                $primaryDbValueParts[] = $this->getValueWithPropertyType($keyPart, $partValue);
393 3
                next($primaryDbValue);
394
            }
395
396 3
            return $primaryDbValueParts;
397
        }
398
399 20
        return $this->getValueWithPropertyType(
400 20
            static::$primaryDbPropertyKey,
401 20
            $primaryDbValue
402
        );
403
    }
404
405
    /**
406
     * @param string $value
407
     * @return \DateTime|\Carbon\Carbon|null
408
     */
409 1
    protected function createDateTimeDbValue($value)
410
    {
411 1
        static $carbonExists = null;
412 1
        if ($carbonExists === true
413 1
            || ($carbonExists === null && ($carbonExists = class_exists(\Carbon\Carbon::class)))
414
        ) {
415 1
            return new \Carbon\Carbon($value);
416
        }
417
418
        return new \DateTime($value);
419
    }
420
421
    /**
422
     * Get a database field value.
423
     *
424
     * @param string $property
425
     * @return mixed
426
     */
427 17
    protected function getDbValue($property)
428
    {
429 17
        return $this->dbData[$property];
430
    }
431
432
    /**
433
     * Get raw (with underscore as word separator as it is formatted in database)
434
     * field name from a object field property name (camelcased).
435
     *
436
     * @param string $propertyName
437
     * @return string
438
     */
439 22
    public static function getDbFieldName($propertyName)
440
    {
441 22
        if (!isset(self::$cachedDbFieldNames[$propertyName])) {
442 6
            self::$cachedDbFieldNames[$propertyName] = Str::camelToSeparator($propertyName);
443
        }
444
445 22
        return self::$cachedDbFieldNames[$propertyName];
446
    }
447
448
    /**
449
     * Get object field property name (camelCased) from database field name (underscore separated).
450
     *
451
     * @param string $dbFieldName
452
     * @return string
453
     */
454 7
    public static function getDbPropertyName($dbFieldName)
455
    {
456 7
        if (!isset(self::$cachedDbPropertyNames[$dbFieldName])) {
457 2
            self::$cachedDbPropertyNames[$dbFieldName] = Str::separatorToCamel($dbFieldName);
458
        }
459
460 7
        return self::$cachedDbPropertyNames[$dbFieldName];
461
    }
462
463
    /**
464
     * @return bool
465
     */
466 5
    public function hasModifiedDbProperties()
467
    {
468 5
        return !empty($this->modifiedDbProperties);
469
    }
470
471
    /**
472
     * @param string $property
473
     * @return bool
474
     */
475 18
    public function isDbPropertyModified($property)
476
    {
477 18
        return in_array($property, $this->modifiedDbProperties);
478
    }
479
480
    /**
481
     * @return array
482
     */
483 6
    public function getModifiedDbData()
484
    {
485 6
        return array_intersect_key($this->dbData, array_flip($this->modifiedDbProperties));
486
    }
487
488
    /**
489
     * @param string $property
490
     */
491
    public function clearModifiedDbProperty($property)
492
    {
493
        if (($key = array_search($property, $this->modifiedDbProperties))) {
494
            unset($this->modifiedDbProperties[$key]);
495
        }
496
    }
497
498 4
    public function clearModifiedDbProperties()
499
    {
500 4
        $this->modifiedDbProperties = [];
501 4
    }
502
503 1
    public function setAllDbPropertiesAsModified()
504
    {
505 1
        $this->modifiedDbProperties = array_keys(static::$dbProperties);
506 1
    }
507
508
    /**
509
     * Magic method used to automate getters & setters for row data.
510
     *
511
     * @param string $name
512
     * @param array  $arguments
513
     * @return mixed
514
     */
515 23
    public function __call($name, array $arguments = [])
516
    {
517 23
        $propertyName = lcfirst(substr($name, 3));
518
519 23
        if (strpos($name, 'get') === 0 && isset(static::$dbProperties[$propertyName])) {
520 7
            return $this->getDbValue($propertyName);
521 19
        } elseif (strpos($name, 'set') === 0 && isset(static::$dbProperties[$propertyName])) {
522 18
            $argumentCount = count($arguments);
523 18
            if ($argumentCount >= 1 && $argumentCount <= 3) {
524 17
                return $this->setDbValue($propertyName, ...$arguments);
525
            } else {
526 1
                throw new \BadMethodCallException("Invalid argument count[{$argumentCount}] for {$name}()");
527
            }
528
        } else {
529 1
            throw new \BadMethodCallException("No method named {$name}()");
530
        }
531
    }
532
533
    /**
534
     * Set database fields' data.
535
     *
536
     * @param array $data
537
     */
538 3
    public function setDbData(array $data)
539
    {
540 3 View Code Duplication
        foreach (array_keys(static::$dbProperties) as $propertyName) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
541 3
            if (array_key_exists($propertyName, $data)) {
542 3
                $this->setDbValue($propertyName, $data[$propertyName], true);
543
            }
544
        }
545 3
    }
546
547
    /**
548
     * Set db data from raw database row data with field names in database format.
549
     *
550
     * @param array $rowData
551
     */
552 7
    public function setDbDataFromRow(array $rowData)
553
    {
554
        // If there are less row data than properties, use rows as starting point (optimization)
555 7
        if (count($rowData) < count(static::$dbProperties)) {
556 6
            foreach ($rowData as $dbFieldName => $value) {
557 6
                $propertyName = static::getDbPropertyName($dbFieldName);
558 6
                if (isset(static::$dbProperties[$propertyName])) {
559 6
                    $this->setDbValue($propertyName, $value, false);
560
                }
561
            }
562
        // If there are more row data than properties, use properties as starting point
563
        } else {
564 2 View Code Duplication
            foreach (array_keys(static::$dbProperties) as $propertyName) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
565 2
                $fieldName = static::getDbFieldName($propertyName);
566 2
                if (array_key_exists($fieldName, $rowData)) {
567 2
                    $this->setDbValue($propertyName, $rowData[$fieldName], false);
568
                }
569
            }
570
        }
571
572 7
        $this->updatePrimaryDbValueFromDbData();
573 7
    }
574
575
    /**
576
     * @return mixed
577
     */
578
    protected function getPrimaryDbValueFromRow(array $rowData)
579
    {
580
        if (is_array(static::$primaryDbPropertyKey)) {
581
            $primaryValues = [];
582
            foreach (static::$primaryDbPropertyKey as $keyPart) {
583
                $fieldName = static::getDbFieldName($keyPart);
584
                $primaryValues[] = $rowData[$fieldName] ?? null;
585
            }
586
587
            return $primaryValues;
588
        }
589
590
        $fieldName = static::getDbFieldName(static::$primaryDbPropertyKey);
591
592
        return $rowData[$fieldName] ?? null;
593
    }
594
595
    /**
596
     * @return array
597
     */
598 11
    public function getDbData()
599
    {
600 11
        return $this->dbData;
601
    }
602
603
    /**
604
     * @return array
605
     */
606 1
    public function getDbRowData()
607
    {
608 1
        $rowData = [];
609 1
        foreach ($this->getDbData() as $propertyName => $value) {
610 1
            $dbFieldName = static::getDbFieldName($propertyName);
611 1
            $rowData[$dbFieldName] = $value;
612
        }
613
614 1
        return $rowData;
615
    }
616
617
    /**
618
     * @return array
619
     */
620 2
    public function getDbDataWithoutPrimary()
621
    {
622 2
        $dbDataWithoutPrimary = $this->dbData;
623
624 2
        if (is_array(static::$primaryDbPropertyKey)) {
625 1
            foreach (static::$primaryDbPropertyKey as $keyPart) {
626 1
                unset($dbDataWithoutPrimary[$keyPart]);
627
            }
628
        } else {
629 1
            unset($dbDataWithoutPrimary[static::$primaryDbPropertyKey]);
630
        }
631
632 2
        return $dbDataWithoutPrimary;
633
    }
634
635
    /**
636
     * @param bool $deleteFromDbOnSave
637
     */
638 3
    public function setDeleteFromDbOnSave($deleteFromDbOnSave = true)
639
    {
640 3
        $this->deleteFromDbOnSave = $deleteFromDbOnSave;
641 3
    }
642
643
    /**
644
     * @return bool
645
     */
646 11
    public function shouldBeDeletedFromDbOnSave()
647
    {
648 11
        return $this->deleteFromDbOnSave;
649
    }
650
651
    /**
652
     * @return bool
653
     */
654 1
    public function isDeleted()
655
    {
656 1
        return $this->deleted;
657
    }
658
659
    /**
660
     * @param bool $deleted
661
     */
662 3
    public function setDeleted($deleted = true)
663
    {
664 3
        $this->deleted = $deleted;
665 3
    }
666
667
    /**
668
     * @param bool $forceDbInsertOnSave
669
     */
670 5
    public function setForceDbInsertOnSave($forceDbInsertOnSave)
671
    {
672 5
        $this->forceDbInsertOnSave = $forceDbInsertOnSave;
673 5
    }
674
675
    /**
676
     * @return bool
677
     */
678 5
    public function shouldForceDbInsertOnSave()
679
    {
680 5
        return $this->forceDbInsertOnSave;
681
    }
682
683
    /**
684
     * @return array
685
     */
686 1
    public static function getDbProperties()
687
    {
688 1
        return static::$dbProperties;
689
    }
690
691
    /**
692
     * @param string $propertyName
693
     * @return int|null
694
     */
695 6
    public static function getDbPropertyMaxLength($propertyName)
696
    {
697 6
        return isset(static::$dbProperties[$propertyName]['maxLength'])
698 6
            ? static::$dbProperties[$propertyName]['maxLength']
699 6
            : null;
700
    }
701
702
    /**
703
     * @param string $propertyName
704
     * @return bool
705
     */
706 3
    public static function getDbPropertyRequired($propertyName)
707
    {
708 3
        return isset(static::$dbProperties[$propertyName]['required'])
709 3
            ? static::$dbProperties[$propertyName]['required']
710 3
            : false;
711
    }
712
713
    /**
714
     * @param string $propertyName
715
     * @return bool
716
     */
717 6
    public static function getDbPropertyNonEmpty($propertyName)
718
    {
719 6
        return isset(static::$dbProperties[$propertyName]['nonEmpty'])
720 2
            ? static::$dbProperties[$propertyName]['nonEmpty']
721 6
            : false;
722
    }
723
724
    /**
725
     * @return string|array
726
     */
727 14
    public static function getPrimaryDbPropertyKey()
728
    {
729 14
        return static::$primaryDbPropertyKey;
730
    }
731
732
    /**
733
     * @return string|array
734
     */
735 10
    public static function getPrimaryDbFieldKey()
736
    {
737 10
        $primaryDbPropertyKey = static::getPrimaryDbPropertyKey();
738
739 10
        if (is_array($primaryDbPropertyKey)) {
740 3
            $primaryDbFieldKey = [];
741 3
            foreach ($primaryDbPropertyKey as $propertyName) {
742 3
                $primaryDbFieldKey[] = static::getDbFieldName($propertyName);
743
            }
744
745 3
            return $primaryDbFieldKey;
746
        } else {
747 7
            return static::getDbFieldName($primaryDbPropertyKey);
748
        }
749
    }
750
751
    /**
752
     * Return array with db property names.
753
     *
754
     * @param array $exclude
755
     * @return array
756
     */
757 1
    public static function getDbPropertyNames(array $exclude = [])
758
    {
759 1
        $dbPropertyNames = array_keys(static::$dbProperties);
760
761 1
        return $exclude ? array_diff($dbPropertyNames, $exclude) : $dbPropertyNames;
762
    }
763
764
    /**
765
     * Return array with raw db field names.
766
     *
767
     * @param array $exclude
768
     * @return array
769
     */
770 3
    public static function getDbFieldNames(array $exclude = [])
771
    {
772 3
        $fieldNames = [];
773 3
        foreach (array_keys(static::$dbProperties) as $propertyName) {
774 3
            $fieldNames[] = static::getDbFieldName($propertyName);
775
        }
776
777 3
        return $exclude ? array_diff($fieldNames, $exclude) : $fieldNames;
778
    }
779
780
781
    /**
782
     * Get raw database field names prefixed (id, name becomes t.id, t.name etc.).
783
     *
784
     * @param string $dbTableAlias
785
     * @param array  $exclude
786
     * @return array
787
     */
788 1
    public static function getPrefixedDbFieldNames($dbTableAlias, array $exclude = [])
789
    {
790 1
        return Arr::valuesWithPrefix(static::getDbFieldNames($exclude), $dbTableAlias . '.');
791
    }
792
793
    /**
794
     * Get database columns transformed from e.g. "productId, date" to "p.product_id AS p_product_id, p.date AS p_date".
795
     *
796
     * @param string $dbTableAlias
797
     * @param array  $exclude
798
     * @return array
799
     */
800 1
    public static function getAliasedDbFieldNames($dbTableAlias, array $exclude = [])
801
    {
802 1
        $newArray = [];
803 1
        foreach (static::getDbFieldNames($exclude) as $dbFieldName) {
804 1
            $fromCol = $dbTableAlias . '.' . $dbFieldName;
805 1
            $toCol = $dbTableAlias . '_' . $dbFieldName;
806 1
            $newArray[] = $fromCol . ' AS ' . $toCol;
807
        }
808
809 1
        return $newArray;
810
    }
811
812
    /**
813
     * Filters a full db item array by it's table alias and the strips the table alias.
814
     *
815
     * @param array  $rowData
816
     * @param string $dbTableAlias
817
     * @param bool   $skipStrip For cases when you want to filter only (no stripping)
818
     * @return array
819
     */
820 1
    public static function filterStripDbRowData(array $rowData, $dbTableAlias, $skipStrip = false)
821
    {
822 1
        $columnPrefix = $dbTableAlias . '_';
823
824 1
        $filteredAndStrippedRowData = [];
825 1
        foreach ($rowData as $key => $val) {
826 1
            if (strpos($key, $columnPrefix) === 0) {
827 1
                $strippedKey = $skipStrip ? $key : Str::stripLeft($key, $columnPrefix);
828 1
                $filteredAndStrippedRowData[$strippedKey] = $val;
829
            }
830
        }
831
832 1
        return $filteredAndStrippedRowData;
833
    }
834
835
    /**
836
     * @return string
837
     */
838 8
    public static function getDbTableName()
839
    {
840 8
        return static::$dbTableName;
841
    }
842
843
    /**
844
     * Method to handle the serialization of this object.
845
     *
846
     * Implementation of Serializable interface. If descendant private properties
847
     * should be serialized, they need to be visible to this parent (i.e. not private).
848
     *
849
     * @return string
850
     */
851 2
    public function serialize()
852
    {
853 2
        return serialize(get_object_vars($this));
854
    }
855
856
    /**
857
     * Method to handle the unserialization of this object.
858
     *
859
     * Implementation of Serializable interface. If descendant private properties
860
     * should be unserialized, they need to be visible to this parent (i.e. not private).
861
     *
862
     * @param string $serializedObject
863
     */
864 1
    public function unserialize($serializedObject)
865
    {
866 1
        $objectVars = unserialize($serializedObject);
867
868 1
        foreach ($objectVars as $key => $value) {
869 1
            $this->{$key} = $value;
870
        }
871 1
    }
872
873
    /**
874
     * Merges other object's modified database data into this object.
875
     *
876
     * @param AbstractDbEntity $otherEntity
877
     */
878 1
    public function mergeWith(AbstractDbEntity $otherEntity)
879
    {
880 1
        $dataToMerge = $otherEntity->getModifiedDbData();
881 1
        $this->setDbData($dataToMerge);
882 1
    }
883
}
884