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.

AbstractDbEntity::getDbRowData()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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