Passed
Pull Request — master (#48)
by Thomas
02:22
created

Entity::generatePrimaryKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

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
nc 1
nop 0
crap 2
1
<?php
2
3
namespace ORM;
4
5
use ORM\Dbal\Column;
6
use ORM\Dbal\Error;
7
use ORM\Dbal\Table;
8
use ORM\Entity\GeneratesPrimaryKeys;
9
use ORM\EntityManager as EM;
10
use ORM\Exception\IncompletePrimaryKey;
11
use ORM\Exception\InvalidConfiguration;
12
use ORM\Exception\InvalidName;
13
use ORM\Exception\InvalidRelation;
14
use ORM\Exception\NoEntityManager;
15
use ORM\Exception\UndefinedRelation;
16
use ORM\Exception\UnknownColumn;
17
18
/**
19
 * Definition of an entity
20
 *
21
 * The instance of an entity represents a row of the table and the statics variables and methods describe the database
22
 * table.
23
 *
24
 * This is the main part where your configuration efforts go. The following properties and methods are well documented
25
 * in the manual under [https://tflori.github.io/orm/entityDefinition.html](Entity Definition).
26
 *
27
 * @package ORM
28
 * @link    https://tflori.github.io/orm/entityDefinition.html Entity Definition
29
 * @author  Thomas Flori <[email protected]>
30
 */
31
abstract class Entity implements \Serializable
32
{
33
    /** @deprecated Use Relation::OPT_CLASS instead */
34
    const OPT_RELATION_CLASS       = 'class';
35
    /** @deprecated Use Relation::OPT_CARDINALITY instead */
36
    const OPT_RELATION_CARDINALITY = 'cardinality';
37
    /** @deprecated Use Relation::OPT_REFERENCE instead */
38
    const OPT_RELATION_REFERENCE   = 'reference';
39
    /** @deprecated Use Relation::OPT_OPPONENT instead */
40
    const OPT_RELATION_OPPONENT    = 'opponent';
41
    /** @deprecated Use Relation::OPT_TABLE instead */
42
    const OPT_RELATION_TABLE       = 'table';
43
44
    /** The template to use to calculate the table name.
45
     * @var string */
46
    protected static $tableNameTemplate;
47
48
    /** The naming scheme to use for table names.
49
     * @var string */
50
    protected static $namingSchemeTable;
51
52
    /** The naming scheme to use for column names.
53
     * @var string */
54
    protected static $namingSchemeColumn;
55
56
    /** The naming scheme to use for method names.
57
     * @var string */
58
    protected static $namingSchemeMethods;
59
60
    /** Fixed table name (ignore other settings)
61
     * @var string */
62
    protected static $tableName;
63
64
    /** The variable(s) used for primary key.
65
     * @var string[]|string */
66
    protected static $primaryKey = ['id'];
67
68
    /** Fixed column names (ignore other settings)
69
     * @var string[] */
70
    protected static $columnAliases = [];
71
72
    /** A prefix for column names.
73
     * @var string */
74
    protected static $columnPrefix;
75
76
    /** Whether or not the primary key is auto incremented.
77
     * @var bool */
78
    protected static $autoIncrement = true;
79
80
    /** Whether or not the validator for this class is enabled.
81
     * @var bool */
82
    protected static $enableValidator = false;
83
84
    /** Whether or not the validator for a class got enabled during runtime.
85
     * @var bool[] */
86
    protected static $enabledValidators = [];
87
88
    /** Relation definitions
89
     * @var array */
90
    protected static $relations = [];
91
92
    /** The reflections of the classes.
93
     * @internal
94
     * @var \ReflectionClass[] */
95
    protected static $reflections = [];
96
97
    /** The current data of a row.
98
     * @var mixed[] */
99
    protected $data = [];
100
101
    /** The original data of the row.
102
     * @var mixed[] */
103
    protected $originalData = [];
104
105
    /** The entity manager from which this entity got created
106
     * @var EM */
107
    protected $entityManager;
108
109
    /** Related objects for getRelated
110
     * @var array */
111
    protected $relatedObjects = [];
112
113
    /**
114
     * Constructor
115
     *
116
     * It calls ::onInit() after initializing $data and $originalData.
117
     *
118
     * @param mixed[] $data          The current data
119
     * @param EM      $entityManager The EntityManager that created this entity
120
     * @param bool    $fromDatabase  Whether or not the data comes from database
121
     */
122 122
    final public function __construct(array $data = [], EM $entityManager = null, $fromDatabase = false)
123
    {
124 122
        if ($fromDatabase) {
125 14
            $this->originalData = $data;
126
        }
127 122
        $this->data          = array_merge($this->data, $data);
128 122
        $this->entityManager = $entityManager ?: EM::getInstance(static::class);
129 122
        $this->onInit(!$fromDatabase);
130 122
    }
131
132
    /**
133
     * Get a description for this table.
134
     *
135
     * @return Table|Column[]
136
     * @codeCoverageIgnore This is just a proxy
137
     */
138
    public static function describe()
139
    {
140
        return EM::getInstance(static::class)->describe(static::getTableName());
141
    }
142
143
    /**
144
     * Get the column name of $attribute
145
     *
146
     * The column names can not be specified by template. Instead they are constructed by $columnPrefix and enforced
147
     * to $namingSchemeColumn.
148
     *
149
     * **ATTENTION**: If your overwrite this method remember that getColumnName(getColumnName($name)) have to be exactly
150
     * the same as getColumnName($name).
151
     *
152
     * @param string $attribute
153
     * @return string
154
     * @throws InvalidConfiguration
155
     */
156 166
    public static function getColumnName($attribute)
157
    {
158 166
        if (isset(static::$columnAliases[$attribute])) {
159 6
            return static::$columnAliases[$attribute];
160
        }
161
162 164
        return EM::getInstance(static::class)->getNamer()
163 164
            ->getColumnName(static::class, $attribute, static::$columnPrefix, static::$namingSchemeColumn);
164
    }
165
166
    /**
167
     * Get the primary key vars
168
     *
169
     * The primary key can consist of multiple columns. You should configure the vars that are translated to these
170
     * columns.
171
     *
172
     * @return array
173
     */
174 72
    public static function getPrimaryKeyVars()
175
    {
176 72
        return !is_array(static::$primaryKey) ? [ static::$primaryKey ] : static::$primaryKey;
177
    }
178
179
    /**
180
     * Get the definition for $relation
181
     *
182
     * It normalize the short definition form and create a Relation object from it.
183
     *
184
     * @param string $relation
185
     * @return Relation
186
     * @throws InvalidConfiguration
187
     * @throws UndefinedRelation
188
     */
189 83
    public static function getRelation($relation)
190
    {
191 83
        if (!isset(static::$relations[$relation])) {
192 3
            throw new UndefinedRelation('Relation ' . $relation . ' is not defined');
193
        }
194
195 82
        $relDef = &static::$relations[$relation];
196
197 82
        if (!$relDef instanceof Relation) {
198 14
            $relDef = Relation::createRelation($relation, $relDef);
199
        }
200
201 81
        return $relDef;
202
    }
203
204
    /**
205
     * Get the table name
206
     *
207
     * The table name is constructed by $tableNameTemplate and $namingSchemeTable. It can be overwritten by
208
     * $tableName.
209
     *
210
     * @return string
211
     * @throws InvalidName|InvalidConfiguration
212
     */
213 154
    public static function getTableName()
214
    {
215 154
        if (static::$tableName) {
216 11
            return static::$tableName;
217
        }
218
219 143
        return EM::getInstance(static::class)->getNamer()
220 143
            ->getTableName(static::class, static::$tableNameTemplate, static::$namingSchemeTable);
221
    }
222
223
    /**
224
     * Check if the table has a auto increment column
225
     *
226
     * @return bool
227
     */
228 19
    public static function isAutoIncremented()
229
    {
230 19
        return count(static::getPrimaryKeyVars()) > 1 ? false : static::$autoIncrement;
231
    }
232
233
    /**
234
     * Check if the validator is enabled
235
     *
236
     * @return bool
237
     */
238 39
    public static function isValidatorEnabled()
239
    {
240 39
        return isset(self::$enabledValidators[static::class]) ?
241 39
            self::$enabledValidators[static::class] : static::$enableValidator;
242
    }
243
244
    /**
245
     * Enable validator
246
     *
247
     * @param bool $enable
248
     */
249 8
    public static function enableValidator($enable = true)
250
    {
251 8
        self::$enabledValidators[static::class] = $enable;
252 8
    }
253
254
    /**
255
     * Disable validator
256
     *
257
     * @param bool $disable
258
     */
259 33
    public static function disableValidator($disable = true)
260
    {
261 33
        self::$enabledValidators[static::class] = !$disable;
262 33
    }
263
264
    /**
265
     * Validate $value for $attribute
266
     *
267
     * @param string $attribute
268
     * @param mixed  $value
269
     * @return bool|Error
270
     * @throws Exception
271
     */
272 10
    public static function validate($attribute, $value)
273
    {
274 10
        return static::describe()->validate(static::getColumnName($attribute), $value);
275
    }
276
277
    /**
278
     * Validate $data
279
     *
280
     * $data has to be an array of $attribute => $value
281
     *
282
     * @param array $data
283
     * @return array
284
     */
285 1
    public static function validateArray(array $data)
286
    {
287 1
        $result = $data;
288 1
        foreach ($result as $attribute => &$value) {
289 1
            $value = static::validate($attribute, $value);
290
        }
291 1
        return $result;
292
    }
293
294
    /**
295
     * @param EM $entityManager
296
     * @return self
297
     */
298 12
    public function setEntityManager(EM $entityManager)
299
    {
300 12
        $this->entityManager = $entityManager;
301 12
        return $this;
302
    }
303
304
    /**
305
     * Get the value from $attribute
306
     *
307
     * If there is a custom getter this method get called instead.
308
     *
309
     * @param string $attribute The variable to get
310
     * @return mixed|null
311
     * @throws IncompletePrimaryKey
312
     * @throws InvalidConfiguration
313
     * @link https://tflori.github.io/orm/entities.html Working with entities
314
     */
315 112
    public function __get($attribute)
316
    {
317 112
        $em     = EM::getInstance(static::class);
318 112
        $getter = $em->getNamer()->getMethodName('get' . ucfirst($attribute), self::$namingSchemeMethods);
319
320 112
        if (method_exists($this, $getter) && is_callable([ $this, $getter ])) {
321 4
            return $this->$getter();
322
        } else {
323 108
            $col    = static::getColumnName($attribute);
324 108
            $result = isset($this->data[$col]) ? $this->data[$col] : null;
325
326 108
            if (!$result && isset(static::$relations[$attribute]) && isset($this->entityManager)) {
327 1
                return $this->getRelated($attribute);
328
            }
329
330 107
            return $result;
331
        }
332
    }
333
334
    /**
335
     * Check if a column is defined
336
     *
337
     * @param $attribute
338
     * @return bool
339
     */
340 3
    public function __isset($attribute)
341
    {
342 3
        $em     = EM::getInstance(static::class);
343 3
        $getter = $em->getNamer()->getMethodName('get' . ucfirst($attribute), self::$namingSchemeMethods);
344
345 3
        if (method_exists($this, $getter) && is_callable([ $this, $getter ])) {
346 1
            return $this->$getter() !== null;
347
        } else {
348 2
            $col = static::getColumnName($attribute);
349 2
            $isset = isset($this->data[$col]);
350
351 2
            if (!$isset && isset(static::$relations[$attribute])) {
352 1
                return !empty($this->getRelated($attribute));
353
            }
354
355 1
            return $isset;
356
        }
357
    }
358
359
    /**
360
     * Set $attribute to $value
361
     *
362
     * Tries to call custom setter before it stores the data directly. If there is a setter the setter needs to store
363
     * data that should be updated in the database to $data. Do not store data in $originalData as it will not be
364
     * written and give wrong results for dirty checking.
365
     *
366
     * The onChange event is called after something got changed.
367
     *
368
     * The method throws an error when the validation fails (also when the column does not exist).
369
     *
370
     * @param string $attribute The variable to change
371
     * @param mixed  $value     The value to store
372
     * @throws Error
373
     * @link https://tflori.github.io/orm/entities.html Working with entities
374
     */
375 38
    public function __set($attribute, $value)
376
    {
377 38
        $col = $this->getColumnName($attribute);
378
379 38
        $em     = EM::getInstance(static::class);
380 38
        $setter = $em->getNamer()->getMethodName('set' . ucfirst($attribute), self::$namingSchemeMethods);
381
382 38
        if (method_exists($this, $setter) && is_callable([ $this, $setter ])) {
383 3
            $oldValue   = $this->__get($attribute);
384 3
            $md5OldData = md5(serialize($this->data));
385 3
            $this->$setter($value);
386 3
            $changed = $md5OldData !== md5(serialize($this->data));
387
        } else {
388 35
            if (static::isValidatorEnabled() &&
389 35
                ($error = static::validate($attribute, $value)) instanceof Error
390
            ) {
391 1
                throw $error;
392
            }
393
394 31
            $oldValue         = $this->__get($attribute);
395 31
            $changed          = (isset($this->data[$col]) ? $this->data[$col] : null) !== $value;
396 31
            $this->data[$col] = $value;
397
        }
398
399 34
        if ($changed) {
400 31
            $this->onChange($attribute, $oldValue, $this->__get($attribute));
401
        }
402 34
    }
403
404
    /**
405
     * Fill the entity with $data
406
     *
407
     * When $checkMissing is set to true it also proves that the absent columns are nullable.
408
     *
409
     * @param array $data
410
     * @param bool  $ignoreUnknown
411
     * @param bool  $checkMissing
412
     * @throws Error
413
     * @throws UnknownColumn
414
     */
415 8
    public function fill(array $data, $ignoreUnknown = false, $checkMissing = false)
416
    {
417 8
        foreach ($data as $attribute => $value) {
418
            try {
419 7
                $this->__set($attribute, $value);
420 2
            } catch (UnknownColumn $e) {
421 2
                if (!$ignoreUnknown) {
422 7
                    throw $e;
423
                }
424
            }
425
        }
426
427 7
        if ($checkMissing && is_array($errors = $this->isValid())) {
428 1
            throw $errors[0];
429
        }
430 6
    }
431
432
    /**
433
     * Get related objects
434
     *
435
     * The difference between getRelated and fetch is that getRelated stores the fetched entities. To refresh set
436
     * $refresh to true.
437
     *
438
     * @param string $relation
439
     * @param bool   $refresh
440
     * @return mixed
441
     * @throws Exception\NoConnection
442
     * @throws Exception\NoEntity
443
     * @throws IncompletePrimaryKey
444
     * @throws InvalidConfiguration
445
     * @throws NoEntityManager
446
     * @throws UndefinedRelation
447
     */
448 11
    public function getRelated($relation, $refresh = false)
449
    {
450 11
        if ($refresh || !isset($this->relatedObjects[$relation])) {
451 9
            $this->relatedObjects[$relation] = $this->fetch($relation, true);
452
        }
453
454 11
        return $this->relatedObjects[$relation];
455
    }
456
457
    /**
458
     * Set $relation to $entity
459
     *
460
     * This method is only for the owner of a relation.
461
     *
462
     * @param string $relation
463
     * @param Entity $entity
464
     * @throws IncompletePrimaryKey
465
     * @throws InvalidRelation
466
     */
467 7
    public function setRelated($relation, Entity $entity = null)
468
    {
469 7
        $this::getRelation($relation)->setRelated($this, $entity);
470
471 4
        $this->relatedObjects[$relation] = $entity;
472 4
    }
473
474
    /**
475
     * Add relations for $relation to $entities
476
     *
477
     * This method is only for many-to-many relations.
478
     *
479
     * This method does not take care about already existing relations and will fail hard.
480
     *
481
     * @param string   $relation
482
     * @param Entity[] $entities
483
     * @throws NoEntityManager
484
     */
485 8
    public function addRelated($relation, array $entities)
486
    {
487
        // @codeCoverageIgnoreStart
488
        if (func_num_args() === 3 && func_get_arg(2) instanceof EM) {
489
            trigger_error(
490
                'Passing EntityManager to addRelated is deprecated. Use ->setEntityManager() to overwrite',
491
                E_USER_DEPRECATED
492
            );
493
        }
494
        // @codeCoverageIgnoreEnd
495
496 8
        $this::getRelation($relation)->addRelated($this, $entities, $this->entityManager);
497 4
    }
498
499
    /**
500
     * Delete relations for $relation to $entities
501
     *
502
     * This method is only for many-to-many relations.
503
     *
504
     * @param string   $relation
505
     * @param Entity[] $entities
506
     * @throws NoEntityManager
507
     */
508 8
    public function deleteRelated($relation, $entities)
509
    {
510
        // @codeCoverageIgnoreStart
511
        if (func_num_args() === 3 && func_get_arg(2) instanceof EM) {
512
            trigger_error(
513
                'Passing EntityManager to deleteRelated is deprecated. Use ->setEntityManager() to overwrite',
514
                E_USER_DEPRECATED
515
            );
516
        }
517
        // @codeCoverageIgnoreEnd
518
519 8
        $this::getRelation($relation)->deleteRelated($this, $entities, $this->entityManager);
520 4
    }
521
522
    /**
523
     * Resets the entity or $attribute to original data
524
     *
525
     * @param string $attribute Reset only this variable or all variables
526
     * @throws InvalidConfiguration
527
     */
528 22
    public function reset($attribute = null)
529
    {
530 22
        if (!empty($attribute)) {
531 3
            $col = static::getColumnName($attribute);
532 3
            if (isset($this->originalData[$col])) {
533 2
                $this->data[$col] = $this->originalData[$col];
534
            } else {
535 1
                unset($this->data[$col]);
536
            }
537 3
            return;
538
        }
539
540 19
        $this->data = $this->originalData;
541 19
    }
542
543
    /**
544
     * Save the entity to EntityManager
545
     *
546
     * @return Entity
547
     * @throws Exception\NoConnection
548
     * @throws Exception\NoEntity
549
     * @throws Exception\NotScalar
550
     * @throws Exception\UnsupportedDriver
551
     * @throws IncompletePrimaryKey
552
     * @throws InvalidConfiguration
553
     * @throws InvalidName
554
     * @throws NoEntityManager
555
     */
556 16
    public function save()
557
    {
558
        // @codeCoverageIgnoreStart
559
        if (func_num_args() === 1 && func_get_arg(0) instanceof EM) {
560
            trigger_error(
561
                'Passing EntityManager to save is deprecated. Use ->setEntityManager() to overwrite',
562
                E_USER_DEPRECATED
563
            );
564
        }
565
        // @codeCoverageIgnoreEnd
566
567 16
        $inserted = false;
568 16
        $updated  = false;
569
570
        try {
571
            // this may throw if the primary key is auto incremented but we using this to omit duplicated code
572 16
            if (!$this->entityManager->sync($this)) {
573 2
                $this->prePersist();
574 2
                $inserted = $this->entityManager->insert($this, false);
575 4
            } elseif ($this->isDirty()) {
576 3
                $this->preUpdate();
577 6
                $updated = $this->entityManager->update($this);
578
            }
579 10
        } catch (IncompletePrimaryKey $e) {
580 10
            if (static::isAutoIncremented()) {
581 8
                $this->prePersist();
582 8
                $inserted = $this->entityManager->insert($this);
583
            } elseif ($this instanceof GeneratesPrimaryKeys) {
584 1
                $this->generatePrimaryKey();
585 1
                $this->prePersist();
586 1
                $inserted = $this->entityManager->insert($this);
587
            } else {
588 1
                throw $e;
589
            }
590
        }
591
592 14
        $inserted && $this->postPersist();
593 14
        $updated && $this->postUpdate();
594
595 14
        return $this;
596
    }
597
598
    /**
599
     * Generates a primary key
600
     *
601
     * This method should only be executed from save method.
602
     */
603
    protected function generatePrimaryKey()
604
    {
605
        // no operation by default
606
    }
607
608
    /**
609
     * Checks if entity or $attribute got changed
610
     *
611
     * @param string $attribute Check only this variable or all variables
612
     * @return bool
613
     * @throws InvalidConfiguration
614
     */
615 20
    public function isDirty($attribute = null)
616
    {
617 20
        if (!empty($attribute)) {
618 4
            $col = static::getColumnName($attribute);
619 4
            return (isset($this->data[$col]) ? $this->data[$col] : null) !==
620 4
                   (isset($this->originalData[$col]) ? $this->originalData[$col] : null);
621
        }
622
623 17
        ksort($this->data);
624 17
        ksort($this->originalData);
625
626 17
        return serialize($this->data) !== serialize($this->originalData);
627
    }
628
629
    /**
630
     * Check if the current data is valid
631
     *
632
     * Returns boolean true when valid otherwise an array of Errors.
633
     *
634
     * @return bool|Error[]
635
     */
636 1
    public function isValid()
637
    {
638 1
        $result = [];
639
640 1
        $presentColumns = [];
641 1
        foreach ($this->data as $column => $value) {
642 1
            $presentColumns[] = $column;
643 1
            $result[]         = static::validate($column, $value);
644
        }
645
646 1
        foreach (static::describe() as $column) {
647 1
            if (!in_array($column->name, $presentColumns)) {
648 1
                $result[] = static::validate($column->name, null);
649
            }
650
        }
651
652 1
        $result = array_values(array_filter($result, function ($error) {
653 1
            return $error instanceof Error;
654 1
        }));
655
656 1
        return count($result) === 0 ? true : $result;
657
    }
658
659
    /**
660
     * Empty event handler
661
     *
662
     * Get called when something is changed with magic setter.
663
     *
664
     * @param string $attribute The variable that got changed.merge(node.inheritedProperties)
665
     * @param mixed  $oldValue  The old value of the variable
666
     * @param mixed  $value     The new value of the variable
667
     * @codeCoverageIgnore dummy event handler
668
     */
669
    public function onChange($attribute, $oldValue, $value)
0 ignored issues
show
Unused Code introduced by
The parameter $attribute is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $oldValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
670
    {
671
    }
672
673
    /**
674
     * Empty event handler
675
     *
676
     * Get called when the entity get initialized.
677
     *
678
     * @param bool $new Whether or not the entity is new or from database
679
     * @codeCoverageIgnore dummy event handler
680
     */
681
    public function onInit($new)
0 ignored issues
show
Unused Code introduced by
The parameter $new is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
682
    {
683
    }
684
685
    /**
686
     * Empty event handler
687
     *
688
     * Get called before the entity get updated in database.
689
     *
690
     * @codeCoverageIgnore dummy event handler
691
     */
692
    public function preUpdate()
693
    {
694
    }
695
696
    /**
697
     * Empty event handler
698
     *
699
     * Get called before the entity get inserted in database.
700
     *
701
     * @codeCoverageIgnore dummy event handler
702
     */
703
    public function prePersist()
704
    {
705
    }
706
707
708
    /**
709
     * Empty event handler
710
     *
711
     * Get called after the entity got inserted in database.
712
     *
713
     * @codeCoverageIgnore dummy event handler
714
     */
715
    public function postPersist()
716
    {
717
    }
718
719
    /**
720
     * Empty event handler
721
     *
722
     * Get called after the entity got updated in database.
723
     *
724
     * @codeCoverageIgnore dummy event handler
725
     */
726
    public function postUpdate()
727
    {
728
    }
729
730
    /**
731
     * Fetches related objects
732
     *
733
     * For relations with cardinality many it returns an EntityFetcher. Otherwise it returns the entity.
734
     *
735
     * It will throw an error for non owner when the key is incomplete.
736
     *
737
     * @param string $relation The relation to fetch
738
     * @param bool   $getAll
739
     * @return Entity|Entity[]|EntityFetcher
740
     * @throws NoEntityManager
741
     */
742 20
    public function fetch($relation, $getAll = false)
743
    {
744
        // @codeCoverageIgnoreStart
745
        if ($getAll instanceof EM || func_num_args() === 3 && $getAll === null) {
746
            $getAll = func_num_args() === 3 ? func_get_arg(2) : false;
747
            trigger_error(
748
                'Passing EntityManager to fetch is deprecated. Use ->setEntityManager() to overwrite',
749
                E_USER_DEPRECATED
750
            );
751
        }
752
        // @codeCoverageIgnoreEnd
753
754 20
        $relation = $this::getRelation($relation);
755
756 20
        if ($getAll) {
757 4
            return $relation->fetchAll($this, $this->entityManager);
758
        } else {
759 16
            return $relation->fetch($this, $this->entityManager);
760
        }
761
    }
762
763
    /**
764
     * Get the primary key
765
     *
766
     * @return array
767
     * @throws IncompletePrimaryKey
768
     */
769 53
    public function getPrimaryKey()
770
    {
771 53
        $primaryKey = [];
772 53
        foreach (static::getPrimaryKeyVars() as $attribute) {
773 53
            $value = $this->$attribute;
774 53
            if ($value === null) {
775 9
                throw new IncompletePrimaryKey('Incomplete primary key - missing ' . $attribute);
776
            }
777 49
            $primaryKey[$attribute] = $value;
778
        }
779 47
        return $primaryKey;
780
    }
781
782
    /**
783
     * Get current data
784
     *
785
     * @return array
786
     * @internal
787
     */
788 31
    public function getData()
789
    {
790 31
        return $this->data;
791
    }
792
793
    /**
794
     * Set new original data
795
     *
796
     * @param array $data
797
     * @internal
798
     */
799 38
    public function setOriginalData(array $data)
800
    {
801 38
        $this->originalData = $data;
802 38
    }
803
804
    /**
805
     * String representation of data
806
     *
807
     * @link http://php.net/manual/en/serializable.serialize.php
808
     * @return string
809
     */
810 2
    public function serialize()
811
    {
812 2
        return serialize([ $this->data, $this->relatedObjects ]);
813
    }
814
815
    /**
816
     * Constructs the object
817
     *
818
     * @link http://php.net/manual/en/serializable.unserialize.php
819
     * @param string $serialized The string representation of data
820
     */
821 3
    public function unserialize($serialized)
822
    {
823 3
        list($this->data, $this->relatedObjects) = unserialize($serialized);
824 3
        $this->entityManager = EM::getInstance(static::class);
825 3
        $this->onInit(false);
826 3
    }
827
828
    // DEPRECATED stuff
829
830
    /**
831
     * @return string
832
     * @deprecated         use getOption from EntityManager
833
     * @codeCoverageIgnore deprecated
834
     */
835
    public static function getTableNameTemplate()
836
    {
837
        return static::$tableNameTemplate;
838
    }
839
840
    /**
841
     * @param string $tableNameTemplate
842
     * @deprecated         use setOption from EntityManager
843
     * @codeCoverageIgnore deprecated
844
     */
845
    public static function setTableNameTemplate($tableNameTemplate)
846
    {
847
        static::$tableNameTemplate = $tableNameTemplate;
848
    }
849
850
    /**
851
     * @return string
852
     * @deprecated         use getOption from EntityManager
853
     * @codeCoverageIgnore deprecated
854
     */
855
    public static function getNamingSchemeTable()
856
    {
857
        return static::$namingSchemeTable;
858
    }
859
860
    /**
861
     * @param string $namingSchemeTable
862
     * @deprecated         use setOption from EntityManager
863
     * @codeCoverageIgnore deprecated
864
     */
865
    public static function setNamingSchemeTable($namingSchemeTable)
866
    {
867
        static::$namingSchemeTable = $namingSchemeTable;
868
    }
869
870
    /**
871
     * @return string
872
     * @deprecated         use getOption from EntityManager
873
     * @codeCoverageIgnore deprecated
874
     */
875
    public static function getNamingSchemeColumn()
876
    {
877
        return static::$namingSchemeColumn;
878
    }
879
880
    /**
881
     * @param string $namingSchemeColumn
882
     * @deprecated         use setOption from EntityManager
883
     * @codeCoverageIgnore deprecated
884
     */
885
    public static function setNamingSchemeColumn($namingSchemeColumn)
886
    {
887
        static::$namingSchemeColumn = $namingSchemeColumn;
888
    }
889
890
    /**
891
     * @return string
892
     * @deprecated         use getOption from EntityManager
893
     * @codeCoverageIgnore deprecated
894
     */
895
    public static function getNamingSchemeMethods()
896
    {
897
        return static::$namingSchemeMethods;
898
    }
899
900
    /**
901
     * @param string $namingSchemeMethods
902
     * @deprecated         use setOption from EntityManager
903
     * @codeCoverageIgnore deprecated
904
     */
905
    public static function setNamingSchemeMethods($namingSchemeMethods)
906
    {
907
        static::$namingSchemeMethods = $namingSchemeMethods;
908
    }
909
}
910