Passed
Pull Request — master (#7825)
by
unknown
08:34
created

ClassMetadata   F

Complexity

Total Complexity 161

Size/Duplication

Total Lines 1063
Duplicated Lines 0 %

Test Coverage

Coverage 90.03%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 294
c 2
b 0
f 0
dl 0
loc 1063
ccs 307
cts 341
cp 0.9003
rs 2
wmc 161

51 Methods

Rating   Name   Duplication   Size   Complexity  
A getColumnsIterator() 0 9 2
B setParent() 0 33 7
A setClassName() 0 3 1
A getAncestorsIterator() 0 14 4
A __construct() 0 6 2
A __toString() 0 3 1
A setChangeTrackingPolicy() 0 3 1
A getLifecycleCallbacks() 0 3 1
B getIdentifierColumns() 0 41 7
A addDiscriminatorMapClass() 0 16 6
A hasLifecycleCallbacks() 0 3 1
A setTable() 0 19 5
A isReadOnly() 0 3 1
A setValueGenerationPlan() 0 3 1
A isVersioned() 0 3 1
A setDiscriminatorColumn() 0 15 3
B validateIdentifier() 0 19 8
A getColumn() 0 9 4
A inlineEmbeddable() 0 2 1
A setInheritanceType() 0 7 2
A isIdentifier() 0 11 3
A isInheritanceType() 0 6 4
A getSchemaName() 0 3 1
A validateLifecycleCallbacks() 0 7 4
A __clone() 0 8 3
A getTableName() 0 3 1
A setIdentifier() 0 3 1
A addLifecycleCallback() 0 7 2
A getIdentifier() 0 3 1
A getSubClasses() 0 3 1
A setSubclasses() 0 4 2
A getIdentifierFieldNames() 0 3 1
A addEntityListener() 0 21 4
A getSingleIdentifierFieldName() 0 11 3
A isInheritedProperty() 0 17 5
F __sleep() 0 62 11
A mapEmbedded() 0 2 1
A setCustomRepositoryClassName() 0 3 1
A getValueGenerationPlan() 0 3 1
A getTemporaryIdTableName() 0 8 2
A getRootClassName() 0 9 3
A checkPropertyDuplication() 0 4 3
A isRootEntity() 0 3 1
A setDiscriminatorMap() 0 4 2
B addInheritedProperty() 0 34 11
C setPropertyOverride() 0 66 17
A asReadOnly() 0 3 1
A getCustomRepositoryClassName() 0 3 1
A isIdentifierComposite() 0 3 1
A hasField() 0 4 2
B addProperty() 0 37 8

How to fix   Complexity   

Complex Class

Complex classes like ClassMetadata 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.

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 ClassMetadata, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
introduced by
An error occurred during processing; checking has been aborted. The error message was: "else" without curly braces is not supported.
Loading history...
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Mapping;
6
7
use ArrayIterator;
8
use Doctrine\ORM\Cache\Exception\CacheException;
9
use Doctrine\ORM\EntityManagerInterface;
10
use Doctrine\ORM\Reflection\ReflectionService;
11
use Doctrine\ORM\Sequencing\Planning\ValueGenerationPlan;
12
use Doctrine\ORM\Utility\PersisterHelper;
13
use ReflectionException;
14
use RuntimeException;
15
use function array_filter;
16
use function array_merge;
17
use function class_exists;
18
use function get_class;
19
use function in_array;
20
use function interface_exists;
21
use function is_subclass_of;
22
use function method_exists;
23
use function spl_object_id;
24
25
/**
26
 * A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
27
 * of an entity and its associations.
28
 */
29
class ClassMetadata extends ComponentMetadata implements TableOwner
30
{
31
    /**
32
     * The name of the custom repository class used for the entity class.
33
     * (Optional).
34
     *
35
     * @var string
36
     */
37
    protected $customRepositoryClassName;
38
39
    /**
40
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
41
     *
42
     * @var bool
43
     */
44
    public $isMappedSuperclass = false;
45
46
    /**
47
     * READ-ONLY: Whether this class describes the mapping of an embeddable class.
48
     *
49
     * @var bool
50
     */
51
    public $isEmbeddedClass = false;
52
53
    /**
54
     * Whether this class describes the mapping of a read-only class.
55
     * That means it is never considered for change-tracking in the UnitOfWork.
56
     * It is a very helpful performance optimization for entities that are immutable,
57
     * either in your domain or through the relation database (coming from a view,
58
     * or a history table for example).
59
     *
60
     * @var bool
61
     */
62
    private $readOnly = false;
63
64
    /**
65
     * The names of all subclasses (descendants).
66
     *
67
     * @var string[]
68
     */
69
    protected $subClasses = [];
70
71
    /**
72
     * READ-ONLY: The names of all embedded classes based on properties.
73
     *
74
     * @var string[]
75
     */
76
    //public $embeddedClasses = [];
77
78
    /**
79
     * READ-ONLY: The registered lifecycle callbacks for entities of this class.
80
     *
81
     * @var string[][]
82
     */
83
    public $lifecycleCallbacks = [];
84
85
    /**
86
     * READ-ONLY: The registered entity listeners.
87
     *
88
     * @var mixed[][]
89
     */
90
    public $entityListeners = [];
91
92
    /**
93
     * READ-ONLY: The field names of all fields that are part of the identifier/primary key
94
     * of the mapped entity class.
95
     *
96
     * @var string[]
97
     */
98
    public $identifier = [];
99
100
    /**
101
     * READ-ONLY: The inheritance mapping type used by the class.
102
     *
103
     * @var string
104
     */
105
    public $inheritanceType = InheritanceType::NONE;
106
107
    /**
108
     * READ-ONLY: The policy used for change-tracking on entities of this class.
109
     *
110
     * @var string
111
     */
112
    public $changeTrackingPolicy = ChangeTrackingPolicy::DEFERRED_IMPLICIT;
113
114
    /**
115
     * READ-ONLY: The discriminator value of this class.
116
     *
117
     * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
118
     * where a discriminator column is used.</b>
119
     *
120
     * @see discriminatorColumn
121
     *
122
     * @var mixed
123
     */
124
    public $discriminatorValue;
125
126
    /**
127
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
128
     *
129
     * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
130
     * where a discriminator column is used.</b>
131
     *
132
     * @see discriminatorColumn
133
     *
134
     * @var string[]
135
     */
136
    public $discriminatorMap = [];
137
138
    /**
139
     * READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
140
     * inheritance mappings.
141
     *
142
     * @var DiscriminatorColumnMetadata
143
     */
144
    public $discriminatorColumn;
145
146
    /**
147
     * READ-ONLY: The primary table metadata.
148
     *
149
     * @var TableMetadata
150
     */
151
    public $table;
152
153
    /**
154
     * READ-ONLY: An array of field names. Used to look up field names from column names.
155
     * Keys are column names and values are field names.
156
     *
157
     * @var string[]
158
     */
159
    public $fieldNames = [];
160
161
    /**
162
     * READ-ONLY: The field which is used for versioning in optimistic locking (if any).
163
     *
164
     * @var FieldMetadata|null
165
     */
166
    public $versionProperty;
167
168
    /**
169
     * Value generation plan is responsible for generating values for auto-generated fields.
170
     *
171
     * @var ValueGenerationPlan
172
     */
173
    protected $valueGenerationPlan;
174
175
    /**
176
     * Initializes a new ClassMetadata instance that will hold the object-relational mapping
177
     * metadata of the class with the given name.
178
     *
179
     * @param string             $entityName The name of the entity class.
180
     * @param ClassMetadata|null $parent     Optional parent class metadata.
181
     */
182 450
    public function __construct(string $entityName, ?ComponentMetadata $parent)
183
    {
184 450
        parent::__construct($entityName);
185
186 450
        if ($parent) {
187 99
            $this->setParent($parent);
188
        }
189 450
    }
190
191
    /**
0 ignored issues
show
Coding Style Documentation introduced by
Doc comment for parameter "$parent" missing
Loading history...
192
     * {@inheritdoc}
193
     *
194
     * @throws MappingException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
195
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
196 99
    public function setParent(ComponentMetadata $parent) : void
197
    {
198 99
        parent::setParent($parent);
199
200 99
        foreach ($parent->getPropertiesIterator() as $fieldName => $property) {
201 96
            $this->addInheritedProperty($property);
202
        }
203
204
        // @todo guilhermeblanco Assume to be a ClassMetadata temporarily until ClassMetadata split is complete.
205
        /** @var ClassMetadata $parent */
206 99
        $this->setInheritanceType($parent->inheritanceType);
0 ignored issues
show
Bug introduced by
$parent->inheritanceType of type string is incompatible with the type integer expected by parameter $type of Doctrine\ORM\Mapping\Cla...a::setInheritanceType(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

206
        $this->setInheritanceType(/** @scrutinizer ignore-type */ $parent->inheritanceType);
Loading history...
207 99
        $this->setIdentifier($parent->identifier);
208 99
        $this->setChangeTrackingPolicy($parent->changeTrackingPolicy);
209
210 99
        if ($parent->discriminatorColumn) {
211 71
            $this->setDiscriminatorColumn($parent->discriminatorColumn);
212 71
            $this->setDiscriminatorMap($parent->discriminatorMap);
213
        }
214
215 99
        if ($parent->isMappedSuperclass) {
216 28
            $this->setCustomRepositoryClassName($parent->getCustomRepositoryClassName());
217
        }
218
219 99
        if ($parent->cache) {
220 3
            $this->setCache(clone $parent->cache);
221
        }
222
223 99
        if (! empty($parent->lifecycleCallbacks)) {
224 5
            $this->lifecycleCallbacks = $parent->lifecycleCallbacks;
225
        }
226
227 99
        if (! empty($parent->entityListeners)) {
228 7
            $this->entityListeners = $parent->entityListeners;
229
        }
230 99
    }
231
232
    public function setClassName(string $className)
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::setClassName() does not have void return type hint.
Loading history...
Coding Style Documentation introduced by
Missing doc comment for function setClassName()
Loading history...
233
    {
234
        $this->className = $className;
235
    }
236
237
    public function getColumnsIterator() : ArrayIterator
0 ignored issues
show
Coding Style Documentation introduced by
Missing doc comment for function getColumnsIterator()
Loading history...
238
    {
239
        $iterator = parent::getColumnsIterator();
240
241
        if ($this->discriminatorColumn) {
242
            $iterator->offsetSet($this->discriminatorColumn->getColumnName(), $this->discriminatorColumn);
0 ignored issues
show
Bug introduced by
$this->discriminatorColumn of type Doctrine\ORM\Mapping\DiscriminatorColumnMetadata is incompatible with the type string expected by parameter $newval of ArrayIterator::offsetSet(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

242
            $iterator->offsetSet($this->discriminatorColumn->getColumnName(), /** @scrutinizer ignore-type */ $this->discriminatorColumn);
Loading history...
243
        }
244
245
        return $iterator;
246
    }
247
248 11
    public function getAncestorsIterator() : ArrayIterator
0 ignored issues
show
Coding Style Documentation introduced by
Missing doc comment for function getAncestorsIterator()
Loading history...
249
    {
250 11
        $ancestors = new ArrayIterator();
251 11
        $parent    = $this;
252
253 11
        while (($parent = $parent->parent) !== null) {
254 8
            if ($parent instanceof ClassMetadata && $parent->isMappedSuperclass) {
255 1
                continue;
256
            }
257
258 7
            $ancestors->append($parent);
259
        }
260
261 11
        return $ancestors;
262
    }
263
264 1260
    public function getRootClassName() : string
0 ignored issues
show
Coding Style Documentation introduced by
Missing doc comment for function getRootClassName()
Loading history...
265
    {
266 1260
        $rootClass = $parentClass = $this;
267 1260
        while (($parentClass = $parentClass->getParent()) !== null) {
268 404
            if (! $parentClass->isMappedSuperclass) {
269 402
                $rootClass = $parentClass;
270
            }
271
        }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
272 1260
        return $rootClass->className;
0 ignored issues
show
introduced by
Expected 1 lines before "return", found 0.
Loading history...
273
    }
274
275
    /**
276
     * Handles metadata cloning nicely.
277
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
278 12
    public function __clone()
279
    {
280 12
        if ($this->cache) {
281 12
            $this->cache = clone $this->cache;
282
        }
283
284 12
        foreach ($this->properties as $name => $property) {
285 12
            $this->properties[$name] = clone $property;
286
        }
287 12
    }
288
289
    /**
290
     * Creates a string representation of this instance.
291
     *
292
     * @return string The string representation of this instance.
293
     *
294
     * @todo Construct meaningful string representation.
295
     */
296
    public function __toString()
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::__toString() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string".
Loading history...
297
    {
298
        return self::class . '@' . spl_object_id($this);
299
    }
300
301
    /**
302
     * Determines which fields get serialized.
303
     *
304
     * It is only serialized what is necessary for best unserialization performance.
305
     * That means any metadata properties that are not set or empty or simply have
306
     * their default value are NOT serialized.
307
     *
308
     * Parts that are also NOT serialized because they can not be properly unserialized:
309
     * - reflectionClass
310
     *
311
     * @return string[] The names of all the fields that should be serialized.
312
     */
313 4
    public function __sleep()
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::__sleep() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string[]".
Loading history...
314
    {
315 4
        $serialized = [];
316
317
        // This metadata is always serialized/cached.
318 4
        $serialized = array_merge($serialized, [
319 4
            'properties',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
320
            'fieldNames',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
321
            //'embeddedClasses',
322
            'identifier',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
323
            'className',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
324
            'parent',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
325
            'table',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
326
            'valueGenerationPlan',
0 ignored issues
show
Coding Style introduced by
This array value does not seem to be aligned correcty; expected 48 spaces, but found 12.
Loading history...
327
        ]);
0 ignored issues
show
Coding Style introduced by
The closing parenthesis does not seem to be aligned correctly; expected 47 space(s), but found 8.
Loading history...
328
329
        // The rest of the metadata is only serialized if necessary.
330 4
        if ($this->changeTrackingPolicy !== ChangeTrackingPolicy::DEFERRED_IMPLICIT) {
331
            $serialized[] = 'changeTrackingPolicy';
332
        }
333
334 4
        if ($this->customRepositoryClassName) {
335 1
            $serialized[] = 'customRepositoryClassName';
336
        }
337
338 4
        if ($this->inheritanceType !== InheritanceType::NONE) {
339 1
            $serialized[] = 'inheritanceType';
340 1
            $serialized[] = 'discriminatorColumn';
341 1
            $serialized[] = 'discriminatorValue';
342 1
            $serialized[] = 'discriminatorMap';
343 1
            $serialized[] = 'subClasses';
344
        }
345
346 4
        if ($this->isMappedSuperclass) {
347
            $serialized[] = 'isMappedSuperclass';
348
        }
349
350 4
        if ($this->isEmbeddedClass) {
351
            $serialized[] = 'isEmbeddedClass';
352
        }
353
354 4
        if ($this->isVersioned()) {
355
            $serialized[] = 'versionProperty';
356
        }
357
358 4
        if ($this->lifecycleCallbacks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->lifecycleCallbacks of type array<mixed,string[]> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
359
            $serialized[] = 'lifecycleCallbacks';
360
        }
361
362 4
        if ($this->entityListeners) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->entityListeners of type array<mixed,array<mixed,mixed>> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
363 1
            $serialized[] = 'entityListeners';
364
        }
365
366 4
        if ($this->cache) {
367
            $serialized[] = 'cache';
368
        }
369
370 4
        if ($this->readOnly) {
371 1
            $serialized[] = 'readOnly';
372
        }
373
374 4
        return $serialized;
375
    }
376
377
    /**
0 ignored issues
show
Coding Style Documentation introduced by
Doc comment for parameter "$policy" missing
Loading history...
378
     * Sets the change tracking policy used by this class.
379
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
380 105
    public function setChangeTrackingPolicy(string $policy) : void
381
    {
382 105
        $this->changeTrackingPolicy = $policy;
383 105
    }
384
385
    /**
386
     * Checks whether a field is part of the identifier/primary key field(s).
387
     *
388
     * @param string $fieldName The field name.
389
     *
390
     * @return bool TRUE if the field is part of the table identifier/primary key field(s), FALSE otherwise.
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
391
     */
392 1027
    public function isIdentifier(string $fieldName) : bool
393
    {
394 1027
        if (! $this->identifier) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->identifier of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
395 1
            return false;
396
        }
397
398 1026
        if (! $this->isIdentifierComposite()) {
399 1022
            return $fieldName === $this->identifier[0];
400
        }
401
402 93
        return in_array($fieldName, $this->identifier, true);
403
    }
404
405 1213
    public function isIdentifierComposite() : bool
0 ignored issues
show
Coding Style Documentation introduced by
Missing doc comment for function isIdentifierComposite()
Loading history...
406
    {
407 1213
        return isset($this->identifier[1]);
408
    }
409
410
    /**
411
     * Validates Identifier.
412
     *
413
     * @throws MappingException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
414
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
415 368
    public function validateIdentifier() : void
416
    {
417 368
        if ($this->isMappedSuperclass || $this->isEmbeddedClass) {
418 28
            return;
419
        }
420
421
        // Verify & complete identifier mapping
422 368
        if (! $this->identifier) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->identifier of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
423 2
            throw MappingException::identifierRequired($this->className);
424
        }
425
426
        $explicitlyGeneratedProperties = array_filter($this->properties, static function (Property $property) : bool {
427 366
            return $property instanceof FieldMetadata
428 366
                && $property->isPrimaryKey()
429 366
                && $property->hasValueGenerator();
430 366
        });
431
432 366
        if ($explicitlyGeneratedProperties && $this->isIdentifierComposite()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $explicitlyGeneratedProperties of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
433
            throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->className);
434
        }
435 366
    }
436
437
    /**
0 ignored issues
show
Coding Style Documentation introduced by
Doc comment for parameter "$reflectionService" missing
Loading history...
438
     * Validates lifecycle callbacks.
439
     *
440
     * @throws MappingException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
441
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
442 369
    public function validateLifecycleCallbacks(ReflectionService $reflectionService) : void
443
    {
444 369
        foreach ($this->lifecycleCallbacks as $callbacks) {
445
            /** @var array $callbacks */
446 10
            foreach ($callbacks as $callbackFuncName) {
447 10
                if (! $reflectionService->hasPublicMethod($this->className, $callbackFuncName)) {
448 1
                    throw MappingException::lifecycleCallbackMethodNotFound($this->className, $callbackFuncName);
449
                }
450
            }
451
        }
452 368
    }
453
454
    /**
455
     * {@inheritDoc}
456
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
457 402
    public function getIdentifierFieldNames()
458
    {
459 402
        return $this->identifier;
460
    }
461
462
    /**
463
     * Gets the name of the single id field. Note that this only works on
464
     * entity classes that have a single-field pk.
465
     *
466
     * @return string
467
     *
468
     * @throws MappingException If the class has a composite primary key.
469
     */
470 152
    public function getSingleIdentifierFieldName()
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::getSingleIdentifierFieldName() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string".
Loading history...
471
    {
472 152
        if ($this->isIdentifierComposite()) {
473 1
            throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->className);
474
        }
475
476 151
        if (! isset($this->identifier[0])) {
477 1
            throw MappingException::noIdDefined($this->className);
478
        }
479
480 150
        return $this->identifier[0];
481
    }
482
483
    /**
484
     * INTERNAL:
485
     * Sets the mapped identifier/primary key fields of this class.
486
     * Mainly used by the ClassMetadataFactory to assign inherited identifiers.
487
     *
488
     * @param mixed[] $identifier
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
489
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
490 101
    public function setIdentifier(array $identifier)
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::setIdentifier() does not have void return type hint.
Loading history...
491
    {
492 101
        $this->identifier = $identifier;
493 101
    }
494
495
    /**
496
     * {@inheritDoc}
497
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
498 1053
    public function getIdentifier()
499
    {
500 1053
        return $this->identifier;
501
    }
502
503
    /**
0 ignored issues
show
Coding Style Documentation introduced by
Doc comment for parameter "$fieldName" missing
Loading history...
504
     * {@inheritDoc}
505
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
506 189
    public function hasField($fieldName)
507
    {
508 189
        return isset($this->properties[$fieldName])
509 189
            && $this->properties[$fieldName] instanceof FieldMetadata;
510
    }
511
512
    /**
0 ignored issues
show
Coding Style Documentation introduced by
Doc comment for parameter "$em" missing
Loading history...
513
     * Returns an array with identifier column names and their corresponding ColumnMetadata.
514
     *
515
     * @return ColumnMetadata[]
516
     */
517 441
    public function getIdentifierColumns(EntityManagerInterface $em) : array
518
    {
519 441
        $columns = [];
520
521 441
        foreach ($this->identifier as $idProperty) {
522 441
            $property = $this->getProperty($idProperty);
523
524 441
            if ($property instanceof FieldMetadata) {
525 435
                $columns[$property->getColumnName()] = $property;
526
527 435
                continue;
528
            }
529
530
            /** @var AssociationMetadata $property */
531
532
            // Association defined as Id field
533 25
            $targetClass = $em->getClassMetadata($property->getTargetEntity());
534
535 25
            if (! $property->isOwningSide()) {
536
                $property    = $targetClass->getProperty($property->getMappedBy());
0 ignored issues
show
Bug introduced by
The method getProperty() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

536
                /** @scrutinizer ignore-call */ 
537
                $property    = $targetClass->getProperty($property->getMappedBy());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
537
                $targetClass = $em->getClassMetadata($property->getTargetEntity());
538
            }
539
540 25
            $joinColumns = $property instanceof ManyToManyAssociationMetadata
541
                ? $property->getJoinTable()->getInverseJoinColumns()
542 25
                : $property->getJoinColumns();
543
544 25
            foreach ($joinColumns as $joinColumn) {
545
                /** @var JoinColumnMetadata $joinColumn */
546 25
                $columnName           = $joinColumn->getColumnName();
547 25
                $referencedColumnName = $joinColumn->getReferencedColumnName();
548
549 25
                if (! $joinColumn->getType()) {
550 13
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $em));
551
                }
552
553 25
                $columns[$columnName] = $joinColumn;
554
            }
555
        }
556
557 441
        return $columns;
558
    }
559
560
    /**
561
     * Gets the name of the primary table.
562
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
563 1570
    public function getTableName() : ?string
564
    {
565 1570
        return $this->table->getName();
566
    }
567
568
    /**
569
     * Gets primary table's schema name.
570
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
571 23
    public function getSchemaName() : ?string
572
    {
573 23
        return $this->table->getSchema();
574
    }
575
576
    /**
577
     * Gets the table name to use for temporary identifier tables of this class.
578
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
579 7
    public function getTemporaryIdTableName() : string
580
    {
581 7
        $schema = $this->getSchemaName() === null
582 6
            ? ''
583 7
            : $this->getSchemaName() . '_';
584
585
        // replace dots with underscores because PostgreSQL creates temporary tables in a special schema
586 7
        return $schema . $this->getTableName() . '_id_tmp';
587
    }
588
589
    /**
590
     * Sets the mapped subclasses of this class.
591
     *
592
     * @param string[] $subclasses The names of all mapped subclasses.
593
     *
594
     * @todo guilhermeblanco Only used for ClassMetadataTest. Remove if possible!
595
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
596 4
    public function setSubclasses(array $subclasses) : void
597
    {
598 4
        foreach ($subclasses as $subclass) {
599 3
            $this->subClasses[] = $subclass;
600
        }
601 4
    }
602
603
    /**
604
     * @return string[]
605
     */
606 1080
    public function getSubClasses() : array
607
    {
608 1080
        return $this->subClasses;
609
    }
610
611
    /**
612
     * Sets the inheritance type used by the class and its subclasses.
613
     *
614
     * @param int $type
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
615
     *
616
     * @throws MappingException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
617
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
618 121
    public function setInheritanceType($type) : void
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::setInheritanceType() does not have parameter type hint for its parameter $type but it should be possible to add it based on @param annotation "int".
Loading history...
Coding Style introduced by
Type hint "int" missing for $type
Loading history...
619
    {
620 121
        if (! $this->isInheritanceType($type)) {
621
            throw MappingException::invalidInheritanceType($this->className, $type);
622
        }
623
624 121
        $this->inheritanceType = $type;
625 121
    }
626
627
    /**
0 ignored issues
show
Coding Style Documentation introduced by
Doc comment for parameter "$property" missing
Loading history...
628
     * Sets the override property mapping for an entity relationship.
629
     *
630
     * @throws RuntimeException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
631
     * @throws MappingException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
632
     * @throws CacheException
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
633
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @return tag in function comment
Loading history...
634 12
    public function setPropertyOverride(Property $property) : void
635
    {
636 12
        $fieldName = $property->getName();
637
638 12
        if (! isset($this->properties[$fieldName])) {
639 2
            throw MappingException::invalidOverrideFieldName($this->className, $fieldName);
640
        }
641
642 10
        $originalProperty          = $this->getProperty($fieldName);
643 10
        $originalPropertyClassName = get_class($originalProperty);
644
645
        // If moving from transient to persistent, assume it's a new property
646 10
        if ($originalPropertyClassName === TransientMetadata::class) {
647 1
            unset($this->properties[$fieldName]);
648
649 1
            $this->addProperty($property);
650
651 1
            return;
652
        }
653
654
        // Do not allow to change property type
655 9
        if ($originalPropertyClassName !== get_class($property)) {
656
            throw MappingException::invalidOverridePropertyType($this->className, $fieldName);
657
        }
658
659
        // Do not allow to change version property
660 9
        if ($originalProperty instanceof FieldMetadata && $originalProperty->isVersioned()) {
661
            throw MappingException::invalidOverrideVersionField($this->className, $fieldName);
662
        }
663
664 9
        unset($this->properties[$fieldName]);
665
666 9
        if ($property instanceof FieldMetadata) {
667
            // Unset defined fieldName prior to override
668 5
            unset($this->fieldNames[$originalProperty->getColumnName()]);
0 ignored issues
show
Bug introduced by
The method getColumnName() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\FieldMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

668
            unset($this->fieldNames[$originalProperty->/** @scrutinizer ignore-call */ getColumnName()]);
Loading history...
669
670
            // Revert what should not be allowed to change
671 5
            $property->setDeclaringClass($originalProperty->getDeclaringClass());
672 5
            $property->setPrimaryKey($originalProperty->isPrimaryKey());
673 9
        } elseif ($property instanceof AssociationMetadata) {
674
            // Unset all defined fieldNames prior to override
675 9
            if ($originalProperty instanceof ToOneAssociationMetadata && $originalProperty->isOwningSide()) {
676 5
                foreach ($originalProperty->getJoinColumns() as $joinColumn) {
677 5
                    unset($this->fieldNames[$joinColumn->getColumnName()]);
678
                }
679
            }
680
681
            // Override what it should be allowed to change
682 9
            if ($property->getInversedBy()) {
683 8
                $originalProperty->setInversedBy($property->getInversedBy());
0 ignored issues
show
Bug introduced by
The method setInversedBy() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

683
                $originalProperty->/** @scrutinizer ignore-call */ 
684
                                   setInversedBy($property->getInversedBy());
Loading history...
684
            }
685
686 9
            if ($property->getFetchMode() !== $originalProperty->getFetchMode()) {
0 ignored issues
show
Bug introduced by
The method getFetchMode() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

686
            if ($property->getFetchMode() !== $originalProperty->/** @scrutinizer ignore-call */ getFetchMode()) {
Loading history...
687 2
                $originalProperty->setFetchMode($property->getFetchMode());
0 ignored issues
show
Bug introduced by
The method setFetchMode() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

687
                $originalProperty->/** @scrutinizer ignore-call */ 
688
                                   setFetchMode($property->getFetchMode());
Loading history...
688
            }
689
690 9
            if ($originalProperty instanceof ToOneAssociationMetadata && $property->getJoinColumns()) {
0 ignored issues
show
Bug introduced by
The method getJoinColumns() does not exist on Doctrine\ORM\Mapping\AssociationMetadata. It seems like you code against a sub-type of Doctrine\ORM\Mapping\AssociationMetadata such as Doctrine\ORM\Mapping\ToOneAssociationMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

690
            if ($originalProperty instanceof ToOneAssociationMetadata && $property->/** @scrutinizer ignore-call */ getJoinColumns()) {
Loading history...
691 5
                $originalProperty->setJoinColumns($property->getJoinColumns());
692 8
            } elseif ($originalProperty instanceof ManyToManyAssociationMetadata && $property->getJoinTable()) {
0 ignored issues
show
Bug introduced by
The method getJoinTable() does not exist on Doctrine\ORM\Mapping\AssociationMetadata. It seems like you code against a sub-type of Doctrine\ORM\Mapping\AssociationMetadata such as Doctrine\ORM\Mapping\ManyToManyAssociationMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

692
            } elseif ($originalProperty instanceof ManyToManyAssociationMetadata && $property->/** @scrutinizer ignore-call */ getJoinTable()) {
Loading history...
693 8
                $originalProperty->setJoinTable($property->getJoinTable());
694
            }
695
696 9
            $property = $originalProperty;
697
        }
698
699 9
        $this->addProperty($property);
0 ignored issues
show
Bug introduced by
It seems like $property can also be of type null; however, parameter $property of Doctrine\ORM\Mapping\ClassMetadata::addProperty() does only seem to accept Doctrine\ORM\Mapping\Property, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

699
        $this->addProperty(/** @scrutinizer ignore-type */ $property);
Loading history...
700 9
    }
701
702
    /**
703
     * Checks if this entity is the root in any entity-inheritance-hierarchy.
704
     *
705
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
706
     */
707 336
    public function isRootEntity()
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::isRootEntity() does not have return type hint for its return value but it should be possible to add it based on @return annotation "bool".
Loading history...
708
    {
709 336
        return $this->className === $this->getRootClassName();
710
    }
711
712
    /**
713
     * Checks whether a mapped field is inherited from a superclass.
714
     *
715
     * @param string $fieldName
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
716
     *
717
     * @return bool TRUE if the field is inherited, FALSE otherwise.
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
718
     */
719 622
    public function isInheritedProperty($fieldName)
0 ignored issues
show
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::isInheritedProperty() does not have parameter type hint for its parameter $fieldName but it should be possible to add it based on @param annotation "string".
Loading history...
introduced by
Method \Doctrine\ORM\Mapping\ClassMetadata::isInheritedProperty() does not have return type hint for its return value but it should be possible to add it based on @return annotation "bool".
Loading history...
Coding Style introduced by
Type hint "string" missing for $fieldName
Loading history...
720
    {
721 622
        $declaringClass = $this->properties[$fieldName]->getDeclaringClass();
722 622
        if ($declaringClass === $this) {
0 ignored issues
show
introduced by
The condition $declaringClass === $this is always false.
Loading history...
723 614
            return false;
724 363
        } else if (! $declaringClass->isMappedSuperclass) {
725 361
            return true;
726
        }
727
728 3
        $parentClass = $this;
729 3
        while (($parentClass = $parentClass->getParent()) !== $declaringClass) {
730 1
            if (! $parentClass->isMappedSuperclass) {
731 1
                return true;
732
            }
733
        }
734
735 3
        return false;
736
    }
737
738
    /**
739
     * {@inheritdoc}
740
     */
741 431
    public function setTable(TableMetadata $table) : void
742
    {
743 431
        $this->table = $table;
744
745
        // Make sure inherited and declared properties reflect newly defined table
746 431
        foreach ($this->properties as $property) {
747
            switch (true) {
748 96
                case $property instanceof FieldMetadata:
749 96
                    $property->setTableName($property->getTableName() ?? $table->getName());
750 96
                    break;
751
752 42
                case $property instanceof ToOneAssociationMetadata:
753
                    // Resolve association join column table names
754 34
                    foreach ($property->getJoinColumns() as $joinColumn) {
755
                        /** @var JoinColumnMetadata $joinColumn */
756 34
                        $joinColumn->setTableName($joinColumn->getTableName() ?? $table->getName());
757
                    }
758
759 34
                    break;
760
            }
761
        }
762 431
    }
763
764
    /**
765
     * Checks whether the given type identifies an inheritance type.
766
     *
767
     * @param int $type
768
     *
769
     * @return bool TRUE if the given type identifies an inheritance type, FALSe otherwise.
770
     */
771 121
    private function isInheritanceType($type)
772
    {
773 121
        return $type === InheritanceType::NONE
774 94
            || $type === InheritanceType::SINGLE_TABLE
775 52
            || $type === InheritanceType::JOINED
776 121
            || $type === InheritanceType::TABLE_PER_CLASS;
777
    }
778
779 916
    public function getColumn(string $columnName) : ?LocalColumnMetadata
780
    {
781 916
        foreach ($this->properties as $property) {
782 916
            if ($property instanceof LocalColumnMetadata && $property->getColumnName() === $columnName) {
783 916
                return $property;
784
            }
785
        }
786
787
        return null;
788
    }
789
790
    /**
791
     * Add a property mapping.
792
     *
793
     * @throws RuntimeException
794
     * @throws MappingException
795
     * @throws CacheException
796
     * @throws ReflectionException
797
     */
798 418
    public function addProperty(Property $property) : void
799
    {
800 418
        $fieldName = $property->getName();
801
802
        // Check for empty field name
803 418
        if (empty($fieldName)) {
804 1
            throw MappingException::missingFieldName($this->className);
805
        }
806
807 417
        $property->setDeclaringClass($this);
808
809
        switch (true) {
810 417
            case $property instanceof FieldMetadata:
811 407
                if ($property->isVersioned()) {
812 20
                    $this->versionProperty = $property;
813
                }
814
815 407
                $this->fieldNames[$property->getColumnName()] = $property->getName();
816 407
                break;
817
818 275
            case $property instanceof ToOneAssociationMetadata:
819 241
                foreach ($property->getJoinColumns() as $joinColumnMetadata) {
820 233
                    $this->fieldNames[$joinColumnMetadata->getColumnName()] = $property->getName();
821
                }
822
823 241
                break;
824
825
            default:
826
                // Transient properties are ignored on purpose here! =)
827 178
                break;
828
        }
829
830 417
        if ($property->isPrimaryKey() && ! in_array($fieldName, $this->identifier, true)) {
831 396
            $this->identifier[] = $fieldName;
832
        }
833
834 417
        parent::addProperty($property);
835 417
    }
836
837
    /**
838
     * INTERNAL:
839
     * Adds a property mapping without completing/validating it.
840
     * This is mainly used to add inherited property mappings to derived classes.
841
     */
842 97
    public function addInheritedProperty(Property $property)
843
    {
844 97
        if (isset($this->properties[$property->getName()])) {
845 1
            throw MappingException::duplicateProperty($this->className, $this->getProperty($property->getName()));
0 ignored issues
show
Bug introduced by
It seems like $this->getProperty($property->getName()) can also be of type null; however, parameter $property of Doctrine\ORM\Mapping\Map...on::duplicateProperty() does only seem to accept Doctrine\ORM\Mapping\Property, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

845
            throw MappingException::duplicateProperty($this->className, /** @scrutinizer ignore-type */ $this->getProperty($property->getName()));
Loading history...
846
        }
847
848 97
        $declaringClass    = $property->getDeclaringClass();
849 97
        $inheritedProperty = $declaringClass->isMappedSuperclass ? clone $property : $property;
850
851 97
        if ($inheritedProperty instanceof FieldMetadata) {
852 96
            if (! $declaringClass->isMappedSuperclass) {
853 74
                $inheritedProperty->setTableName($property->getTableName());
0 ignored issues
show
Bug introduced by
The method getTableName() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\FieldMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

853
                $inheritedProperty->setTableName($property->/** @scrutinizer ignore-call */ getTableName());
Loading history...
854
            }
855
856 96
            if ($inheritedProperty->isVersioned()) {
857 4
                $this->versionProperty = $inheritedProperty;
858
            }
859
860 96
            $this->fieldNames[$property->getColumnName()] = $property->getName();
861 43
        } elseif ($inheritedProperty instanceof AssociationMetadata) {
862 42
            if ($declaringClass->isMappedSuperclass) {
863 10
                $inheritedProperty->setSourceEntity($this->className);
864
            }
865
866
            // Need to add inherited fieldNames
867 42
            if ($inheritedProperty instanceof ToOneAssociationMetadata && $inheritedProperty->isOwningSide()) {
868 35
                foreach ($inheritedProperty->getJoinColumns() as $joinColumn) {
869
                    /** @var JoinColumnMetadata $joinColumn */
870 34
                    $this->fieldNames[$joinColumn->getColumnName()] = $property->getName();
871
                }
872
            }
873
        }
874
875 97
        $this->properties[$property->getName()] = $inheritedProperty;
876 97
    }
877
878
    /**
879
     * Registers a custom repository class for the entity class.
880
     *
881
     * @param string|null $repositoryClassName The class name of the custom mapper.
882
     */
883 31
    public function setCustomRepositoryClassName(?string $repositoryClassName)
884
    {
885 31
        $this->customRepositoryClassName = $repositoryClassName;
886 31
    }
887
888 164
    public function getCustomRepositoryClassName() : ?string
889
    {
890 164
        return $this->customRepositoryClassName;
891
    }
892
893
    /**
894
     * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
895
     *
896
     * @param string $lifecycleEvent
897
     *
898
     * @return bool
899
     */
900
    public function hasLifecycleCallbacks($lifecycleEvent)
901
    {
902
        return isset($this->lifecycleCallbacks[$lifecycleEvent]);
903
    }
904
905
    /**
906
     * Gets the registered lifecycle callbacks for an event.
907
     *
908
     * @param string $event
909
     *
910
     * @return string[]
911
     */
912
    public function getLifecycleCallbacks($event) : array
913
    {
914
        return $this->lifecycleCallbacks[$event] ?? [];
915
    }
916
917
    /**
918
     * Adds a lifecycle callback for entities of this class.
919
     */
920 16
    public function addLifecycleCallback(string $eventName, string $methodName)
921
    {
922 16
        if (in_array($methodName, $this->lifecycleCallbacks[$eventName] ?? [], true)) {
923 3
            return;
924
        }
925
926 16
        $this->lifecycleCallbacks[$eventName][] = $methodName;
927 16
    }
928
929
    /**
930
     * Adds a entity listener for entities of this class.
931
     *
932
     * @param string $eventName The entity lifecycle event.
933
     * @param string $class     The listener class.
934
     * @param string $method    The listener callback method.
935
     *
936
     * @throws MappingException
937
     */
938 13
    public function addEntityListener(string $eventName, string $class, string $methodName) : void
939
    {
940
        $listener = [
941 13
            'class'  => $class,
942 13
            'method' => $methodName,
943
        ];
944
945 13
        if (! class_exists($class)) {
946 1
            throw MappingException::entityListenerClassNotFound($class, $this->className);
947
        }
948
949 12
        if (! method_exists($class, $methodName)) {
950 1
            throw MappingException::entityListenerMethodNotFound($class, $methodName, $this->className);
951
        }
952
953
        // Check if entity listener already got registered and ignore it if positive
954 11
        if (in_array($listener, $this->entityListeners[$eventName] ?? [], true)) {
955 5
            return;
956
        }
957
958 11
        $this->entityListeners[$eventName][] = $listener;
959 11
    }
960
961
    /**
962
     * Sets the discriminator column definition.
963
     *
964
     * @see getDiscriminatorColumn()
965
     *
966
     * @throws MappingException
967
     */
968 95
    public function setDiscriminatorColumn(DiscriminatorColumnMetadata $discriminatorColumn) : void
969
    {
970 95
        if (isset($this->fieldNames[$discriminatorColumn->getColumnName()])) {
971
            throw MappingException::duplicateColumnName($this->className, $discriminatorColumn->getColumnName());
972
        }
973
974 95
        $discriminatorColumn->setTableName($discriminatorColumn->getTableName() ?? $this->getTableName());
975
976 95
        $allowedTypeList = ['boolean', 'array', 'object', 'datetime', 'time', 'date'];
977
978 95
        if (in_array($discriminatorColumn->getTypeName(), $allowedTypeList, true)) {
979
            throw MappingException::invalidDiscriminatorColumnType($discriminatorColumn->getTypeName());
980
        }
981
982 95
        $this->discriminatorColumn = $discriminatorColumn;
983 95
    }
984
985
    /**
986
     * Sets the discriminator values used by this class.
987
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
988
     *
989
     * @param string[] $map
990
     *
991
     * @throws MappingException
992
     */
993 90
    public function setDiscriminatorMap(array $map) : void
994
    {
995 90
        foreach ($map as $value => $className) {
996 90
            $this->addDiscriminatorMapClass($value, $className);
997
        }
998 90
    }
999
1000
    /**
1001
     * Adds one entry of the discriminator map with a new class and corresponding name.
1002
     *
1003
     * @param string|int $name
1004
     *
1005
     * @throws MappingException
1006
     */
1007 90
    public function addDiscriminatorMapClass($name, string $className) : void
1008
    {
1009 90
        $this->discriminatorMap[$name] = $className;
1010
1011 90
        if ($this->className === $className) {
1012 76
            $this->discriminatorValue = $name;
1013
1014 76
            return;
1015
        }
1016
1017 89
        if (! (class_exists($className) || interface_exists($className))) {
1018
            throw MappingException::invalidClassInDiscriminatorMap($className, $this->className);
1019
        }
1020
1021 89
        if (is_subclass_of($className, $this->className) && ! in_array($className, $this->subClasses, true)) {
1022 84
            $this->subClasses[] = $className;
1023
        }
1024 89
    }
1025
1026 1031
    public function getValueGenerationPlan() : ValueGenerationPlan
1027
    {
1028 1031
        return $this->valueGenerationPlan;
1029
    }
1030
1031 368
    public function setValueGenerationPlan(ValueGenerationPlan $valueGenerationPlan) : void
1032
    {
1033 368
        $this->valueGenerationPlan = $valueGenerationPlan;
1034 368
    }
1035
1036 399
    public function checkPropertyDuplication(string $columnName) : bool
1037
    {
1038 399
        return isset($this->fieldNames[$columnName])
1039 399
            || ($this->discriminatorColumn !== null && $this->discriminatorColumn->getColumnName() === $columnName);
1040
    }
1041
1042
    /**
1043
     * Marks this class as read only, no change tracking is applied to it.
1044
     */
1045 2
    public function asReadOnly() : void
1046
    {
1047 2
        $this->readOnly = true;
1048 2
    }
1049
1050
    /**
1051
     * Whether this class is read only or not.
1052
     */
1053 447
    public function isReadOnly() : bool
1054
    {
1055 447
        return $this->readOnly;
1056
    }
1057
1058 1091
    public function isVersioned() : bool
1059
    {
1060 1091
        return $this->versionProperty !== null;
1061
    }
1062
1063
    /**
1064
     * Map Embedded Class
1065
     *
1066
     * @param mixed[] $mapping
1067
     *
1068
     * @throws MappingException
1069
     */
1070
    public function mapEmbedded(array $mapping) : void
0 ignored issues
show
Unused Code introduced by
The parameter $mapping is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1070
    public function mapEmbedded(/** @scrutinizer ignore-unused */ array $mapping) : void

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

Loading history...
1071
    {
1072
        /*if (isset($this->properties[$mapping['fieldName']])) {
1073
            throw MappingException::duplicateProperty($this->className, $this->getProperty($mapping['fieldName']));
1074
        }
1075
1076
        $this->embeddedClasses[$mapping['fieldName']] = [
1077
            'class'          => $this->fullyQualifiedClassName($mapping['class']),
1078
            'columnPrefix'   => $mapping['columnPrefix'],
1079
            'declaredField'  => $mapping['declaredField'] ?? null,
1080
            'originalField'  => $mapping['originalField'] ?? null,
1081
            'declaringClass' => $this,
1082
        ];*/
1083
    }
1084
1085
    /**
1086
     * Inline the embeddable class
1087
     *
1088
     * @param string $property
1089
     */
1090
    public function inlineEmbeddable($property, ClassMetadata $embeddable) : void
0 ignored issues
show
Unused Code introduced by
The parameter $property is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1090
    public function inlineEmbeddable(/** @scrutinizer ignore-unused */ $property, ClassMetadata $embeddable) : void

This check looks for 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 $embeddable is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1090
    public function inlineEmbeddable($property, /** @scrutinizer ignore-unused */ ClassMetadata $embeddable) : void

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

Loading history...
1091
    {
1092
        /*foreach ($embeddable->fieldMappings as $fieldName => $fieldMapping) {
1093
            $fieldMapping['fieldName']     = $property . "." . $fieldName;
1094
            $fieldMapping['originalClass'] = $fieldMapping['originalClass'] ?? $embeddable->getClassName();
1095
            $fieldMapping['originalField'] = $fieldMapping['originalField'] ?? $fieldName;
1096
            $fieldMapping['declaredField'] = isset($fieldMapping['declaredField'])
1097
                ? $property . '.' . $fieldMapping['declaredField']
1098
                : $property;
1099
1100
            if (! empty($this->embeddedClasses[$property]['columnPrefix'])) {
1101
                $fieldMapping['columnName'] = $this->embeddedClasses[$property]['columnPrefix'] . $fieldMapping['columnName'];
1102
            } elseif ($this->embeddedClasses[$property]['columnPrefix'] !== false) {
1103
                $fieldMapping['columnName'] = $this->namingStrategy->embeddedFieldToColumnName(
1104
                    $property,
1105
                    $fieldMapping['columnName'],
1106
                    $this->reflectionClass->getName(),
1107
                    $embeddable->reflectionClass->getName()
1108
                );
1109
            }
1110
1111
            $this->mapField($fieldMapping);
1112
        }*/
1113
    }
1114
}
1115