Passed
Branch feature-dbal (53df75)
by Thomas
02:50
created

Entity::describe()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace ORM;
4
5
use ORM\Dbal\Column;
6
use ORM\Exceptions\IncompletePrimaryKey;
7
use ORM\Exceptions\InvalidConfiguration;
8
use ORM\Exceptions\InvalidRelation;
9
use ORM\Exceptions\InvalidName;
10
use ORM\Exceptions\NoEntityManager;
11
use ORM\Exceptions\UndefinedRelation;
12
13
/**
14
 * Definition of an entity
15
 *
16
 * The instance of an entity represents a row of the table and the statics variables and methods describe the database
17
 * table.
18
 *
19
 * This is the main part where your configuration efforts go. The following properties and methods are well documented
20
 * in the manual under [https://tflori.github.io/orm/entityDefinition.html](Entity Definition).
21
 *
22
 * @package ORM
23
 * @link https://tflori.github.io/orm/entityDefinition.html Entity Definition
24
 * @author Thomas Flori <[email protected]>
25
 */
26
abstract class Entity implements \Serializable
27
{
28
    const OPT_RELATION_CLASS       = 'class';
29
    const OPT_RELATION_CARDINALITY = 'cardinality';
30
    const OPT_RELATION_REFERENCE   = 'reference';
31
    const OPT_RELATION_OPPONENT    = 'opponent';
32
    const OPT_RELATION_TABLE       = 'table';
33
34
    /** The template to use to calculate the table name.
35
     * @var string */
36
    protected static $tableNameTemplate = '%short%';
37
38
    /** The naming scheme to use for table names.
39
     * @var string */
40
    protected static $namingSchemeTable = 'snake_lower';
41
42
    /** The naming scheme to use for column names.
43
     * @var string */
44
    protected static $namingSchemeColumn = 'snake_lower';
45
46
    /** The naming scheme to use for method names.
47
     * @var string */
48
    protected static $namingSchemeMethods = 'camelCase';
49
50
    /** Whether or not the naming got used
51
     * @var bool */
52
    protected static $namingUsed = false;
53
54
    /** Fixed table name (ignore other settings)
55
     * @var string */
56
    protected static $tableName;
57
58
    /** The variable(s) used for primary key.
59
     * @var string[]|string */
60
    protected static $primaryKey = ['id'];
61
62
    /** Fixed column names (ignore other settings)
63
     * @var string[] */
64
    protected static $columnAliases = [];
65
66
    /** A prefix for column names.
67
     * @var string */
68
    protected static $columnPrefix;
69
70
    /** Whether or not the primary key is auto incremented.
71
     * @var bool */
72
    protected static $autoIncrement = true;
73
74
    /** Relation definitions
75
     * @var array */
76
    protected static $relations = [];
77
78
    /** The current data of a row.
79
     * @var mixed[] */
80
    protected $data = [];
81
82
    /** The original data of the row.
83
     * @var mixed[] */
84
    protected $originalData = [];
85
86
    /** The entity manager from which this entity got created
87
     * @var EntityManager*/
88
    protected $entityManager;
89
90
    /** Related objects for getRelated
91
     * @var array */
92
    protected $relatedObjects = [];
93
94
    /** Calculated table names.
95
     * @internal
96
     * @var string[] */
97
    protected static $calculatedTableNames = [];
98
99
    /** Calculated column names.
100
     * @internal
101
     * @var string[][] */
102
    protected static $calculatedColumnNames = [];
103
104
    /** The reflections of the classes.
105
     * @internal
106
     * @var \ReflectionClass[] */
107
    protected static $reflections = [];
108
109
    /** The fetched column descriptions for the table.
110
     * @internal
111
     * @var Column[][] */
112
    protected static $descriptions;
113
114
    /**
115
     * Get the table name
116
     *
117
     * The table name is constructed by $tableNameTemplate and $namingSchemeTable. It can be overwritten by
118
     * $tableName.
119
     *
120
     * @return string
121
     * @throws InvalidName|InvalidConfiguration
122
     */
123 137
    public static function getTableName()
124
    {
125 137
        if (static::$tableName) {
126 11
            return static::$tableName;
127
        }
128
129 126
        if (!isset(self::$calculatedTableNames[static::class])) {
130 126
            static::$namingUsed = true;
131 126
            $reflection = self::getReflection();
132
133
            $tableName = preg_replace_callback('/%([a-z]+)(\[(-?\d+)(\*)?\])?%/', function ($match) use ($reflection) {
134 126
                switch ($match[1]) {
135 126
                    case 'short':
136 112
                        $words = [$reflection->getShortName()];
137 112
                        break;
138
139 14
                    case 'namespace':
140 4
                        $words = explode('\\', $reflection->getNamespaceName());
141 4
                        break;
142
143 10
                    case 'name':
144 9
                        $words = preg_split('/[\\\\_]+/', $reflection->getName());
145 9
                        break;
146
147
                    default:
148 1
                        throw new InvalidConfiguration(
149 1
                            'Template invalid: Placeholder %' . $match[1] . '% is not allowed'
150
                        );
151
                }
152
153 125
                if (!isset($match[2])) {
154 114
                    return implode('_', $words);
155
                }
156 11
                $from = $match[3][0] === '-' ? count($words) - substr($match[3], 1) : $match[3];
157 11
                if (isset($words[$from])) {
158 9
                    return !isset($match[4]) ?
159 9
                        $words[$from] : implode('_', array_slice($words, $from));
160
                }
161 2
                return '';
162 126
            }, static::getTableNameTemplate());
163
164 125
            if (empty($tableName)) {
165 2
                throw new InvalidName('Table name can not be empty');
166
            }
167 123
            self::$calculatedTableNames[static::class] =
168 123
                self::forceNamingScheme($tableName, static::getNamingSchemeTable());
169
        }
170
171 122
        return self::$calculatedTableNames[static::class];
172
    }
173
174
    /**
175
     * Get the column name of $name
176
     *
177
     * The column names can not be specified by template. Instead they are constructed by $columnPrefix and enforced
178
     * to $namingSchemeColumn.
179
     *
180
     * **ATTENTION**: If your overwrite this method remember that getColumnName(getColumnName($name)) have to exactly
181
     * the same as getColumnName($name).
182
     *
183
     * @param string $var
184
     * @return string
185
     * @throws InvalidConfiguration
186
     */
187 136
    public static function getColumnName($var)
188
    {
189 136
        if (isset(static::$columnAliases[$var])) {
190 7
            return static::$columnAliases[$var];
191
        }
192
193 133
        if (!isset(self::$calculatedColumnNames[static::class][$var])) {
194 133
            static::$namingUsed = true;
195 133
            $colName = $var;
196
197 133
            if (static::$columnPrefix &&
198 23
                strpos(
199
                    $colName,
200 23
                    self::forceNamingScheme(static::$columnPrefix, static::getNamingSchemeColumn())
201 133
                ) !== 0) {
202 22
                $colName = static::$columnPrefix . $colName;
203
            }
204
205 133
            self::$calculatedColumnNames[static::class][$var] =
206 133
                self::forceNamingScheme($colName, static::getNamingSchemeColumn());
207
        }
208
209 133
        return self::$calculatedColumnNames[static::class][$var];
210
    }
211
212
    /**
213
     * Get the definition for $relation
214
     *
215
     * It normalize the short definition form and create a Relation object from it.
216
     *
217
     * @param string $relation
218
     * @return Relation
219
     * @throws InvalidConfiguration
220
     * @throws UndefinedRelation
221
     */
222 84
    public static function getRelation($relation)
223
    {
224 84
        if (!isset(static::$relations[$relation])) {
225 3
            throw new UndefinedRelation('Relation ' . $relation . ' is not defined');
226
        }
227
228 83
        $relDef = &static::$relations[$relation];
229
230 83
        if (!$relDef instanceof Relation) {
231 15
            $relDef = Relation::createRelation($relation, $relDef);
232
        }
233
234 82
        return $relDef;
235
    }
236
237
    /**
238
     * @return string
239
     */
240 127
    public static function getTableNameTemplate()
241
    {
242 127
        return static::$tableNameTemplate;
243
    }
244
245
    /**
246
     * @param string $tableNameTemplate
247
     * @throws InvalidConfiguration
248
     */
249 52
    public static function setTableNameTemplate($tableNameTemplate)
250
    {
251 52
        if (static::$namingUsed) {
252 1
            throw new InvalidConfiguration('Template can not be changed afterwards');
253
        }
254
255 51
        static::$tableNameTemplate = $tableNameTemplate;
256 51
    }
257
258
    /**
259
     * @return string
260
     */
261 124
    public static function getNamingSchemeTable()
262
    {
263 124
        return static::$namingSchemeTable;
264
    }
265
266
    /**
267
     * @param string $namingSchemeTable
268
     * @throws InvalidConfiguration
269
     */
270 52
    public static function setNamingSchemeTable($namingSchemeTable)
271
    {
272 52
        if (static::$namingUsed) {
273 1
            throw new InvalidConfiguration('Naming scheme can not be changed afterwards');
274
        }
275
276 51
        static::$namingSchemeTable = $namingSchemeTable;
277 51
    }
278
279
    /**
280
     * @return string
281
     */
282 134
    public static function getNamingSchemeColumn()
283
    {
284 134
        return static::$namingSchemeColumn;
285
    }
286
287
    /**
288
     * @param string $namingSchemeColumn
289
     * @throws InvalidConfiguration
290
     */
291 27
    public static function setNamingSchemeColumn($namingSchemeColumn)
292
    {
293 27
        if (static::$namingUsed) {
294 1
            throw new InvalidConfiguration('Naming scheme can not be changed afterwards');
295
        }
296
297 26
        static::$namingSchemeColumn = $namingSchemeColumn;
298 26
    }
299
300
    /**
301
     * @return string
302
     */
303 88
    public static function getNamingSchemeMethods()
304
    {
305 88
        return static::$namingSchemeMethods;
306
    }
307
308
    /**
309
     * @param string $namingSchemeMethods
310
     * @throws InvalidConfiguration
311
     */
312 3
    public static function setNamingSchemeMethods($namingSchemeMethods)
313
    {
314 3
        if (static::$namingUsed) {
315 1
            throw new InvalidConfiguration('Naming scheme can not be changed afterwards');
316
        }
317
318 3
        static::$namingSchemeMethods = $namingSchemeMethods;
319 3
    }
320
321
    /**
322
     * Get the primary key vars
323
     *
324
     * The primary key can consist of multiple columns. You should configure the vars that are translated to these
325
     * columns.
326
     *
327
     * @return array
328
     */
329 56
    public static function getPrimaryKeyVars()
330
    {
331 56
        return !is_array(static::$primaryKey) ? [static::$primaryKey] : static::$primaryKey;
332
    }
333
334
    /**
335
     * Check if the table has a auto increment column.
336
     *
337
     * @return bool
338
     */
339 14
    public static function isAutoIncremented()
340
    {
341 14
        return count(static::getPrimaryKeyVars()) > 1 ? false : static::$autoIncrement;
342
    }
343
344
    /**
345
     * Get an array of Columns for this table.
346
     *
347
     * @param EntityManager $em
348
     * @return mixed
349
     * @codeCoverageIgnore This is just a proxy
350
     */
351
    public static function describe(EntityManager $em)
352
    {
353
        return $em->describe(static::getTableName());
354
    }
355
356
    /**
357
     * Enforce $namingScheme to $name
358
     *
359
     * Supported naming schemes: snake_case, snake_lower, SNAKE_UPPER, Snake_Ucfirst, camelCase, StudlyCaps, lower
360
     * and UPPER.
361
     *
362
     * @param string $name         The name of the var / column
363
     * @param string $namingScheme The naming scheme to use
364
     * @return string
365
     * @throws InvalidConfiguration
366
     */
367 214
    protected static function forceNamingScheme($name, $namingScheme)
368
    {
369 214
        $words = explode('_', preg_replace(
370 214
            '/([a-z0-9])([A-Z])/',
371 214
            '$1_$2',
372 214
            preg_replace_callback('/([a-z0-9])?([A-Z]+)([A-Z][a-z])/', function ($d) {
373 24
                return ($d[1] ? $d[1] . '_' : '') . $d[2] . '_' . $d[3];
374 214
            }, $name)
375
        ));
376
377
        switch ($namingScheme) {
378 214
            case 'snake_case':
379 27
                $newName = implode('_', $words);
380 27
                break;
381
382 187
            case 'snake_lower':
383 154
                $newName = implode('_', array_map('strtolower', $words));
384 154
                break;
385
386 116
            case 'SNAKE_UPPER':
387 4
                $newName = implode('_', array_map('strtoupper', $words));
388 4
                break;
389
390 112
            case 'Snake_Ucfirst':
391 4
                $newName = implode('_', array_map('ucfirst', $words));
392 4
                break;
393
394 108
            case 'camelCase':
395 89
                $newName = lcfirst(implode('', array_map('ucfirst', array_map('strtolower', $words))));
396 89
                break;
397
398 19
            case 'StudlyCaps':
399 10
                $newName = implode('', array_map('ucfirst', array_map('strtolower', $words)));
400 10
                break;
401
402 9
            case 'lower':
403 4
                $newName = implode('', array_map('strtolower', $words));
404 4
                break;
405
406 5
            case 'UPPER':
407 4
                $newName = implode('', array_map('strtoupper', $words));
408 4
                break;
409
410
            default:
411 1
                throw new InvalidConfiguration('Naming scheme ' . $namingScheme . ' unknown');
412
        }
413
414 213
        return $newName;
415
    }
416
417
    /**
418
     * Get reflection of the entity
419
     *
420
     * @return \ReflectionClass
421
     */
422 126
    protected static function getReflection()
423
    {
424 126
        if (!isset(self::$reflections[static::class])) {
425 126
            self::$reflections[static::class] = new \ReflectionClass(static::class);
426
        }
427 126
        return self::$reflections[static::class];
428
    }
429
430
    /**
431
     * Constructor
432
     *
433
     * It calls ::onInit() after initializing $data and $originalData.
434
     *
435
     * @param mixed[]       $data          The current data
436
     * @param EntityManager $entityManager The EntityManager that created this entity
437
     * @param bool          $fromDatabase  Whether or not the data comes from database
438
     */
439 110
    final public function __construct(array $data = [], EntityManager $entityManager = null, $fromDatabase = false)
440
    {
441 110
        if ($fromDatabase) {
442 14
            $this->originalData = $data;
443
        }
444 110
        $this->data = array_merge($this->data, $data);
445 110
        $this->entityManager = $entityManager;
446 110
        $this->onInit(!$fromDatabase);
447 110
    }
448
449
    /**
450
     * @param EntityManager $entityManager
451
     * @return self
452
     */
453 1
    public function setEntityManager(EntityManager $entityManager)
454
    {
455 1
        $this->entityManager = $entityManager;
456 1
        return $this;
457
    }
458
459
    /**
460
     * Set $var to $value
461
     *
462
     * Tries to call custom setter before it stores the data directly. If there is a setter the setter needs to store
463
     * data that should be updated in the database to $data. Do not store data in $originalData as it will not be
464
     * written and give wrong results for dirty checking.
465
     *
466
     * The onChange event is called after something got changed.
467
     *
468
     * @param string $var   The variable to change
469
     * @param mixed  $value The value to store
470
     * @throws IncompletePrimaryKey
471
     * @throws InvalidConfiguration
472
     * @link https://tflori.github.io/orm/entities.html Working with entities
473
     */
474 19
    public function __set($var, $value)
475
    {
476 19
        $col = $this->getColumnName($var);
477
478 19
        static::$namingUsed = true;
479 19
        $setter = self::forceNamingScheme('set' . ucfirst($var), static::getNamingSchemeMethods());
480 19
        if (method_exists($this, $setter) && is_callable([$this, $setter])) {
481 4
            $oldValue = $this->__get($var);
482 4
            $md5OldData = md5(serialize($this->data));
483 4
            $this->$setter($value);
484 4
            $changed = $md5OldData !== md5(serialize($this->data));
485
        } else {
486 15
            $oldValue = $this->__get($var);
487 15
            $changed = (isset($this->data[$col]) ? $this->data[$col] : null) !== $value;
488 15
            $this->data[$col] = $value;
489
        }
490
491 19
        if ($changed) {
492 15
            $this->onChange($var, $oldValue, $this->__get($var));
493
        }
494 19
    }
495
496
    /**
497
     * Get the value from $var
498
     *
499
     * If there is a custom getter this method get called instead.
500
     *
501
     * @param string $var The variable to get
502
     * @return mixed|null
503
     * @throws IncompletePrimaryKey
504
     * @throws InvalidConfiguration
505
     * @link https://tflori.github.io/orm/entities.html Working with entities
506
     */
507 87
    public function __get($var)
508
    {
509 87
        $getter = self::forceNamingScheme('get' . ucfirst($var), static::getNamingSchemeMethods());
510 87
        if (method_exists($this, $getter) && is_callable([$this, $getter])) {
511 5
            return $this->$getter();
512
        } else {
513 82
            $col = static::getColumnName($var);
514 82
            $result = isset($this->data[$col]) ? $this->data[$col] : null;
515
516 82
            if (!$result && isset(static::$relations[$var]) && isset($this->entityManager)) {
517 1
                return $this->getRelated($var);
518
            }
519
520 81
            return $result;
521
        }
522
    }
523
524
    /**
525
     * Get related objects
526
     *
527
     * The difference between getRelated and fetch is that getRelated stores the fetched entities. To refresh set
528
     * $refresh to true.
529
     *
530
     * @param string $relation
531
     * @param bool   $refresh
532
     * @return mixed
533
     * @throws Exceptions\NoConnection
534
     * @throws Exceptions\NoEntity
535
     * @throws IncompletePrimaryKey
536
     * @throws InvalidConfiguration
537
     * @throws NoEntityManager
538
     * @throws UndefinedRelation
539
     */
540 11
    public function getRelated($relation, $refresh = false)
541
    {
542 11
        if ($refresh || !isset($this->relatedObjects[$relation])) {
543 9
            $this->relatedObjects[$relation] = $this->fetch($relation, null, true);
544
        }
545
546 11
        return $this->relatedObjects[$relation];
547
    }
548
549
    /**
550
     * Set $relation to $entity
551
     *
552
     * This method is only for the owner of a relation.
553
     *
554
     * @param string $relation
555
     * @param Entity $entity
556
     * @throws IncompletePrimaryKey
557
     * @throws InvalidRelation
558
     */
559 7
    public function setRelated($relation, Entity $entity = null)
560
    {
561 7
        $this::getRelation($relation)->setRelated($this, $entity);
562
563 4
        $this->relatedObjects[$relation] = $entity;
564 4
    }
565
566
    /**
567
     * Add relations for $relation to $entities
568
     *
569
     * This method is only for many-to-many relations.
570
     *
571
     * This method does not take care about already existing relations and will fail hard.
572
     *
573
     * @param string        $relation
574
     * @param Entity[]      $entities
575
     * @param EntityManager $entityManager
576
     * @throws NoEntityManager
577
     */
578 9
    public function addRelated($relation, array $entities, EntityManager $entityManager = null)
579
    {
580 9
        $entityManager = $entityManager ?: $this->entityManager;
581
582 9
        if (!$entityManager) {
583 1
            throw new NoEntityManager('No entity manager given');
584
        }
585
586 8
        $this::getRelation($relation)->addRelated($this, $entities, $entityManager);
587 4
    }
588
589
    /**
590
     * Delete relations for $relation to $entities
591
     *
592
     * This method is only for many-to-many relations.
593
     *
594
     * @param string        $relation
595
     * @param Entity[]      $entities
596
     * @param EntityManager $entityManager
597
     * @throws NoEntityManager
598
     */
599 9
    public function deleteRelated($relation, $entities, EntityManager $entityManager = null)
600
    {
601 9
        $entityManager = $entityManager ?: $this->entityManager;
602
603 9
        if (!$entityManager) {
604 1
            throw new NoEntityManager('No entity manager given');
605
        }
606
607 8
        $this::getRelation($relation)->deleteRelated($this, $entities, $entityManager);
608 4
    }
609
610
    /**
611
     * Checks if entity or $var got changed
612
     *
613
     * @param string $var Check only this variable or all variables
614
     * @return bool
615
     * @throws InvalidConfiguration
616
     */
617 18
    public function isDirty($var = null)
618
    {
619 18
        if (!empty($var)) {
620 4
            $col = static::getColumnName($var);
621 4
            return (isset($this->data[$col]) ? $this->data[$col] : null) !==
622 4
                   (isset($this->originalData[$col]) ? $this->originalData[$col] : null);
623
        }
624
625 15
        ksort($this->data);
626 15
        ksort($this->originalData);
627
628 15
        return serialize($this->data) !== serialize($this->originalData);
629
    }
630
631
    /**
632
     * Resets the entity or $var to original data
633
     *
634
     * @param string $var Reset only this variable or all variables
635
     * @throws InvalidConfiguration
636
     */
637 8
    public function reset($var = null)
638
    {
639 8
        if (!empty($var)) {
640 3
            $col = static::getColumnName($var);
641 3
            if (isset($this->originalData[$col])) {
642 2
                $this->data[$col] = $this->originalData[$col];
643
            } else {
644 1
                unset($this->data[$col]);
645
            }
646 3
            return;
647
        }
648
649 5
        $this->data = $this->originalData;
650 5
    }
651
652
    /**
653
     * Save the entity to $entityManager
654
     *
655
     * @param EntityManager $entityManager
656
     * @return Entity
657
     * @throws Exceptions\NoConnection
658
     * @throws Exceptions\NoEntity
659
     * @throws Exceptions\NotScalar
660
     * @throws Exceptions\UnsupportedDriver
661
     * @throws IncompletePrimaryKey
662
     * @throws InvalidConfiguration
663
     * @throws InvalidName
664
     * @throws NoEntityManager
665
     */
666 13
    public function save(EntityManager $entityManager = null)
667
    {
668 13
        $entityManager = $entityManager ?: $this->entityManager;
669
670 13
        if (!$entityManager) {
671 1
            throw new NoEntityManager('No entity manager given');
672
        }
673
674 12
        $inserted = false;
675 12
        $updated = false;
676
677
        try {
678
            // this may throw if the primary key is auto incremented but we using this to omit duplicated code
679 12
            if (!$entityManager->sync($this)) {
680 2
                $entityManager->insert($this, false);
681 2
                $inserted = true;
682 5
            } elseif ($this->isDirty()) {
683 4
                $this->preUpdate();
684 4
                $entityManager->update($this);
685 7
                $updated = true;
686
            }
687 5
        } catch (IncompletePrimaryKey $e) {
688 5
            if (static::isAutoIncremented()) {
689 4
                $this->prePersist();
690 4
                $id = $entityManager->insert($this);
691 4
                $this->data[static::getColumnName(static::getPrimaryKeyVars()[0])] = $id;
692 4
                $inserted = true;
693
            } else {
694 1
                throw $e;
695
            }
696
        }
697
698 11
        if ($inserted || $updated) {
699 10
            $inserted && $this->postPersist();
700 10
            $updated && $this->postUpdate();
701 10
            $entityManager->sync($this, true);
702
        }
703
704 11
        return $this;
705
    }
706
707
    /**
708
     * Fetches related objects
709
     *
710
     * For relations with cardinality many it returns an EntityFetcher. Otherwise it returns the entity.
711
     *
712
     * It will throw an error for non owner when the key is incomplete.
713
     *
714
     * @param string        $relation      The relation to fetch
715
     * @param EntityManager $entityManager The EntityManager to use
716
     * @param bool          $getAll
717
     * @return Entity|Entity[]|EntityFetcher
718
     * @throws NoEntityManager
719
     */
720 19
    public function fetch($relation, EntityManager $entityManager = null, $getAll = false)
721
    {
722 19
        $entityManager = $entityManager ?: $this->entityManager;
723
724 19
        if (!$entityManager) {
725 1
            throw new NoEntityManager('No entity manager given');
726
        }
727
728 18
        $relation = $this::getRelation($relation);
729
730 18
        if ($getAll) {
731 4
            return $relation->fetchAll($this, $entityManager);
732
        } else {
733 14
            return $relation->fetch($this, $entityManager);
734
        }
735
    }
736
737
    /**
738
     * Get the primary key
739
     *
740
     * @return array
741
     * @throws IncompletePrimaryKey
742
     */
743 38
    public function getPrimaryKey()
744
    {
745 38
        $primaryKey = [];
746 38
        foreach (static::getPrimaryKeyVars() as $var) {
747 38
            $value = $this->$var;
748 38
            if ($value === null) {
749 4
                throw new IncompletePrimaryKey('Incomplete primary key - missing ' . $var);
750
            }
751 36
            $primaryKey[$var] = $value;
752
        }
753 34
        return $primaryKey;
754
    }
755
756
    /**
757
     * Get current data
758
     *
759
     * @return array
760
     * @internal
761
     */
762 20
    public function getData()
763
    {
764 20
        return $this->data;
765
    }
766
767
    /**
768
     * Set new original data
769
     *
770
     * @param array $data
771
     * @internal
772
     */
773 18
    public function setOriginalData(array $data)
774
    {
775 18
        $this->originalData = $data;
776 18
    }
777
778
    /**
779
     * Empty event handler
780
     *
781
     * Get called when something is changed with magic setter.
782
     *
783
     * @param string $var The variable that got changed.merge(node.inheritedProperties)
784
     * @param mixed  $oldValue The old value of the variable
785
     * @param mixed  $value The new value of the variable
786
     */
787 6
    public function onChange($var, $oldValue, $value)
788
    {
789 6
    }
790
791
    /**
792
     * Empty event handler
793
     *
794
     * Get called when the entity get initialized.
795
     *
796
     * @param bool $new Whether or not the entity is new or from database
797
     */
798 109
    public function onInit($new)
799
    {
800 109
    }
801
802
    /**
803
     * Empty event handler
804
     *
805
     * Get called before the entity get inserted in database.
806
     */
807 3
    public function prePersist()
808
    {
809 3
    }
810
811
    /**
812
     * Empty event handler
813
     *
814
     * Get called after the entity got inserted in database.
815
     */
816 5
    public function postPersist()
817
    {
818 5
    }
819
820
    /**
821
     * Empty event handler
822
     *
823
     * Get called before the entity get updated in database.
824
     */
825 3
    public function preUpdate()
826
    {
827 3
    }
828
829
    /**
830
     * Empty event handler
831
     *
832
     * Get called after the entity got updated in database.
833
     */
834 3
    public function postUpdate()
835
    {
836 3
    }
837
838
    /**
839
     * String representation of data
840
     *
841
     * @link http://php.net/manual/en/serializable.serialize.php
842
     * @return string
843
     */
844 2
    public function serialize()
845
    {
846 2
        return serialize([$this->data, $this->relatedObjects]);
847
    }
848
849
    /**
850
     * Constructs the object
851
     *
852
     * @link http://php.net/manual/en/serializable.unserialize.php
853
     * @param string $serialized The string representation of data
854
     */
855 3
    public function unserialize($serialized)
856
    {
857 3
        list($this->data, $this->relatedObjects) = unserialize($serialized);
858 3
        $this->onInit(false);
859 3
    }
860
}
861