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
Push — master ( cad5d4...8cd4da )
by Felix
14s queued 10s
created

AbstractDbEntity   F

Complexity

Total Complexity 132

Size/Duplication

Total Lines 873
Duplicated Lines 4.24 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 96.39%

Importance

Changes 0
Metric Value
wmc 132
lcom 1
cbo 3
dl 37
loc 873
ccs 267
cts 277
cp 0.9639
rs 1.727
c 0
b 0
f 0

55 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 2
B checkStaticProperties() 0 17 9
A setPrimaryDbValueOrRowData() 0 10 3
A getDefaultDbData() 0 12 3
A getDefaultDbPropertyValue() 0 12 2
A getPrimaryDbValue() 0 4 1
A setPrimaryDbValue() 0 7 1
A setDbDataPrimaryValue() 0 12 3
A updatePrimaryDbValueFromDbData() 0 8 2
A getDbDataPrimaryValue() 13 13 3
A getDbDataPrimaryDefaultValue() 13 13 3
A isNewDbEntity() 0 11 2
A shouldInsertOnDbSave() 0 5 3
A setDbValue() 0 12 5
B getValueWithPropertyType() 0 24 9
A getPrimaryDbValueWithPropertyType() 0 27 5
A createDateTimeDbValue() 0 11 4
A getDbValue() 0 4 1
A getDbFieldName() 0 8 2
A getDbPropertyName() 0 8 2
A hasModifiedDbProperties() 0 4 1
A isDbPropertyModified() 0 4 1
A getModifiedDbData() 0 4 1
A clearModifiedDbProperties() 0 4 1
A setAllDbPropertiesAsModified() 0 4 1
B __call() 0 17 7
A setDbData() 5 8 3
B setDbDataFromRow() 6 22 6
A getPrimaryDbValueFromRow() 0 16 3
A getDbData() 0 4 1
A getDbRowData() 0 10 2
A getDbDataWithoutPrimary() 0 14 3
A setDeleteFromDbOnSave() 0 4 1
A shouldBeDeletedFromDbOnSave() 0 4 1
A isDeleted() 0 4 1
A setDeleted() 0 4 1
A setForceDbInsertOnSave() 0 4 1
A shouldForceDbInsertOnSave() 0 4 1
A getDbProperties() 0 4 1
A getDbPropertyMaxLength() 0 6 2
A getDbPropertyRequired() 0 6 2
A getDbPropertyNonEmpty() 0 6 2
A getPrimaryDbPropertyKey() 0 4 1
A getPrimaryDbFieldKey() 0 15 3
A getDbPropertyNames() 0 6 2
A getDbFieldNames() 0 9 3
A getPrefixedDbFieldNames() 0 4 1
A getAliasedDbFieldNames() 0 11 2
A filterStripDbRowData() 0 14 4
A getDbTableName() 0 4 1
A serialize() 0 4 1
A unserialize() 0 8 2
A mergeWith() 0 5 1
A getModifiedDbProperties() 0 4 1
A clearModifiedDbProperty() 0 6 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractDbEntity often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractDbEntity, and based on these observations, apply Extract Interface, too.

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 44
        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 43
        $nullIsAllowed = (array_key_exists('default', static::$dbProperties[$property])
354 43
            && static::$dbProperties[$property]['default'] === null);
355 43
        if (!($value === null && $nullIsAllowed)) {
356 42
            $type = static::$dbProperties[$property]['type'];
357
            // Set null when empty and default is null
358 42
            if ($value === '' && $nullIsAllowed) {
359 1
                 $value = null;
360 42
            } elseif ($type === 'dateTime') {
361 1
                if (!($value instanceof \DateTimeInterface)) {
362 1
                    $value = $this->createDateTimeDbValue($value);
363
                }
364
            } else {
365 41
                settype($value, $type);
366
            }
367
        }
368
369 43
        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 19
    protected function getDbValue($property)
428
    {
429 19
        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 24
    public static function getDbFieldName($propertyName)
440
    {
441 24
        if (!isset(self::$cachedDbFieldNames[$propertyName])) {
442 6
            self::$cachedDbFieldNames[$propertyName] = Str::camelToSeparator($propertyName);
443
        }
444
445 24
        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 9
    public static function getDbPropertyName($dbFieldName)
455
    {
456 9
        if (!isset(self::$cachedDbPropertyNames[$dbFieldName])) {
457 3
            self::$cachedDbPropertyNames[$dbFieldName] = Str::separatorToCamel($dbFieldName);
458
        }
459
460 9
        return self::$cachedDbPropertyNames[$dbFieldName];
461
    }
462
463
    /**
464
     * @return bool
465
     */
466 6
    public function hasModifiedDbProperties()
467
    {
468 6
        return !empty($this->modifiedDbProperties);
469
    }
470
471
    /**
472
     * @param string $property
473
     * @return bool
474
     */
475 19
    public function isDbPropertyModified($property)
476
    {
477 19
        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
     * @return array
490
     */
491 1
    public function getModifiedDbProperties()
492
    {
493 1
        return $this->modifiedDbProperties;
494
    }
495
496
    /**
497
     * @param string $property
498
     */
499 1
    public function clearModifiedDbProperty($property)
500
    {
501 1
        if (($key = array_search($property, $this->modifiedDbProperties)) !== false) {
502 1
            unset($this->modifiedDbProperties[$key]);
503
        }
504 1
    }
505
506 4
    public function clearModifiedDbProperties()
507
    {
508 4
        $this->modifiedDbProperties = [];
509 4
    }
510
511 1
    public function setAllDbPropertiesAsModified()
512
    {
513 1
        $this->modifiedDbProperties = array_keys(static::$dbProperties);
514 1
    }
515
516
    /**
517
     * Magic method used to automate getters & setters for row data.
518
     *
519
     * @param string $name
520
     * @param array  $arguments
521
     * @return mixed
522
     */
523 24
    public function __call($name, array $arguments = [])
524
    {
525 24
        $propertyName = lcfirst(substr($name, 3));
526
527 24
        if (strpos($name, 'get') === 0 && isset(static::$dbProperties[$propertyName])) {
528 7
            return $this->getDbValue($propertyName);
529 20
        } elseif (strpos($name, 'set') === 0 && isset(static::$dbProperties[$propertyName])) {
530 19
            $argumentCount = count($arguments);
531 19
            if ($argumentCount >= 1 && $argumentCount <= 3) {
532 18
                return $this->setDbValue($propertyName, ...$arguments);
533
            } else {
534 1
                throw new \BadMethodCallException("Invalid argument count[{$argumentCount}] for {$name}()");
535
            }
536
        } else {
537 1
            throw new \BadMethodCallException("No method named {$name}()");
538
        }
539
    }
540
541
    /**
542
     * Set database fields' data.
543
     *
544
     * @param array $data
545
     */
546 3
    public function setDbData(array $data)
547
    {
548 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...
549 3
            if (array_key_exists($propertyName, $data)) {
550 3
                $this->setDbValue($propertyName, $data[$propertyName], true);
551
            }
552
        }
553 3
    }
554
555
    /**
556
     * Set db data from raw database row data with field names in database format.
557
     *
558
     * @param array $rowData
559
     */
560 9
    public function setDbDataFromRow(array $rowData)
561
    {
562
        // If there are less row data than properties, use rows as starting point (optimization)
563 9
        if (count($rowData) < count(static::$dbProperties)) {
564 8
            foreach ($rowData as $dbFieldName => $value) {
565 8
                $propertyName = static::getDbPropertyName($dbFieldName);
566 8
                if (isset(static::$dbProperties[$propertyName])) {
567 8
                    $this->setDbValue($propertyName, $value, false);
568
                }
569
            }
570
        // If there are more row data than properties, use properties as starting point
571
        } else {
572 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...
573 2
                $fieldName = static::getDbFieldName($propertyName);
574 2
                if (array_key_exists($fieldName, $rowData)) {
575 2
                    $this->setDbValue($propertyName, $rowData[$fieldName], false);
576
                }
577
            }
578
        }
579
580 9
        $this->updatePrimaryDbValueFromDbData();
581 9
    }
582
583
    /**
584
     * @return mixed
585
     */
586
    protected function getPrimaryDbValueFromRow(array $rowData)
587
    {
588
        if (is_array(static::$primaryDbPropertyKey)) {
589
            $primaryValues = [];
590
            foreach (static::$primaryDbPropertyKey as $keyPart) {
591
                $fieldName = static::getDbFieldName($keyPart);
592
                $primaryValues[] = $rowData[$fieldName] ?? null;
593
            }
594
595
            return $primaryValues;
596
        }
597
598
        $fieldName = static::getDbFieldName(static::$primaryDbPropertyKey);
599
600
        return $rowData[$fieldName] ?? null;
601
    }
602
603
    /**
604
     * @return array
605
     */
606 11
    public function getDbData()
607
    {
608 11
        return $this->dbData;
609
    }
610
611
    /**
612
     * @return array
613
     */
614 1
    public function getDbRowData()
615
    {
616 1
        $rowData = [];
617 1
        foreach ($this->getDbData() as $propertyName => $value) {
618 1
            $dbFieldName = static::getDbFieldName($propertyName);
619 1
            $rowData[$dbFieldName] = $value;
620
        }
621
622 1
        return $rowData;
623
    }
624
625
    /**
626
     * @return array
627
     */
628 2
    public function getDbDataWithoutPrimary()
629
    {
630 2
        $dbDataWithoutPrimary = $this->dbData;
631
632 2
        if (is_array(static::$primaryDbPropertyKey)) {
633 1
            foreach (static::$primaryDbPropertyKey as $keyPart) {
634 1
                unset($dbDataWithoutPrimary[$keyPart]);
635
            }
636
        } else {
637 1
            unset($dbDataWithoutPrimary[static::$primaryDbPropertyKey]);
638
        }
639
640 2
        return $dbDataWithoutPrimary;
641
    }
642
643
    /**
644
     * @param bool $deleteFromDbOnSave
645
     */
646 3
    public function setDeleteFromDbOnSave($deleteFromDbOnSave = true)
647
    {
648 3
        $this->deleteFromDbOnSave = $deleteFromDbOnSave;
649 3
    }
650
651
    /**
652
     * @return bool
653
     */
654 11
    public function shouldBeDeletedFromDbOnSave()
655
    {
656 11
        return $this->deleteFromDbOnSave;
657
    }
658
659
    /**
660
     * @return bool
661
     */
662 1
    public function isDeleted()
663
    {
664 1
        return $this->deleted;
665
    }
666
667
    /**
668
     * @param bool $deleted
669
     */
670 3
    public function setDeleted($deleted = true)
671
    {
672 3
        $this->deleted = $deleted;
673 3
    }
674
675
    /**
676
     * @param bool $forceDbInsertOnSave
677
     */
678 5
    public function setForceDbInsertOnSave($forceDbInsertOnSave)
679
    {
680 5
        $this->forceDbInsertOnSave = $forceDbInsertOnSave;
681 5
    }
682
683
    /**
684
     * @return bool
685
     */
686 5
    public function shouldForceDbInsertOnSave()
687
    {
688 5
        return $this->forceDbInsertOnSave;
689
    }
690
691
    /**
692
     * @return array
693
     */
694 1
    public static function getDbProperties()
695
    {
696 1
        return static::$dbProperties;
697
    }
698
699
    /**
700
     * @param string $propertyName
701
     * @return int|null
702
     */
703 6
    public static function getDbPropertyMaxLength($propertyName)
704
    {
705 6
        return isset(static::$dbProperties[$propertyName]['maxLength'])
706 6
            ? static::$dbProperties[$propertyName]['maxLength']
707 6
            : null;
708
    }
709
710
    /**
711
     * @param string $propertyName
712
     * @return bool
713
     */
714 3
    public static function getDbPropertyRequired($propertyName)
715
    {
716 3
        return isset(static::$dbProperties[$propertyName]['required'])
717 3
            ? static::$dbProperties[$propertyName]['required']
718 3
            : false;
719
    }
720
721
    /**
722
     * @param string $propertyName
723
     * @return bool
724
     */
725 6
    public static function getDbPropertyNonEmpty($propertyName)
726
    {
727 6
        return isset(static::$dbProperties[$propertyName]['nonEmpty'])
728 2
            ? static::$dbProperties[$propertyName]['nonEmpty']
729 6
            : false;
730
    }
731
732
    /**
733
     * @return string|array
734
     */
735 16
    public static function getPrimaryDbPropertyKey()
736
    {
737 16
        return static::$primaryDbPropertyKey;
738
    }
739
740
    /**
741
     * @return string|array
742
     */
743 12
    public static function getPrimaryDbFieldKey()
744
    {
745 12
        $primaryDbPropertyKey = static::getPrimaryDbPropertyKey();
746
747 12
        if (is_array($primaryDbPropertyKey)) {
748 3
            $primaryDbFieldKey = [];
749 3
            foreach ($primaryDbPropertyKey as $propertyName) {
750 3
                $primaryDbFieldKey[] = static::getDbFieldName($propertyName);
751
            }
752
753 3
            return $primaryDbFieldKey;
754
        } else {
755 9
            return static::getDbFieldName($primaryDbPropertyKey);
756
        }
757
    }
758
759
    /**
760
     * Return array with db property names.
761
     *
762
     * @param array $exclude
763
     * @return array
764
     */
765 1
    public static function getDbPropertyNames(array $exclude = [])
766
    {
767 1
        $dbPropertyNames = array_keys(static::$dbProperties);
768
769 1
        return $exclude ? array_diff($dbPropertyNames, $exclude) : $dbPropertyNames;
770
    }
771
772
    /**
773
     * Return array with raw db field names.
774
     *
775
     * @param array $exclude
776
     * @return array
777
     */
778 3
    public static function getDbFieldNames(array $exclude = [])
779
    {
780 3
        $fieldNames = [];
781 3
        foreach (array_keys(static::$dbProperties) as $propertyName) {
782 3
            $fieldNames[] = static::getDbFieldName($propertyName);
783
        }
784
785 3
        return $exclude ? array_diff($fieldNames, $exclude) : $fieldNames;
786
    }
787
788
789
    /**
790
     * Get raw database field names prefixed (id, name becomes t.id, t.name etc.).
791
     *
792
     * @param string $dbTableAlias
793
     * @param array  $exclude
794
     * @return array
795
     */
796 1
    public static function getPrefixedDbFieldNames($dbTableAlias, array $exclude = [])
797
    {
798 1
        return Arr::valuesWithPrefix(static::getDbFieldNames($exclude), $dbTableAlias . '.');
799
    }
800
801
    /**
802
     * Get database columns transformed from e.g. "productId, date" to "p.product_id AS p_product_id, p.date AS p_date".
803
     *
804
     * @param string $dbTableAlias
805
     * @param array  $exclude
806
     * @return array
807
     */
808 1
    public static function getAliasedDbFieldNames($dbTableAlias, array $exclude = [])
809
    {
810 1
        $newArray = [];
811 1
        foreach (static::getDbFieldNames($exclude) as $dbFieldName) {
812 1
            $fromCol = $dbTableAlias . '.' . $dbFieldName;
813 1
            $toCol = $dbTableAlias . '_' . $dbFieldName;
814 1
            $newArray[] = $fromCol . ' AS ' . $toCol;
815
        }
816
817 1
        return $newArray;
818
    }
819
820
    /**
821
     * Filters a full db item array by it's table alias and the strips the table alias.
822
     *
823
     * @param array  $rowData
824
     * @param string $dbTableAlias
825
     * @param bool   $skipStrip For cases when you want to filter only (no stripping)
826
     * @return array
827
     */
828 1
    public static function filterStripDbRowData(array $rowData, $dbTableAlias, $skipStrip = false)
829
    {
830 1
        $columnPrefix = $dbTableAlias . '_';
831
832 1
        $filteredAndStrippedRowData = [];
833 1
        foreach ($rowData as $key => $val) {
834 1
            if (strpos($key, $columnPrefix) === 0) {
835 1
                $strippedKey = $skipStrip ? $key : Str::stripLeft($key, $columnPrefix);
836 1
                $filteredAndStrippedRowData[$strippedKey] = $val;
837
            }
838
        }
839
840 1
        return $filteredAndStrippedRowData;
841
    }
842
843
    /**
844
     * @return string
845
     */
846 8
    public static function getDbTableName()
847
    {
848 8
        return static::$dbTableName;
849
    }
850
851
    /**
852
     * Method to handle the serialization of this object.
853
     *
854
     * Implementation of Serializable interface. If descendant private properties
855
     * should be serialized, they need to be visible to this parent (i.e. not private).
856
     *
857
     * @return string
858
     */
859 2
    public function serialize()
860
    {
861 2
        return serialize(get_object_vars($this));
862
    }
863
864
    /**
865
     * Method to handle the unserialization of this object.
866
     *
867
     * Implementation of Serializable interface. If descendant private properties
868
     * should be unserialized, they need to be visible to this parent (i.e. not private).
869
     *
870
     * @param string $serializedObject
871
     */
872 1
    public function unserialize($serializedObject)
873
    {
874 1
        $objectVars = unserialize($serializedObject);
875
876 1
        foreach ($objectVars as $key => $value) {
877 1
            $this->{$key} = $value;
878
        }
879 1
    }
880
881
    /**
882
     * Merges other object's modified database data into this object.
883
     *
884
     * @param AbstractDbEntity $otherEntity
885
     */
886 1
    public function mergeWith(AbstractDbEntity $otherEntity)
887
    {
888 1
        $dataToMerge = $otherEntity->getModifiedDbData();
889 1
        $this->setDbData($dataToMerge);
890 1
    }
891
}
892