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:51
created

AbstractDbEntity::getPrimaryDbValueFromDbData()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5.0342

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 8
cts 9
cp 0.8889
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 6
nop 0
crap 5.0342
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 7
    public function getDefaultDbPropertyValue($propertyName)
199
    {
200
        // A default value is set
201 7
        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 7
            $defaultValue = self::$typeDefaults[static::$dbProperties[$propertyName]['type']];
206
        }
207
208 7
        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
        $primaryDbValue = $this->getPrimaryDbValueFromDbData();
257
258 10
        if ($primaryDbValue !== null) {
259 8
            $this->setPrimaryDbValue($primaryDbValue);
260
        }
261 10
    }
262
263
    /**
264
     * @return mixed|null Returns value/values or null if not set
265
     */
266 10
    protected function getPrimaryDbValueFromDbData()
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
            if (empty(array_filter($primaryValues))) {
275
                return null;
276
            }
277
278 1
            return $primaryValues;
279
        }
280
281 9
        return $this->getDbValue(static::$primaryDbPropertyKey) ?: null;
282
    }
283
284
    /**
285
     * @return bool
286
     */
287 10
    public function isNewDbEntity()
288
    {
289 10
        if (is_array(static::$primaryDbPropertyKey)) {
290
            // Multiple column keys have to use explicit force insert because we have no way
291
            // to detect if it's a new entity (can't leave more than one primary field empty
292
            // on insert because db can't have two auto increment columns)
293 1
            throw new \LogicException("Can't detect if multi column primary key is a new entity");
294
        }
295
296 9
        return !$this->getPrimaryDbValue();
297
    }
298
299
    /**
300
     * @return bool
301
     */
302 9
    public function shouldInsertOnDbSave()
303
    {
304 9
        return (!is_array(static::$primaryDbPropertyKey) && $this->isNewDbEntity())
305 9
            || $this->shouldForceDbInsertOnSave();
306
    }
307
308
    /**
309
     * Set a row field value.
310
     *
311
     * @param string $property
312
     * @param mixed  $value
313
     * @param bool   $setAsModified
314
     * @param bool   $force
315
     */
316 29
    protected function setDbValue($property, $value, $setAsModified = true, $force = false)
317
    {
318 29
        $value = $this->getValueWithPropertyType($property, $value);
319
320 28
        if ($this->dbData[$property] !== $value || $force) {
321 24
            $this->dbData[$property] = $value;
322
323 24
            if ($setAsModified && !$this->isDbPropertyModified($property)) {
324 17
                $this->modifiedDbProperties[] = $property;
325
            }
326
        }
327 28
    }
328
329
    /**
330
     * @param string $property
331
     * @param mixed  $value
332
     * @return mixed
333
     */
334 41
    private function getValueWithPropertyType(string $property, $value) {
335 41
        if (!isset(static::$dbProperties[$property])) {
336 1
            throw new \InvalidArgumentException("No database entity property[{$property}] exists");
337
        }
338
339
         // Don't set type if value is null and allowed (allowed currently indicated by default => null)
340 40
        $nullIsAllowed = (array_key_exists('default', static::$dbProperties[$property])
341 40
            && static::$dbProperties[$property]['default'] === null);
342 40
        if (!($value === null && $nullIsAllowed)) {
343 39
            $type = static::$dbProperties[$property]['type'];
344
            // Set null when empty and default is null
345 39
            if ($value === '' && $nullIsAllowed) {
346 1
                 $value = null;
347 39
            } elseif ($type === 'dateTime') {
348 1
                if (!($value instanceof \DateTimeInterface)) {
349 1
                    $value = $this->createDateTimeDbValue($value);
350
                }
351
            } else {
352 38
                settype($value, $type);
353
            }
354
        }
355
356 40
        return $value;
357
    }
358
359
    /**
360
     * @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...
361
     * @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...
362
     * @return mixed
363
     */
364 24
    private function getPrimaryDbValueWithPropertyType($primaryDbValue) {
365 24
        if (is_array(static::$primaryDbPropertyKey)) {
366 4
            if (!is_array($primaryDbValue)
367 4
                || count(static::$primaryDbPropertyKey) !== count($primaryDbValue)
368
            ) {
369 1
                throw new \InvalidArgumentException(sprintf(
370 1
                    'Primary db value should be an array of length %d',
371 1
                    count(static::$primaryDbPropertyKey)
372
                ));
373
            }
374
375 3
            $primaryDbValueParts = [];
376 3
            reset($primaryDbValue);
377 3
            foreach (static::$primaryDbPropertyKey as $keyPart) {
378 3
                $partValue = current($primaryDbValue);
379 3
                $primaryDbValueParts[] = $this->getValueWithPropertyType($keyPart, $partValue);
380 3
                next($primaryDbValue);
381
            }
382
383 3
            return $primaryDbValueParts;
384
        }
385
386 20
        return $this->getValueWithPropertyType(
387 20
            static::$primaryDbPropertyKey,
388 20
            $primaryDbValue
389
        );
390
    }
391
392
    /**
393
     * @param string $value
394
     * @return \DateTime|\Carbon\Carbon|null
395
     */
396 1
    protected function createDateTimeDbValue($value)
397
    {
398 1
        static $carbonExists = null;
399 1
        if ($carbonExists === true
400 1
            || ($carbonExists === null && ($carbonExists = class_exists(\Carbon\Carbon::class)))
401
        ) {
402 1
            return new \Carbon\Carbon($value);
403
        }
404
405
        return new \DateTime($value);
406
    }
407
408
    /**
409
     * Get a database field value.
410
     *
411
     * @param string $property
412
     * @return mixed
413
     */
414 17
    protected function getDbValue($property)
415
    {
416 17
        return $this->dbData[$property];
417
    }
418
419
    /**
420
     * Get raw (with underscore as word separator as it is formatted in database)
421
     * field name from a object field property name (camelcased).
422
     *
423
     * @param string $propertyName
424
     * @return string
425
     */
426 22
    public static function getDbFieldName($propertyName)
427
    {
428 22
        if (!isset(self::$cachedDbFieldNames[$propertyName])) {
429 6
            self::$cachedDbFieldNames[$propertyName] = Str::camelToSeparator($propertyName);
430
        }
431
432 22
        return self::$cachedDbFieldNames[$propertyName];
433
    }
434
435
    /**
436
     * Get object field property name (camelCased) from database field name (underscore separated).
437
     *
438
     * @param string $dbFieldName
439
     * @return string
440
     */
441 7
    public static function getDbPropertyName($dbFieldName)
442
    {
443 7
        if (!isset(self::$cachedDbPropertyNames[$dbFieldName])) {
444 2
            self::$cachedDbPropertyNames[$dbFieldName] = Str::separatorToCamel($dbFieldName);
445
        }
446
447 7
        return self::$cachedDbPropertyNames[$dbFieldName];
448
    }
449
450
    /**
451
     * @return bool
452
     */
453 5
    public function hasModifiedDbProperties()
454
    {
455 5
        return !empty($this->modifiedDbProperties);
456
    }
457
458
    /**
459
     * @param string $property
460
     * @return bool
461
     */
462 18
    public function isDbPropertyModified($property)
463
    {
464 18
        return in_array($property, $this->modifiedDbProperties);
465
    }
466
467
    /**
468
     * @return array
469
     */
470 6
    public function getModifiedDbData()
471
    {
472 6
        return array_intersect_key($this->dbData, array_flip($this->modifiedDbProperties));
473
    }
474
475
    /**
476
     * @param string $property
477
     */
478
    public function clearModifiedDbProperty($property)
479
    {
480
        if (($key = array_search($property, $this->modifiedDbProperties))) {
481
            unset($this->modifiedDbProperties[$key]);
482
        }
483
    }
484
485 4
    public function clearModifiedDbProperties()
486
    {
487 4
        $this->modifiedDbProperties = [];
488 4
    }
489
490 1
    public function setAllDbPropertiesAsModified()
491
    {
492 1
        $this->modifiedDbProperties = array_keys(static::$dbProperties);
493 1
    }
494
495
    /**
496
     * Magic method used to automate getters & setters for row data.
497
     *
498
     * @param string $name
499
     * @param array  $arguments
500
     * @return mixed
501
     */
502 23
    public function __call($name, array $arguments = [])
503
    {
504 23
        $propertyName = lcfirst(substr($name, 3));
505
506 23
        if (strpos($name, 'get') === 0 && isset(static::$dbProperties[$propertyName])) {
507 7
            return $this->getDbValue($propertyName);
508 19
        } elseif (strpos($name, 'set') === 0 && isset(static::$dbProperties[$propertyName])) {
509 18
            $argumentCount = count($arguments);
510 18
            if ($argumentCount >= 1 && $argumentCount <= 3) {
511 17
                return $this->setDbValue($propertyName, ...$arguments);
512
            } else {
513 1
                throw new \BadMethodCallException("Invalid argument count[{$argumentCount}] for {$name}()");
514
            }
515
        } else {
516 1
            throw new \BadMethodCallException("No method named {$name}()");
517
        }
518
    }
519
520
    /**
521
     * Set database fields' data.
522
     *
523
     * @param array $data
524
     */
525 3
    public function setDbData(array $data)
526
    {
527 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...
528 3
            if (array_key_exists($propertyName, $data)) {
529 3
                $this->setDbValue($propertyName, $data[$propertyName], true);
530
            }
531
        }
532 3
    }
533
534
    /**
535
     * Set db data from raw database row data with field names in database format.
536
     *
537
     * @param array $rowData
538
     */
539 7
    public function setDbDataFromRow(array $rowData)
540
    {
541
        // If there are less row data than properties, use rows as starting point (optimization)
542 7
        if (count($rowData) < count(static::$dbProperties)) {
543 6
            foreach ($rowData as $dbFieldName => $value) {
544 6
                $propertyName = static::getDbPropertyName($dbFieldName);
545 6
                if (isset(static::$dbProperties[$propertyName])) {
546 6
                    $this->setDbValue($propertyName, $value, false);
547
                }
548
            }
549
        // If there are more row data than properties, use properties as starting point
550
        } else {
551 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...
552 2
                $fieldName = static::getDbFieldName($propertyName);
553 2
                if (array_key_exists($fieldName, $rowData)) {
554 2
                    $this->setDbValue($propertyName, $rowData[$fieldName], false);
555
                }
556
            }
557
        }
558
559 7
        $this->updatePrimaryDbValueFromDbData();
560 7
    }
561
562
    /**
563
     * @return mixed
564
     */
565
    protected function getPrimaryDbValueFromRow(array $rowData)
566
    {
567
        if (is_array(static::$primaryDbPropertyKey)) {
568
            $primaryValues = [];
569
            foreach (static::$primaryDbPropertyKey as $keyPart) {
570
                $fieldName = static::getDbFieldName($keyPart);
571
                $primaryValues[] = $rowData[$fieldName] ?? null;
572
            }
573
574
            return $primaryValues;
575
        }
576
577
        $fieldName = static::getDbFieldName(static::$primaryDbPropertyKey);
578
579
        return $rowData[$fieldName] ?? null;
580
    }
581
582
    /**
583
     * @return array
584
     */
585 11
    public function getDbData()
586
    {
587 11
        return $this->dbData;
588
    }
589
590
    /**
591
     * @return array
592
     */
593 1
    public function getDbRowData()
594
    {
595 1
        $rowData = [];
596 1
        foreach ($this->getDbData() as $propertyName => $value) {
597 1
            $dbFieldName = static::getDbFieldName($propertyName);
598 1
            $rowData[$dbFieldName] = $value;
599
        }
600
601 1
        return $rowData;
602
    }
603
604
    /**
605
     * @return array
606
     */
607 2
    public function getDbDataWithoutPrimary()
608
    {
609 2
        $dbDataWithoutPrimary = $this->dbData;
610
611 2
        if (is_array(static::$primaryDbPropertyKey)) {
612 1
            foreach (static::$primaryDbPropertyKey as $keyPart) {
613 1
                unset($dbDataWithoutPrimary[$keyPart]);
614
            }
615
        } else {
616 1
            unset($dbDataWithoutPrimary[static::$primaryDbPropertyKey]);
617
        }
618
619 2
        return $dbDataWithoutPrimary;
620
    }
621
622
    /**
623
     * @param bool $deleteFromDbOnSave
624
     */
625 3
    public function setDeleteFromDbOnSave($deleteFromDbOnSave = true)
626
    {
627 3
        $this->deleteFromDbOnSave = $deleteFromDbOnSave;
628 3
    }
629
630
    /**
631
     * @return bool
632
     */
633 11
    public function shouldBeDeletedFromDbOnSave()
634
    {
635 11
        return $this->deleteFromDbOnSave;
636
    }
637
638
    /**
639
     * @return bool
640
     */
641 1
    public function isDeleted()
642
    {
643 1
        return $this->deleted;
644
    }
645
646
    /**
647
     * @param bool $deleted
648
     */
649 3
    public function setDeleted($deleted = true)
650
    {
651 3
        $this->deleted = $deleted;
652 3
    }
653
654
    /**
655
     * @param bool $forceDbInsertOnSave
656
     */
657 5
    public function setForceDbInsertOnSave($forceDbInsertOnSave)
658
    {
659 5
        $this->forceDbInsertOnSave = $forceDbInsertOnSave;
660 5
    }
661
662
    /**
663
     * @return bool
664
     */
665 5
    public function shouldForceDbInsertOnSave()
666
    {
667 5
        return $this->forceDbInsertOnSave;
668
    }
669
670
    /**
671
     * @return array
672
     */
673 1
    public static function getDbProperties()
674
    {
675 1
        return static::$dbProperties;
676
    }
677
678
    /**
679
     * @param string $propertyName
680
     * @return int|null
681
     */
682 6
    public static function getDbPropertyMaxLength($propertyName)
683
    {
684 6
        return isset(static::$dbProperties[$propertyName]['maxLength'])
685 6
            ? static::$dbProperties[$propertyName]['maxLength']
686 6
            : null;
687
    }
688
689
    /**
690
     * @param string $propertyName
691
     * @return bool
692
     */
693 3
    public static function getDbPropertyRequired($propertyName)
694
    {
695 3
        return isset(static::$dbProperties[$propertyName]['required'])
696 3
            ? static::$dbProperties[$propertyName]['required']
697 3
            : false;
698
    }
699
700
    /**
701
     * @param string $propertyName
702
     * @return bool
703
     */
704 6
    public static function getDbPropertyNonEmpty($propertyName)
705
    {
706 6
        return isset(static::$dbProperties[$propertyName]['nonEmpty'])
707 2
            ? static::$dbProperties[$propertyName]['nonEmpty']
708 6
            : false;
709
    }
710
711
    /**
712
     * @return string|array
713
     */
714 14
    public static function getPrimaryDbPropertyKey()
715
    {
716 14
        return static::$primaryDbPropertyKey;
717
    }
718
719
    /**
720
     * @return string|array
721
     */
722 10
    public static function getPrimaryDbFieldKey()
723
    {
724 10
        $primaryDbPropertyKey = static::getPrimaryDbPropertyKey();
725
726 10
        if (is_array($primaryDbPropertyKey)) {
727 3
            $primaryDbFieldKey = [];
728 3
            foreach ($primaryDbPropertyKey as $propertyName) {
729 3
                $primaryDbFieldKey[] = static::getDbFieldName($propertyName);
730
            }
731
732 3
            return $primaryDbFieldKey;
733
        } else {
734 7
            return static::getDbFieldName($primaryDbPropertyKey);
735
        }
736
    }
737
738
    /**
739
     * Return array with db property names.
740
     *
741
     * @param array $exclude
742
     * @return array
743
     */
744 1
    public static function getDbPropertyNames(array $exclude = [])
745
    {
746 1
        $dbPropertyNames = array_keys(static::$dbProperties);
747
748 1
        return $exclude ? array_diff($dbPropertyNames, $exclude) : $dbPropertyNames;
749
    }
750
751
    /**
752
     * Return array with raw db field names.
753
     *
754
     * @param array $exclude
755
     * @return array
756
     */
757 3
    public static function getDbFieldNames(array $exclude = [])
758
    {
759 3
        $fieldNames = [];
760 3
        foreach (array_keys(static::$dbProperties) as $propertyName) {
761 3
            $fieldNames[] = static::getDbFieldName($propertyName);
762
        }
763
764 3
        return $exclude ? array_diff($fieldNames, $exclude) : $fieldNames;
765
    }
766
767
768
    /**
769
     * Get raw database field names prefixed (id, name becomes t.id, t.name etc.).
770
     *
771
     * @param string $dbTableAlias
772
     * @param array  $exclude
773
     * @return array
774
     */
775 1
    public static function getPrefixedDbFieldNames($dbTableAlias, array $exclude = [])
776
    {
777 1
        return Arr::valuesWithPrefix(static::getDbFieldNames($exclude), $dbTableAlias . '.');
778
    }
779
780
    /**
781
     * Get database columns transformed from e.g. "productId, date" to "p.product_id AS p_product_id, p.date AS p_date".
782
     *
783
     * @param string $dbTableAlias
784
     * @param array  $exclude
785
     * @return array
786
     */
787 1
    public static function getAliasedDbFieldNames($dbTableAlias, array $exclude = [])
788
    {
789 1
        $newArray = [];
790 1
        foreach (static::getDbFieldNames($exclude) as $dbFieldName) {
791 1
            $fromCol = $dbTableAlias . '.' . $dbFieldName;
792 1
            $toCol = $dbTableAlias . '_' . $dbFieldName;
793 1
            $newArray[] = $fromCol . ' AS ' . $toCol;
794
        }
795
796 1
        return $newArray;
797
    }
798
799
    /**
800
     * Filters a full db item array by it's table alias and the strips the table alias.
801
     *
802
     * @param array  $rowData
803
     * @param string $dbTableAlias
804
     * @param bool   $skipStrip For cases when you want to filter only (no stripping)
805
     * @return array
806
     */
807 1
    public static function filterStripDbRowData(array $rowData, $dbTableAlias, $skipStrip = false)
808
    {
809 1
        $columnPrefix = $dbTableAlias . '_';
810
811 1
        $filteredAndStrippedRowData = [];
812 1
        foreach ($rowData as $key => $val) {
813 1
            if (strpos($key, $columnPrefix) === 0) {
814 1
                $strippedKey = $skipStrip ? $key : Str::stripLeft($key, $columnPrefix);
815 1
                $filteredAndStrippedRowData[$strippedKey] = $val;
816
            }
817
        }
818
819 1
        return $filteredAndStrippedRowData;
820
    }
821
822
    /**
823
     * @return string
824
     */
825 8
    public static function getDbTableName()
826
    {
827 8
        return static::$dbTableName;
828
    }
829
830
    /**
831
     * Method to handle the serialization of this object.
832
     *
833
     * Implementation of Serializable interface. If descendant private properties
834
     * should be serialized, they need to be visible to this parent (i.e. not private).
835
     *
836
     * @return string
837
     */
838 2
    public function serialize()
839
    {
840 2
        return serialize(get_object_vars($this));
841
    }
842
843
    /**
844
     * Method to handle the unserialization of this object.
845
     *
846
     * Implementation of Serializable interface. If descendant private properties
847
     * should be unserialized, they need to be visible to this parent (i.e. not private).
848
     *
849
     * @param string $serializedObject
850
     */
851 1
    public function unserialize($serializedObject)
852
    {
853 1
        $objectVars = unserialize($serializedObject);
854
855 1
        foreach ($objectVars as $key => $value) {
856 1
            $this->{$key} = $value;
857
        }
858 1
    }
859
860
    /**
861
     * Merges other object's modified database data into this object.
862
     *
863
     * @param AbstractDbEntity $otherEntity
864
     */
865 1
    public function mergeWith(AbstractDbEntity $otherEntity)
866
    {
867 1
        $dataToMerge = $otherEntity->getModifiedDbData();
868 1
        $this->setDbData($dataToMerge);
869 1
    }
870
}
871