Failed Conditions
Push — master ( ddb3cd...4476ec )
by Marco
11:47
created

ClassMetadata::setPropertyOverride()   C

Complexity

Conditions 16
Paths 30

Size

Total Lines 66
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 16.1922

Importance

Changes 0
Metric Value
cc 16
eloc 32
nc 30
nop 1
dl 0
loc 66
ccs 30
cts 33
cp 0.9091
crap 16.1922
rs 5.8516
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Mapping;
6
7
use Doctrine\ORM\Cache\CacheException;
8
use Doctrine\ORM\EntityManagerInterface;
9
use Doctrine\ORM\Mapping\Factory\NamingStrategy;
10
use Doctrine\ORM\Reflection\ReflectionService;
11
use Doctrine\ORM\Sequencing\Planning\ValueGenerationPlan;
12
use Doctrine\ORM\Utility\PersisterHelper;
13
14
/**
15
 * A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
16
 * of an entity and its associations.
17
 *
18
 */
19
class ClassMetadata extends ComponentMetadata implements TableOwner
20
{
21
    /**
22
     * The name of the custom repository class used for the entity class.
23
     * (Optional).
24
     *
25
     * @var string
26
     */
27
    protected $customRepositoryClassName;
28
29
    /**
30
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
31
     *
32
     * @var bool
33
     */
34
    public $isMappedSuperclass = false;
35
36
    /**
37
     * READ-ONLY: Whether this class describes the mapping of an embeddable class.
38
     *
39
     * @var bool
40
     */
41
    public $isEmbeddedClass = false;
42
43
    /**
44
     * Whether this class describes the mapping of a read-only class.
45
     * That means it is never considered for change-tracking in the UnitOfWork.
46
     * It is a very helpful performance optimization for entities that are immutable,
47
     * either in your domain or through the relation database (coming from a view,
48
     * or a history table for example).
49
     *
50
     * @var bool
51
     */
52
    private $readOnly = false;
53
54
    /**
55
     * The names of all subclasses (descendants).
56
     *
57
     * @var string[]
58
     */
59
    protected $subClasses = [];
60
61
    /**
62
     * READ-ONLY: The names of all embedded classes based on properties.
63
     *
64
     * @var string[]
65
     */
66
    //public $embeddedClasses = [];
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
67
68
    /**
69
     * The named queries allowed to be called directly from Repository.
70
     *
71
     * @var string[]
72
     */
73
    protected $namedQueries = [];
74
75
    /**
76
     * READ-ONLY: The named native queries allowed to be called directly from Repository.
77
     *
78
     * A native SQL named query definition has the following structure:
79
     * <pre>
80
     * array(
81
     *     'name'               => <query name>,
82
     *     'query'              => <sql query>,
83
     *     'resultClass'        => <class of the result>,
84
     *     'resultSetMapping'   => <name of a SqlResultSetMapping>
85
     * )
86
     * </pre>
87
     *
88
     * @var string[][]
89
     */
90
    public $namedNativeQueries = [];
91
92
    /**
93
     * READ-ONLY: The mappings of the results of native SQL queries.
94
     *
95
     * A native result mapping definition has the following structure:
96
     * <pre>
97
     * array(
98
     *     'name'               => <result name>,
99
     *     'entities'           => array(<entity result mapping>),
100
     *     'columns'            => array(<column result mapping>)
101
     * )
102
     * </pre>
103
     *
104
     * @var mixed[][]
105
     */
106
    public $sqlResultSetMappings = [];
107
108
    /**
109
     * READ-ONLY: The registered lifecycle callbacks for entities of this class.
110
     *
111
     * @var string[][]
112
     */
113
    public $lifecycleCallbacks = [];
114
115
    /**
116
     * READ-ONLY: The registered entity listeners.
117
     *
118
     * @var mixed[][]
119
     */
120
    public $entityListeners = [];
121
122
    /**
123
     * READ-ONLY: The field names of all fields that are part of the identifier/primary key
124
     * of the mapped entity class.
125
     *
126
     * @var string[]
127
     */
128
    public $identifier = [];
129
130
    /**
131
     * READ-ONLY: The inheritance mapping type used by the class.
132
     *
133
     * @var string
134
     */
135
    public $inheritanceType = InheritanceType::NONE;
136
137
    /**
138
     * READ-ONLY: The policy used for change-tracking on entities of this class.
139
     *
140
     * @var string
141
     */
142
    public $changeTrackingPolicy = ChangeTrackingPolicy::DEFERRED_IMPLICIT;
143
144
    /**
145
     * READ-ONLY: The discriminator value of this class.
146
     *
147
     * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
148
     * where a discriminator column is used.</b>
149
     *
150
     * @var mixed
151
     *
152
     * @see discriminatorColumn
153
     */
154
    public $discriminatorValue;
155
156
    /**
157
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
158
     *
159
     * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
160
     * where a discriminator column is used.</b>
161
     *
162
     * @var string[]
163
     *
164
     * @see discriminatorColumn
165
     */
166
    public $discriminatorMap = [];
167
168
    /**
169
     * READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
170
     * inheritance mappings.
171
     *
172
     * @var DiscriminatorColumnMetadata
173
     */
174
    public $discriminatorColumn;
175
176
    /**
177
     * READ-ONLY: The primary table metadata.
178
     *
179
     * @var TableMetadata
180
     */
181
    public $table;
182
183
    /**
184
     * READ-ONLY: An array of field names. Used to look up field names from column names.
185
     * Keys are column names and values are field names.
186
     *
187
     * @var string[]
188
     */
189
    public $fieldNames = [];
190
191
    /**
192
     * READ-ONLY: The field which is used for versioning in optimistic locking (if any).
193
     *
194
     * @var FieldMetadata|null
195
     */
196
    public $versionProperty;
197
198
    /**
199
     * NamingStrategy determining the default column and table names.
200
     *
201
     * @var NamingStrategy
202
     */
203
    protected $namingStrategy;
204
205
    /**
206
     * Value generation plan is responsible for generating values for auto-generated fields.
207
     *
208
     * @var ValueGenerationPlan
209
     */
210
    protected $valueGenerationPlan;
211
212
    /**
213
     * Initializes a new ClassMetadata instance that will hold the object-relational mapping
214
     * metadata of the class with the given name.
215
     *
216
     * @param string $entityName The name of the entity class.
217
     */
218 428
    public function __construct(
219
        string $entityName,
220
        ClassMetadataBuildingContext $metadataBuildingContext
221
    ) {
222 428
        parent::__construct($entityName, $metadataBuildingContext);
223
224 428
        $this->namingStrategy = $metadataBuildingContext->getNamingStrategy();
225 428
    }
226
227 2
    public function setClassName(string $className)
228
    {
229 2
        $this->className = $className;
230 2
    }
231
232
    public function getColumnsIterator() : \ArrayIterator
233
    {
234
        $iterator = parent::getColumnsIterator();
235
236
        if ($this->discriminatorColumn) {
237
            $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

237
            $iterator->offsetSet($this->discriminatorColumn->getColumnName(), /** @scrutinizer ignore-type */ $this->discriminatorColumn);
Loading history...
238
        }
239
240
        return $iterator;
241
    }
242
243 11
    public function getAncestorsIterator() : \ArrayIterator
244
    {
245 11
        $ancestors = new \ArrayIterator();
246 11
        $parent    = $this;
247
248 11
        while (($parent = $parent->parent) !== null) {
249 8
            if ($parent instanceof ClassMetadata && $parent->isMappedSuperclass) {
250 1
                continue;
251
            }
252
253 7
            $ancestors->append($parent);
254
        }
255
256 11
        return $ancestors;
257
    }
258
259 1165
    public function getRootClassName() : string
260
    {
261 1165
        return ($this->parent instanceof ClassMetadata && ! $this->parent->isMappedSuperclass)
262 382
            ? $this->parent->getRootClassName()
263 1165
            : $this->className
264
        ;
265
    }
266
267
    /**
268
     * Handles metadata cloning nicely.
269
     */
270 13
    public function __clone()
271
    {
272 13
        if ($this->cache) {
273 12
            $this->cache = clone $this->cache;
274
        }
275
276 13
        foreach ($this->declaredProperties as $name => $property) {
277 13
            $this->declaredProperties[$name] = clone $property;
278
        }
279 13
    }
280
281
    /**
282
     * Creates a string representation of this instance.
283
     *
284
     * @return string The string representation of this instance.
285
     *
286
     * @todo Construct meaningful string representation.
287
     */
288
    public function __toString()
289
    {
290
        return __CLASS__ . '@' . spl_object_id($this);
291
    }
292
293
    /**
294
     * Determines which fields get serialized.
295
     *
296
     * It is only serialized what is necessary for best unserialization performance.
297
     * That means any metadata properties that are not set or empty or simply have
298
     * their default value are NOT serialized.
299
     *
300
     * Parts that are also NOT serialized because they can not be properly unserialized:
301
     * - reflectionClass
302
     *
303
     * @return string[] The names of all the fields that should be serialized.
304
     */
305 5
    public function __sleep()
306
    {
307 5
        $serialized = [];
308
309
        // This metadata is always serialized/cached.
310 5
        $serialized = array_merge($serialized, [
311 5
            'declaredProperties',
312
            'fieldNames',
313
            //'embeddedClasses',
314
            'identifier',
315
            'className',
316
            'parent',
317
            'table',
318
            'valueGenerationPlan',
319
        ]);
320
321
        // The rest of the metadata is only serialized if necessary.
322 5
        if ($this->changeTrackingPolicy !== ChangeTrackingPolicy::DEFERRED_IMPLICIT) {
323
            $serialized[] = 'changeTrackingPolicy';
324
        }
325
326 5
        if ($this->customRepositoryClassName) {
327 1
            $serialized[] = 'customRepositoryClassName';
328
        }
329
330 5
        if ($this->inheritanceType !== InheritanceType::NONE) {
331 1
            $serialized[] = 'inheritanceType';
332 1
            $serialized[] = 'discriminatorColumn';
333 1
            $serialized[] = 'discriminatorValue';
334 1
            $serialized[] = 'discriminatorMap';
335 1
            $serialized[] = 'subClasses';
336
        }
337
338 5
        if ($this->isMappedSuperclass) {
339
            $serialized[] = 'isMappedSuperclass';
340
        }
341
342 5
        if ($this->isEmbeddedClass) {
343
            $serialized[] = 'isEmbeddedClass';
344
        }
345
346 5
        if ($this->isVersioned()) {
347
            $serialized[] = 'versionProperty';
348
        }
349
350 5
        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...
351
            $serialized[] = 'lifecycleCallbacks';
352
        }
353
354 5
        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...
355 1
            $serialized[] = 'entityListeners';
356
        }
357
358 5
        if ($this->namedQueries) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->namedQueries 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...
359 1
            $serialized[] = 'namedQueries';
360
        }
361
362 5
        if ($this->namedNativeQueries) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->namedNativeQueries 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...
363
            $serialized[] = 'namedNativeQueries';
364
        }
365
366 5
        if ($this->sqlResultSetMappings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->sqlResultSetMappings 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...
367
            $serialized[] = 'sqlResultSetMappings';
368
        }
369
370 5
        if ($this->cache) {
371
            $serialized[] = 'cache';
372
        }
373
374 5
        if ($this->readOnly) {
375 1
            $serialized[] = 'readOnly';
376
        }
377
378 5
        return $serialized;
379
    }
380
381
    /**
382
     * Restores some state that can not be serialized/unserialized.
383
     */
384 1495
    public function wakeupReflection(ReflectionService $reflectionService) : void
385
    {
386
        // Restore ReflectionClass and properties
387 1495
        $this->reflectionClass = $reflectionService->getClass($this->className);
388
389 1495
        if (! $this->reflectionClass) {
390
            return;
391
        }
392
393 1495
        $this->className = $this->reflectionClass->getName();
394
395 1495
        foreach ($this->declaredProperties as $property) {
396
            /** @var Property $property */
397 1494
            $property->wakeupReflection($reflectionService);
398
        }
399 1495
    }
400
401
    /**
402
     * Validates Identifier.
403
     *
404
     * @throws MappingException
405
     */
406 351
    public function validateIdentifier() : void
407
    {
408 351
        if ($this->isMappedSuperclass || $this->isEmbeddedClass) {
409 25
            return;
410
        }
411
412
        // Verify & complete identifier mapping
413 351
        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...
414
            throw MappingException::identifierRequired($this->className);
415
        }
416
417 351
        $explicitlyGeneratedProperties = array_filter($this->declaredProperties, function (Property $property) : bool {
418 351
            return $property instanceof FieldMetadata
419 351
                && $property->isPrimaryKey()
420 351
                && $property->hasValueGenerator();
421 351
        });
422
423 351
        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...
introduced by
The condition $explicitlyGeneratedProp...isIdentifierComposite() can never be true.
Loading history...
424
            throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->className);
425
        }
426 351
    }
427
428
    /**
429
     * Validates association targets actually exist.
430
     *
431
     * @throws MappingException
432
     */
433 351
    public function validateAssociations() : void
434
    {
435 351
        array_map(
436 351
            function (Property $property) {
437 351
                if (! ($property instanceof AssociationMetadata)) {
438 349
                    return;
439
                }
440
441 242
                $targetEntity = $property->getTargetEntity();
442
443 242
                if (! class_exists($targetEntity)) {
444
                    throw MappingException::invalidTargetEntityClass($targetEntity, $this->className, $property->getName());
445
                }
446 351
            },
447 351
            $this->declaredProperties
448
        );
449 351
    }
450
451
    /**
452
     * Validates lifecycle callbacks.
453
     *
454
     * @throws MappingException
455
     */
456 351
    public function validateLifecycleCallbacks(ReflectionService $reflectionService) : void
457
    {
458 351
        foreach ($this->lifecycleCallbacks as $callbacks) {
459
            /** @var array $callbacks */
460 9
            foreach ($callbacks as $callbackFuncName) {
461 9
                if (! $reflectionService->hasPublicMethod($this->className, $callbackFuncName)) {
462 9
                    throw MappingException::lifecycleCallbackMethodNotFound($this->className, $callbackFuncName);
463
                }
464
            }
465
        }
466 351
    }
467
468
    /**
469
     * Sets the change tracking policy used by this class.
470
     */
471 99
    public function setChangeTrackingPolicy(string $policy) : void
472
    {
473 99
        $this->changeTrackingPolicy = $policy;
474 99
    }
475
476
    /**
477
     * Checks whether a field is part of the identifier/primary key field(s).
478
     *
479
     * @param string $fieldName The field name.
480
     *
481
     * @return bool TRUE if the field is part of the table identifier/primary key field(s), FALSE otherwise.
482
     */
483 949
    public function isIdentifier(string $fieldName) : bool
484
    {
485 949
        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...
486 1
            return false;
487
        }
488
489 948
        if (! $this->isIdentifierComposite()) {
490 944
            return $fieldName === $this->identifier[0];
491
        }
492
493 88
        return in_array($fieldName, $this->identifier, true);
494
    }
495
496 1120
    public function isIdentifierComposite() : bool
497
    {
498 1120
        return isset($this->identifier[1]);
499
    }
500
501
    /**
502
     * Gets the named query.
503
     *
504
     * @see ClassMetadata::$namedQueries
505
     *
506
     * @param string $queryName The query name.
507
     *
508
     * @throws MappingException
509
     */
510 3
    public function getNamedQuery($queryName) : string
511
    {
512 3
        if (! isset($this->namedQueries[$queryName])) {
513
            throw MappingException::queryNotFound($this->className, $queryName);
514
        }
515
516 3
        return $this->namedQueries[$queryName];
517
    }
518
519
    /**
520
     * Gets all named queries of the class.
521
     *
522
     * @return string[]
523
     */
524 98
    public function getNamedQueries() : array
525
    {
526 98
        return $this->namedQueries;
527
    }
528
529
    /**
530
     * Gets the named native query.
531
     *
532
     * @see ClassMetadata::$namedNativeQueries
533
     *
534
     * @param string $queryName The query name.
535
     *
536
     * @return string[]
537
     *
538
     * @throws MappingException
539
     */
540 15
    public function getNamedNativeQuery($queryName) : array
541
    {
542 15
        if (! isset($this->namedNativeQueries[$queryName])) {
543
            throw MappingException::queryNotFound($this->className, $queryName);
544
        }
545
546 15
        return $this->namedNativeQueries[$queryName];
547
    }
548
549
    /**
550
     * Gets all named native queries of the class.
551
     *
552
     * @return string[]
553
     */
554 3
    public function getNamedNativeQueries() : array
555
    {
556 3
        return $this->namedNativeQueries;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->namedNativeQueries returns the type array<mixed,string[]> which is incompatible with the documented return type string[].
Loading history...
557
    }
558
559
    /**
560
     * Gets the result set mapping.
561
     *
562
     * @see ClassMetadata::$sqlResultSetMappings
563
     *
564
     * @param string $name The result set mapping name.
565
     *
566
     * @return mixed[]
567
     *
568
     * @throws MappingException
569
     */
570 13
    public function getSqlResultSetMapping($name)
571
    {
572 13
        if (! isset($this->sqlResultSetMappings[$name])) {
573
            throw MappingException::resultMappingNotFound($this->className, $name);
574
        }
575
576 13
        return $this->sqlResultSetMappings[$name];
577
    }
578
579
    /**
580
     * Gets all sql result set mappings of the class.
581
     *
582
     * @return mixed[][]
583
     */
584 5
    public function getSqlResultSetMappings()
585
    {
586 5
        return $this->sqlResultSetMappings;
587
    }
588
589
    /**
590
     * Validates & completes the basic mapping information for field mapping.
591
     *
592
     * @throws MappingException If something is wrong with the mapping.
593
     */
594 385
    protected function validateAndCompleteFieldMapping(FieldMetadata $property)
595
    {
596 385
        $fieldName  = $property->getName();
597 385
        $columnName = $property->getColumnName();
598
599 385
        if (empty($columnName)) {
600 330
            $columnName = $this->namingStrategy->propertyToColumnName($fieldName, $this->className);
601
602 330
            $property->setColumnName($columnName);
603
        }
604
605 385
        if (! $this->isMappedSuperclass) {
606 380
            $property->setTableName($this->getTableName());
607
        }
608
609
        // Check for already declared column
610 385
        if (isset($this->fieldNames[$columnName]) ||
611 385
            ($this->discriminatorColumn !== null && $this->discriminatorColumn->getColumnName() === $columnName)) {
612
            throw MappingException::duplicateColumnName($this->className, $columnName);
613
        }
614
615
        // Complete id mapping
616 385
        if ($property->isPrimaryKey()) {
617 378
            if ($this->versionProperty !== null && $this->versionProperty->getName() === $fieldName) {
618
                throw MappingException::cannotVersionIdField($this->className, $fieldName);
619
            }
620
621 378
            if ($property->getType()->canRequireSQLConversion()) {
622
                throw MappingException::sqlConversionNotAllowedForPrimaryKeyProperties($property);
0 ignored issues
show
Bug introduced by
$property of type Doctrine\ORM\Mapping\FieldMetadata is incompatible with the type string expected by parameter $className of Doctrine\ORM\Mapping\Map...rPrimaryKeyProperties(). ( Ignorable by Annotation )

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

622
                throw MappingException::sqlConversionNotAllowedForPrimaryKeyProperties(/** @scrutinizer ignore-type */ $property);
Loading history...
Bug introduced by
The call to Doctrine\ORM\Mapping\Map...rPrimaryKeyProperties() has too few arguments starting with property. ( Ignorable by Annotation )

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

622
                throw MappingException::/** @scrutinizer ignore-call */ sqlConversionNotAllowedForPrimaryKeyProperties($property);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
623
            }
624
625 378
            if (! in_array($fieldName, $this->identifier, true)) {
626 378
                $this->identifier[] = $fieldName;
627
            }
628
        }
629
630 385
        $this->fieldNames[$columnName] = $fieldName;
631 385
    }
632
633
    /**
634
     * Validates & completes the basic mapping information for field mapping.
635
     *
636
     * @throws MappingException If something is wrong with the mapping.
637
     */
638 20
    protected function validateAndCompleteVersionFieldMapping(VersionFieldMetadata $property)
639
    {
640 20
        $this->versionProperty = $property;
641
642 20
        $options = $property->getOptions();
643
644 20
        if (isset($options['default'])) {
645
            return;
646
        }
647
648 20
        if (in_array($property->getTypeName(), ['integer', 'bigint', 'smallint'], true)) {
649 20
            $property->setOptions(array_merge($options, ['default' => 1]));
650
651 20
            return;
652
        }
653
654 1
        if ($property->getTypeName() === 'datetime') {
655 1
            $property->setOptions(array_merge($options, ['default' => 'CURRENT_TIMESTAMP']));
656
657 1
            return;
658
        }
659
660
        throw MappingException::unsupportedOptimisticLockingType($property->getType());
661
    }
662
663
    /**
664
     * Validates & completes the basic mapping information that is common to all
665
     * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
666
     *
667
     * @throws MappingException If something is wrong with the mapping.
668
     * @throws CacheException   If entity is not cacheable.
669
     */
670 265
    protected function validateAndCompleteAssociationMapping(AssociationMetadata $property)
671
    {
672 265
        $fieldName    = $property->getName();
673 265
        $targetEntity = $property->getTargetEntity();
674
675 265
        if (! $targetEntity) {
676
            throw MappingException::missingTargetEntity($fieldName);
677
        }
678
679 265
        $property->setSourceEntity($this->className);
680 265
        $property->setOwningSide($property->getMappedBy() === null);
681 265
        $property->setTargetEntity($targetEntity);
682
683
        // Complete id mapping
684 265
        if ($property->isPrimaryKey()) {
685 39
            if ($property->isOrphanRemoval()) {
686
                throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->className, $fieldName);
687
            }
688
689 39
            if (! in_array($property->getName(), $this->identifier, true)) {
690 39
                if ($property instanceof ToOneAssociationMetadata && count($property->getJoinColumns()) >= 2) {
691
                    throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
692
                        $property->getTargetEntity(),
693
                        $this->className,
694
                        $fieldName
695
                    );
696
                }
697
698 39
                $this->identifier[] = $property->getName();
699
            }
700
701 39
            if ($this->cache && ! $property->getCache()) {
702
                throw CacheException::nonCacheableEntityAssociation($this->className, $fieldName);
703
            }
704
705 39
            if ($property instanceof ToManyAssociationMetadata) {
706
                throw MappingException::illegalToManyIdentifierAssociation($this->className, $property->getName());
707
            }
708
        }
709
710
        // Cascades
711 265
        $cascadeTypes = ['remove', 'persist', 'refresh'];
712 265
        $cascades     = array_map('strtolower', $property->getCascade());
713
714 265
        if (in_array('all', $cascades, true)) {
715 4
            $cascades = $cascadeTypes;
716
        }
717
718 265
        if (count($cascades) !== count(array_intersect($cascades, $cascadeTypes))) {
719
            $diffCascades = array_diff($cascades, array_intersect($cascades, $cascadeTypes));
720
721
            throw MappingException::invalidCascadeOption($diffCascades, $this->className, $fieldName);
722
        }
723
724 265
        $property->setCascade($cascades);
725 265
    }
726
727
    /**
728
     * Validates & completes a to-one association mapping.
729
     *
730
     * @param ToOneAssociationMetadata $property The association mapping to validate & complete.
731
     *
732
     * @throws \RuntimeException
733
     * @throws MappingException
734
     */
735 231
    protected function validateAndCompleteToOneAssociationMetadata(ToOneAssociationMetadata $property)
736
    {
737 231
        $fieldName = $property->getName();
738
739 231
        if ($property->getJoinColumns()) {
740 164
            $property->setOwningSide(true);
741
        }
742
743 231
        if ($property->isOwningSide()) {
744 229
            if (empty($property->getJoinColumns())) {
745
                // Apply default join column
746 77
                $property->addJoinColumn(new JoinColumnMetadata());
747
            }
748
749 229
            $uniqueConstraintColumns = [];
750
751 229
            foreach ($property->getJoinColumns() as $joinColumn) {
752
                /** @var JoinColumnMetadata $joinColumn */
753 229
                if ($property instanceof OneToOneAssociationMetadata && $this->inheritanceType !== InheritanceType::SINGLE_TABLE) {
754 112
                    if (count($property->getJoinColumns()) === 1) {
755 110
                        if (! $property->isPrimaryKey()) {
756 110
                            $joinColumn->setUnique(true);
757
                        }
758
                    } else {
759 2
                        $uniqueConstraintColumns[] = $joinColumn->getColumnName();
760
                    }
761
                }
762
763 229
                $joinColumn->setTableName(! $this->isMappedSuperclass ? $this->getTableName() : null);
764
765 229
                if (! $joinColumn->getColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $joinColumn->getColumnName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
766 96
                    $joinColumn->setColumnName($this->namingStrategy->joinColumnName($fieldName, $this->className));
767
                }
768
769 229
                if (! $joinColumn->getReferencedColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $joinColumn->getReferencedColumnName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
770 77
                    $joinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
771
                }
772
773 229
                $this->fieldNames[$joinColumn->getColumnName()] = $fieldName;
774
            }
775
776 229
            if ($uniqueConstraintColumns) {
0 ignored issues
show
introduced by
The condition $uniqueConstraintColumns can never be true.
Loading history...
777 2
                if (! $this->table) {
778
                    throw new \RuntimeException(
779
                        'ClassMetadata::setTable() has to be called before defining a one to one relationship.'
780
                    );
781
                }
782
783 2
                $this->table->addUniqueConstraint(
784
                    [
785 2
                        'name'    => sprintf('%s_uniq', $fieldName),
786 2
                        'columns' => $uniqueConstraintColumns,
787
                        'options' => [],
788
                        'flags'   => [],
789
                    ]
790
                );
791
            }
792
        }
793
794 231
        if ($property->isOrphanRemoval()) {
795 9
            $cascades = $property->getCascade();
796
797 9
            if (! in_array('remove', $cascades, true)) {
798 8
                $cascades[] = 'remove';
799
800 8
                $property->setCascade($cascades);
801
            }
802
803
            // @todo guilhermeblanco where is this used?
804
            // @todo guilhermeblanco Shouldn￿'t we iterate through JoinColumns to set non-uniqueness?
805
            //$property->setUnique(false);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
806
        }
807
808 231
        if ($property->isPrimaryKey() && ! $property->isOwningSide()) {
809
            throw MappingException::illegalInverseIdentifierAssociation($this->className, $fieldName);
810
        }
811 231
    }
812
813
    /**
814
     * Validates & completes a to-many association mapping.
815
     *
816
     * @param ToManyAssociationMetadata $property The association mapping to validate & complete.
817
     *
818
     * @throws MappingException
819
     */
820 164
    protected function validateAndCompleteToManyAssociationMetadata(ToManyAssociationMetadata $property)
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

820
    protected function validateAndCompleteToManyAssociationMetadata(/** @scrutinizer ignore-unused */ ToManyAssociationMetadata $property)

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...
821
    {
822
        // Do nothing
823 164
    }
824
825
    /**
826
     * Validates & completes a one-to-one association mapping.
827
     *
828
     * @param OneToOneAssociationMetadata $property The association mapping to validate & complete.
829
     */
830 119
    protected function validateAndCompleteOneToOneMapping(OneToOneAssociationMetadata $property)
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

830
    protected function validateAndCompleteOneToOneMapping(/** @scrutinizer ignore-unused */ OneToOneAssociationMetadata $property)

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...
831
    {
832
        // Do nothing
833 119
    }
834
835
    /**
836
     * Validates & completes a many-to-one association mapping.
837
     *
838
     * @param ManyToOneAssociationMetadata $property The association mapping to validate & complete.
839
     *
840
     * @throws MappingException
841
     */
842 135
    protected function validateAndCompleteManyToOneMapping(ManyToOneAssociationMetadata $property)
843
    {
844
        // A many-to-one mapping is essentially a one-one backreference
845 135
        if ($property->isOrphanRemoval()) {
846
            throw MappingException::illegalOrphanRemoval($this->className, $property->getName());
847
        }
848 135
    }
849
850
    /**
851
     * Validates & completes a one-to-many association mapping.
852
     *
853
     * @param OneToManyAssociationMetadata $property The association mapping to validate & complete.
854
     *
855
     * @throws MappingException
856
     */
857 112
    protected function validateAndCompleteOneToManyMapping(OneToManyAssociationMetadata $property)
858
    {
859
        // OneToMany MUST be inverse side
860 112
        $property->setOwningSide(false);
861
862
        // OneToMany MUST have mappedBy
863 112
        if (! $property->getMappedBy()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $property->getMappedBy() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
864
            throw MappingException::oneToManyRequiresMappedBy($property->getName());
865
        }
866
867 112
        if ($property->isOrphanRemoval()) {
868 23
            $cascades = $property->getCascade();
869
870 23
            if (! in_array('remove', $cascades, true)) {
871 20
                $cascades[] = 'remove';
872
873 20
                $property->setCascade($cascades);
874
            }
875
        }
876 112
    }
877
878
    /**
879
     * Validates & completes a many-to-many association mapping.
880
     *
881
     * @param ManyToManyAssociationMetadata $property The association mapping to validate & complete.
882
     *
883
     * @throws MappingException
884
     */
885 103
    protected function validateAndCompleteManyToManyMapping(ManyToManyAssociationMetadata $property)
886
    {
887 103
        if ($property->isOwningSide()) {
888
            // owning side MUST have a join table
889 92
            $joinTable = $property->getJoinTable() ?: new JoinTableMetadata();
890
891 92
            $property->setJoinTable($joinTable);
892
893 92
            if (! $joinTable->getName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $joinTable->getName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
894 18
                $joinTableName = $this->namingStrategy->joinTableName(
895 18
                    $property->getSourceEntity(),
896 18
                    $property->getTargetEntity(),
897 18
                    $property->getName()
898
                );
899
900 18
                $joinTable->setName($joinTableName);
901
            }
902
903 92
            $selfReferencingEntityWithoutJoinColumns = $property->getSourceEntity() === $property->getTargetEntity() && ! $joinTable->hasColumns();
904
905 92
            if (! $joinTable->getJoinColumns()) {
906 16
                $referencedColumnName = $this->namingStrategy->referenceColumnName();
907 16
                $sourceReferenceName  = $selfReferencingEntityWithoutJoinColumns ? 'source' : $referencedColumnName;
908 16
                $columnName           = $this->namingStrategy->joinKeyColumnName($property->getSourceEntity(), $sourceReferenceName);
909 16
                $joinColumn           = new JoinColumnMetadata();
910
911 16
                $joinColumn->setColumnName($columnName);
912 16
                $joinColumn->setReferencedColumnName($referencedColumnName);
913 16
                $joinColumn->setOnDelete('CASCADE');
914
915 16
                $joinTable->addJoinColumn($joinColumn);
916
            }
917
918 92
            if (! $joinTable->getInverseJoinColumns()) {
919 16
                $referencedColumnName = $this->namingStrategy->referenceColumnName();
920 16
                $targetReferenceName  = $selfReferencingEntityWithoutJoinColumns ? 'target' : $referencedColumnName;
921 16
                $columnName           = $this->namingStrategy->joinKeyColumnName($property->getTargetEntity(), $targetReferenceName);
922 16
                $joinColumn           = new JoinColumnMetadata();
923
924 16
                $joinColumn->setColumnName($columnName);
925 16
                $joinColumn->setReferencedColumnName($referencedColumnName);
926 16
                $joinColumn->setOnDelete('CASCADE');
927
928 16
                $joinTable->addInverseJoinColumn($joinColumn);
929
            }
930
931 92
            foreach ($joinTable->getJoinColumns() as $joinColumn) {
932
                /** @var JoinColumnMetadata $joinColumn */
933 92
                if (! $joinColumn->getReferencedColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $joinColumn->getReferencedColumnName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
934 2
                    $joinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
935
                }
936
937 92
                $referencedColumnName = $joinColumn->getReferencedColumnName();
938
939 92
                if (! $joinColumn->getColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $joinColumn->getColumnName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
940 2
                    $columnName = $this->namingStrategy->joinKeyColumnName(
941 2
                        $property->getSourceEntity(),
942 2
                        $referencedColumnName
943
                    );
944
945 92
                    $joinColumn->setColumnName($columnName);
946
                }
947
            }
948
949 92
            foreach ($joinTable->getInverseJoinColumns() as $inverseJoinColumn) {
950
                /** @var JoinColumnMetadata $inverseJoinColumn */
951 92
                if (! $inverseJoinColumn->getReferencedColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $inverseJoinColumn->getReferencedColumnName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
952 2
                    $inverseJoinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
953
                }
954
955 92
                $referencedColumnName = $inverseJoinColumn->getReferencedColumnName();
956
957 92
                if (! $inverseJoinColumn->getColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $inverseJoinColumn->getColumnName() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
958 2
                    $columnName = $this->namingStrategy->joinKeyColumnName(
959 2
                        $property->getTargetEntity(),
960 2
                        $referencedColumnName
961
                    );
962
963 92
                    $inverseJoinColumn->setColumnName($columnName);
964
                }
965
            }
966
        }
967 103
    }
968
969
    /**
970
     * {@inheritDoc}
971
     */
972 326
    public function getIdentifierFieldNames()
973
    {
974 326
        return $this->identifier;
975
    }
976
977
    /**
978
     * Gets the name of the single id field. Note that this only works on
979
     * entity classes that have a single-field pk.
980
     *
981
     * @return string
982
     *
983
     * @throws MappingException If the class has a composite primary key.
984
     */
985 142
    public function getSingleIdentifierFieldName()
986
    {
987 142
        if ($this->isIdentifierComposite()) {
988
            throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->className);
989
        }
990
991 142
        if (! isset($this->identifier[0])) {
992
            throw MappingException::noIdDefined($this->className);
993
        }
994
995 142
        return $this->identifier[0];
996
    }
997
998
    /**
999
     * INTERNAL:
1000
     * Sets the mapped identifier/primary key fields of this class.
1001
     * Mainly used by the ClassMetadataFactory to assign inherited identifiers.
1002
     *
1003
     * @param mixed[] $identifier
1004
     */
1005 95
    public function setIdentifier(array $identifier)
1006
    {
1007 95
        $this->identifier = $identifier;
1008 95
    }
1009
1010
    /**
1011
     * {@inheritDoc}
1012
     */
1013 972
    public function getIdentifier()
1014
    {
1015 972
        return $this->identifier;
1016
    }
1017
1018
    /**
1019
     * {@inheritDoc}
1020
     */
1021 134
    public function hasField($fieldName)
1022
    {
1023 134
        return isset($this->declaredProperties[$fieldName])
1024 134
            && $this->declaredProperties[$fieldName] instanceof FieldMetadata;
1025
    }
1026
1027
    /**
1028
     * Returns an array with identifier column names and their corresponding ColumnMetadata.
1029
     *
1030
     * @return ColumnMetadata[]
1031
     */
1032 419
    public function getIdentifierColumns(EntityManagerInterface $em) : array
1033
    {
1034 419
        $columns = [];
1035
1036 419
        foreach ($this->identifier as $idProperty) {
1037 419
            $property = $this->getProperty($idProperty);
1038
1039 419
            if ($property instanceof FieldMetadata) {
1040 414
                $columns[$property->getColumnName()] = $property;
1041
1042 414
                continue;
1043
            }
1044
1045
            /** @var AssociationMetadata $property */
1046
1047
            // Association defined as Id field
1048 24
            $targetClass = $em->getClassMetadata($property->getTargetEntity());
1049
1050 24
            if (! $property->isOwningSide()) {
1051
                $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

1051
                /** @scrutinizer ignore-call */ 
1052
                $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...
1052
                $targetClass = $em->getClassMetadata($property->getTargetEntity());
1053
            }
1054
1055 24
            $joinColumns = $property instanceof ManyToManyAssociationMetadata
1056
                ? $property->getJoinTable()->getInverseJoinColumns()
1057 24
                : $property->getJoinColumns()
1058
            ;
1059
1060 24
            foreach ($joinColumns as $joinColumn) {
1061
                /** @var JoinColumnMetadata $joinColumn */
1062 24
                $columnName           = $joinColumn->getColumnName();
1063 24
                $referencedColumnName = $joinColumn->getReferencedColumnName();
1064
1065 24
                if (! $joinColumn->getType()) {
1066 12
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $em));
0 ignored issues
show
Bug introduced by
$targetClass of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn(). ( Ignorable by Annotation )

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

1066
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, /** @scrutinizer ignore-type */ $targetClass, $em));
Loading history...
1067
                }
1068
1069 24
                $columns[$columnName] = $joinColumn;
1070
            }
1071
        }
1072
1073 419
        return $columns;
1074
    }
1075
1076
    /**
1077
     * Gets the name of the primary table.
1078
     */
1079 1463
    public function getTableName() : ?string
1080
    {
1081 1463
        return $this->table->getName();
1082
    }
1083
1084
    /**
1085
     * Gets primary table's schema name.
1086
     */
1087 14
    public function getSchemaName() : ?string
1088
    {
1089 14
        return $this->table->getSchema();
1090
    }
1091
1092
    /**
1093
     * Gets the table name to use for temporary identifier tables of this class.
1094
     */
1095 7
    public function getTemporaryIdTableName() : string
1096
    {
1097 7
        $schema = $this->getSchemaName() === null
1098 6
            ? ''
1099 7
            : $this->getSchemaName() . '_'
1100
        ;
1101
1102
        // replace dots with underscores because PostgreSQL creates temporary tables in a special schema
1103 7
        return $schema . $this->getTableName() . '_id_tmp';
1104
    }
1105
1106
    /**
1107
     * Sets the mapped subclasses of this class.
1108
     *
1109
     * @todo guilhermeblanco Only used for ClassMetadataTest. Remove if possible!
1110
     *
1111
     * @param string[] $subclasses The names of all mapped subclasses.
1112
     */
1113 4
    public function setSubclasses(array $subclasses) : void
1114
    {
1115 4
        foreach ($subclasses as $subclass) {
1116 3
            $this->subClasses[] = $subclass;
1117
        }
1118 4
    }
1119
1120
    /**
1121
     * @return string[]
1122
     */
1123 999
    public function getSubClasses() : array
1124
    {
1125 999
        return $this->subClasses;
1126
    }
1127
1128
    /**
1129
     * Sets the inheritance type used by the class and its subclasses.
1130
     *
1131
     * @param int $type
1132
     *
1133
     * @throws MappingException
1134
     */
1135 114
    public function setInheritanceType($type) : void
1136
    {
1137 114
        if (! $this->isInheritanceType($type)) {
1138
            throw MappingException::invalidInheritanceType($this->className, $type);
1139
        }
1140
1141 114
        $this->inheritanceType = $type;
1142 114
    }
1143
1144
    /**
1145
     * Sets the override property mapping for an entity relationship.
1146
     *
1147
     * @throws \RuntimeException
1148
     * @throws MappingException
1149
     * @throws CacheException
1150
     */
1151 10
    public function setPropertyOverride(Property $property) : void
1152
    {
1153 10
        $fieldName = $property->getName();
1154
1155 10
        if (! isset($this->declaredProperties[$fieldName])) {
1156
            throw MappingException::invalidOverrideFieldName($this->className, $fieldName);
1157
        }
1158
1159 10
        $originalProperty          = $this->getProperty($fieldName);
1160 10
        $originalPropertyClassName = get_class($originalProperty);
1161
1162
        // If moving from transient to persistent, assume it's a new property
1163 10
        if ($originalPropertyClassName === TransientMetadata::class) {
1164 1
            unset($this->declaredProperties[$fieldName]);
1165
1166 1
            $this->addProperty($property);
1167
1168 1
            return;
1169
        }
1170
1171
        // Do not allow to change property type
1172 9
        if ($originalPropertyClassName !== get_class($property)) {
1173
            throw MappingException::invalidOverridePropertyType($this->className, $fieldName);
1174
        }
1175
1176
        // Do not allow to change version property
1177 9
        if ($originalProperty instanceof VersionFieldMetadata) {
1178
            throw MappingException::invalidOverrideVersionField($this->className, $fieldName);
1179
        }
1180
1181 9
        unset($this->declaredProperties[$fieldName]);
1182
1183 9
        if ($property instanceof FieldMetadata) {
1184
            // Unset defined fieldName prior to override
1185 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

1185
            unset($this->fieldNames[$originalProperty->/** @scrutinizer ignore-call */ getColumnName()]);
Loading history...
1186
1187
            // Revert what should not be allowed to change
1188 5
            $property->setDeclaringClass($originalProperty->getDeclaringClass());
1189 5
            $property->setPrimaryKey($originalProperty->isPrimaryKey());
1190 9
        } elseif ($property instanceof AssociationMetadata) {
1191
            // Unset all defined fieldNames prior to override
1192 9
            if ($originalProperty instanceof ToOneAssociationMetadata && $originalProperty->isOwningSide()) {
1193 5
                foreach ($originalProperty->getJoinColumns() as $joinColumn) {
1194 5
                    unset($this->fieldNames[$joinColumn->getColumnName()]);
1195
                }
1196
            }
1197
1198
            // Override what it should be allowed to change
1199 9
            if ($property->getInversedBy()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $property->getInversedBy() of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1200 2
                $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

1200
                $originalProperty->/** @scrutinizer ignore-call */ 
1201
                                   setInversedBy($property->getInversedBy());
Loading history...
1201
            }
1202
1203 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

1203
            if ($property->getFetchMode() !== $originalProperty->/** @scrutinizer ignore-call */ getFetchMode()) {
Loading history...
1204 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

1204
                $originalProperty->/** @scrutinizer ignore-call */ 
1205
                                   setFetchMode($property->getFetchMode());
Loading history...
1205
            }
1206
1207 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

1207
            if ($originalProperty instanceof ToOneAssociationMetadata && $property->/** @scrutinizer ignore-call */ getJoinColumns()) {
Loading history...
1208 5
                $originalProperty->setJoinColumns($property->getJoinColumns());
1209 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

1209
            } elseif ($originalProperty instanceof ManyToManyAssociationMetadata && $property->/** @scrutinizer ignore-call */ getJoinTable()) {
Loading history...
1210 4
                $originalProperty->setJoinTable($property->getJoinTable());
1211
            }
1212
1213 9
            $property = $originalProperty;
1214
        }
1215
1216 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

1216
        $this->addProperty(/** @scrutinizer ignore-type */ $property);
Loading history...
1217 9
    }
1218
1219
    /**
1220
     * Checks if this entity is the root in any entity-inheritance-hierarchy.
1221
     *
1222
     * @return bool
1223
     */
1224 317
    public function isRootEntity()
1225
    {
1226 317
        return $this->className === $this->getRootClassName();
1227
    }
1228
1229
    /**
1230
     * Checks whether a mapped field is inherited from a superclass.
1231
     *
1232
     * @param string $fieldName
1233
     *
1234
     * @return bool TRUE if the field is inherited, FALSE otherwise.
1235
     */
1236 547
    public function isInheritedProperty($fieldName)
1237
    {
1238 547
        $declaringClass = $this->declaredProperties[$fieldName]->getDeclaringClass();
1239
1240 547
        return ! ($declaringClass->className === $this->className);
1241
    }
1242
1243
    /**
1244
     * {@inheritdoc}
1245
     */
1246 412
    public function setTable(TableMetadata $table) : void
1247
    {
1248 412
        $this->table = $table;
1249
1250 412
        if (empty($table->getName())) {
1251
            $table->setName($this->namingStrategy->classToTableName($this->className));
1252
        }
1253 412
    }
1254
1255
    /**
1256
     * Checks whether the given type identifies an inheritance type.
1257
     *
1258
     * @param int $type
1259
     *
1260
     * @return bool TRUE if the given type identifies an inheritance type, FALSe otherwise.
1261
     */
1262 114
    private function isInheritanceType($type)
1263
    {
1264 114
        return $type === InheritanceType::NONE
1265 90
            || $type === InheritanceType::SINGLE_TABLE
1266 51
            || $type === InheritanceType::JOINED
1267 114
            || $type === InheritanceType::TABLE_PER_CLASS;
1268
    }
1269
1270 842
    public function getColumn(string $columnName) : ?LocalColumnMetadata
1271
    {
1272 842
        foreach ($this->declaredProperties as $property) {
1273 842
            if ($property instanceof LocalColumnMetadata && $property->getColumnName() === $columnName) {
1274 842
                return $property;
1275
            }
1276
        }
1277
1278
        return null;
1279
    }
1280
1281
    /**
1282
     * Add a property mapping.
1283
     *
1284
     * @throws \RuntimeException
1285
     * @throws MappingException
1286
     * @throws CacheException
1287
     */
1288 398
    public function addProperty(Property $property)
1289
    {
1290 398
        $fieldName = $property->getName();
1291
1292
        // Check for empty field name
1293 398
        if (empty($fieldName)) {
1294
            throw MappingException::missingFieldName($this->className);
1295
        }
1296
1297 398
        $property->setDeclaringClass($this);
1298
1299
        switch (true) {
1300 398
            case ($property instanceof VersionFieldMetadata):
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1301 20
                $this->validateAndCompleteFieldMapping($property);
1302 20
                $this->validateAndCompleteVersionFieldMapping($property);
1303 20
                break;
1304
1305 398
            case ($property instanceof FieldMetadata):
1306 385
                $this->validateAndCompleteFieldMapping($property);
1307 385
                break;
1308
1309 268
            case ($property instanceof OneToOneAssociationMetadata):
1310 119
                $this->validateAndCompleteAssociationMapping($property);
1311 119
                $this->validateAndCompleteToOneAssociationMetadata($property);
1312 119
                $this->validateAndCompleteOneToOneMapping($property);
1313 119
                break;
1314
1315 212
            case ($property instanceof OneToManyAssociationMetadata):
1316 112
                $this->validateAndCompleteAssociationMapping($property);
1317 112
                $this->validateAndCompleteToManyAssociationMetadata($property);
1318 112
                $this->validateAndCompleteOneToManyMapping($property);
1319 112
                break;
1320
1321 208
            case ($property instanceof ManyToOneAssociationMetadata):
1322 135
                $this->validateAndCompleteAssociationMapping($property);
1323 135
                $this->validateAndCompleteToOneAssociationMetadata($property);
1324 135
                $this->validateAndCompleteManyToOneMapping($property);
1325 135
                break;
1326
1327 120
            case ($property instanceof ManyToManyAssociationMetadata):
1328 103
                $this->validateAndCompleteAssociationMapping($property);
1329 103
                $this->validateAndCompleteToManyAssociationMetadata($property);
1330 103
                $this->validateAndCompleteManyToManyMapping($property);
1331 103
                break;
1332
1333
            default:
1334
                // Transient properties are ignored on purpose here! =)
1335 32
                break;
1336
        }
1337
1338 398
        $this->addDeclaredProperty($property);
1339 398
    }
1340
1341
    /**
1342
     * INTERNAL:
1343
     * Adds a property mapping without completing/validating it.
1344
     * This is mainly used to add inherited property mappings to derived classes.
1345
     */
1346 94
    public function addInheritedProperty(Property $property)
1347
    {
1348 94
        $inheritedProperty = clone $property;
1349 94
        $declaringClass    = $property->getDeclaringClass();
1350
1351 94
        if ($inheritedProperty instanceof FieldMetadata) {
1352 94
            if (! $declaringClass->isMappedSuperclass) {
1353 73
                $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

1353
                $inheritedProperty->setTableName($property->/** @scrutinizer ignore-call */ getTableName());
Loading history...
1354
            }
1355
1356 94
            $this->fieldNames[$property->getColumnName()] = $property->getName();
1357 41
        } elseif ($inheritedProperty instanceof AssociationMetadata) {
1358 40
            if ($declaringClass->isMappedSuperclass) {
1359 10
                $inheritedProperty->setSourceEntity($this->className);
1360
            }
1361
1362
            // Need to add inherited fieldNames
1363 40
            if ($inheritedProperty instanceof ToOneAssociationMetadata && $inheritedProperty->isOwningSide()) {
1364 33
                foreach ($inheritedProperty->getJoinColumns() as $joinColumn) {
1365
                    /** @var JoinColumnMetadata $joinColumn */
1366 33
                    $this->fieldNames[$joinColumn->getColumnName()] = $property->getName();
1367
                }
1368
            }
1369
        }
1370
1371 94
        if (isset($this->declaredProperties[$property->getName()])) {
1372
            throw MappingException::duplicateProperty($this->className, $this->getProperty($property->getName()));
1373
        }
1374
1375 94
        $this->declaredProperties[$property->getName()] = $inheritedProperty;
1376
1377 94
        if ($inheritedProperty instanceof VersionFieldMetadata) {
1378 4
            $this->versionProperty = $inheritedProperty;
1379
        }
1380 94
    }
1381
1382
    /**
1383
     * INTERNAL:
1384
     * Adds a named query to this class.
1385
     *
1386
     * @throws MappingException
1387
     */
1388 19
    public function addNamedQuery(string $name, string $query)
1389
    {
1390 19
        if (isset($this->namedQueries[$name])) {
1391
            throw MappingException::duplicateQueryMapping($this->className, $name);
1392
        }
1393
1394 19
        $this->namedQueries[$name] = $query;
1395 19
    }
1396
1397
    /**
1398
     * INTERNAL:
1399
     * Adds a named native query to this class.
1400
     *
1401
     * @param mixed[] $queryMapping
1402
     *
1403
     * @throws MappingException
1404
     */
1405 23
    public function addNamedNativeQuery(string $name, string $query, array $queryMapping)
1406
    {
1407 23
        if (isset($this->namedNativeQueries[$name])) {
1408
            throw MappingException::duplicateQueryMapping($this->className, $name);
1409
        }
1410
1411 23
        if (! isset($queryMapping['resultClass']) && ! isset($queryMapping['resultSetMapping'])) {
1412
            throw MappingException::missingQueryMapping($this->className, $name);
1413
        }
1414
1415 23
        $this->namedNativeQueries[$name] = array_merge(['query' => $query], $queryMapping);
1416 23
    }
1417
1418
    /**
1419
     * INTERNAL:
1420
     * Adds a sql result set mapping to this class.
1421
     *
1422
     * @param mixed[] $resultMapping
1423
     *
1424
     * @throws MappingException
1425
     */
1426 22
    public function addSqlResultSetMapping(array $resultMapping)
1427
    {
1428 22
        if (! isset($resultMapping['name'])) {
1429
            throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->className);
1430
        }
1431
1432 22
        if (isset($this->sqlResultSetMappings[$resultMapping['name']])) {
1433
            throw MappingException::duplicateResultSetMapping($this->className, $resultMapping['name']);
1434
        }
1435
1436 22
        if (isset($resultMapping['entities'])) {
1437 22
            foreach ($resultMapping['entities'] as $key => $entityResult) {
1438 22
                if (! isset($entityResult['entityClass'])) {
1439
                    throw MappingException::missingResultSetMappingEntity($this->className, $resultMapping['name']);
1440
                }
1441
1442 22
                $entityClassName                                = $entityResult['entityClass'];
1443 22
                $resultMapping['entities'][$key]['entityClass'] = $entityClassName;
1444
1445 22
                if (isset($entityResult['fields'])) {
1446 19
                    foreach ($entityResult['fields'] as $k => $field) {
1447 19
                        if (! isset($field['name'])) {
1448
                            throw MappingException::missingResultSetMappingFieldName($this->className, $resultMapping['name']);
1449
                        }
1450
1451 19
                        if (! isset($field['column'])) {
1452 11
                            $fieldName = $field['name'];
1453
1454 11
                            if (strpos($fieldName, '.')) {
1455 6
                                list(, $fieldName) = explode('.', $fieldName);
1456
                            }
1457
1458 22
                            $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
1459
                        }
1460
                    }
1461
                }
1462
            }
1463
        }
1464
1465 22
        $this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping;
1466 22
    }
1467
1468
    /**
1469
     * Registers a custom repository class for the entity class.
1470
     *
1471
     * @param string|null $repositoryClassName The class name of the custom mapper.
1472
     */
1473 28
    public function setCustomRepositoryClassName(?string $repositoryClassName)
1474
    {
1475 28
        $this->customRepositoryClassName = $repositoryClassName;
1476 28
    }
1477
1478 155
    public function getCustomRepositoryClassName() : ?string
1479
    {
1480 155
        return $this->customRepositoryClassName;
1481
    }
1482
1483
    /**
1484
     * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
1485
     *
1486
     * @param string $lifecycleEvent
1487
     *
1488
     * @return bool
1489
     */
1490
    public function hasLifecycleCallbacks($lifecycleEvent)
1491
    {
1492
        return isset($this->lifecycleCallbacks[$lifecycleEvent]);
1493
    }
1494
1495
    /**
1496
     * Gets the registered lifecycle callbacks for an event.
1497
     *
1498
     * @param string $event
1499
     *
1500
     * @return string[]
1501
     */
1502
    public function getLifecycleCallbacks($event)
1503
    {
1504
        return $this->lifecycleCallbacks[$event] ?? [];
1505
    }
1506
1507
    /**
1508
     * Adds a lifecycle callback for entities of this class.
1509
     *
1510
     * @param string $callback
1511
     * @param string $event
1512
     */
1513 17
    public function addLifecycleCallback($callback, $event)
1514
    {
1515 17
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event], true)) {
1516 3
            return;
1517
        }
1518
1519 17
        $this->lifecycleCallbacks[$event][] = $callback;
1520 17
    }
1521
1522
    /**
1523
     * Sets the lifecycle callbacks for entities of this class.
1524
     * Any previously registered callbacks are overwritten.
1525
     *
1526
     * @param string[][] $callbacks
1527
     */
1528 94
    public function setLifecycleCallbacks(array $callbacks) : void
1529
    {
1530 94
        $this->lifecycleCallbacks = $callbacks;
1531 94
    }
1532
1533
    /**
1534
     * Adds a entity listener for entities of this class.
1535
     *
1536
     * @param string $eventName The entity lifecycle event.
1537
     * @param string $class     The listener class.
1538
     * @param string $method    The listener callback method.
1539
     *
1540
     * @throws \Doctrine\ORM\Mapping\MappingException
1541
     */
1542 15
    public function addEntityListener(string $eventName, string $class, string $method) : void
1543
    {
1544
        $listener = [
1545 15
            'class'  => $class,
1546 15
            'method' => $method,
1547
        ];
1548
1549 15
        if (! class_exists($class)) {
1550
            throw MappingException::entityListenerClassNotFound($class, $this->className);
1551
        }
1552
1553 15
        if (! method_exists($class, $method)) {
1554
            throw MappingException::entityListenerMethodNotFound($class, $method, $this->className);
1555
        }
1556
1557 15
        if (isset($this->entityListeners[$eventName]) && in_array($listener, $this->entityListeners[$eventName], true)) {
1558
            throw MappingException::duplicateEntityListener($class, $method, $this->className);
1559
        }
1560
1561 15
        $this->entityListeners[$eventName][] = $listener;
1562 15
    }
1563
1564
    /**
1565
     * Sets the discriminator column definition.
1566
     *
1567
     * @throws MappingException
1568
     *
1569
     * @see getDiscriminatorColumn()
1570
     */
1571 90
    public function setDiscriminatorColumn(DiscriminatorColumnMetadata $discriminatorColumn) : void
1572
    {
1573 90
        if (isset($this->fieldNames[$discriminatorColumn->getColumnName()])) {
1574
            throw MappingException::duplicateColumnName($this->className, $discriminatorColumn->getColumnName());
1575
        }
1576
1577 90
        $discriminatorColumn->setTableName($discriminatorColumn->getTableName() ?? $this->getTableName());
1578
1579 90
        $allowedTypeList = ['boolean', 'array', 'object', 'datetime', 'time', 'date'];
1580
1581 90
        if (in_array($discriminatorColumn->getTypeName(), $allowedTypeList, true)) {
1582
            throw MappingException::invalidDiscriminatorColumnType($discriminatorColumn->getTypeName());
1583
        }
1584
1585 90
        $this->discriminatorColumn = $discriminatorColumn;
1586 90
    }
1587
1588
    /**
1589
     * Sets the discriminator values used by this class.
1590
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
1591
     *
1592
     * @param string[] $map
1593
     *
1594
     * @throws MappingException
1595
     */
1596 89
    public function setDiscriminatorMap(array $map) : void
1597
    {
1598 89
        foreach ($map as $value => $className) {
1599 89
            $this->addDiscriminatorMapClass($value, $className);
1600
        }
1601 89
    }
1602
1603
    /**
1604
     * Adds one entry of the discriminator map with a new class and corresponding name.
1605
     *
1606
     * @param string|int $name
1607
     *
1608
     * @throws MappingException
1609
     */
1610 89
    public function addDiscriminatorMapClass($name, string $className) : void
1611
    {
1612 89
        $this->discriminatorMap[$name] = $className;
1613
1614 89
        if ($this->className === $className) {
1615 75
            $this->discriminatorValue = $name;
1616
1617 75
            return;
1618
        }
1619
1620 88
        if (! (class_exists($className) || interface_exists($className))) {
1621
            throw MappingException::invalidClassInDiscriminatorMap($className, $this->className);
1622
        }
1623
1624 88
        if (is_subclass_of($className, $this->className) && ! in_array($className, $this->subClasses, true)) {
1625 83
            $this->subClasses[] = $className;
1626
        }
1627 88
    }
1628
1629 958
    public function getValueGenerationPlan() : ValueGenerationPlan
1630
    {
1631 958
        return $this->valueGenerationPlan;
1632
    }
1633
1634 351
    public function setValueGenerationPlan(ValueGenerationPlan $valueGenerationPlan) : void
1635
    {
1636 351
        $this->valueGenerationPlan = $valueGenerationPlan;
1637 351
    }
1638
1639
    /**
1640
     * Checks whether the class has a named query with the given query name.
1641
     *
1642
     * @param string $queryName
1643
     */
1644 2
    public function hasNamedQuery($queryName) : bool
1645
    {
1646 2
        return isset($this->namedQueries[$queryName]);
1647
    }
1648
1649
    /**
1650
     * Checks whether the class has a named native query with the given query name.
1651
     *
1652
     * @param string $queryName
1653
     */
1654 1
    public function hasNamedNativeQuery($queryName) : bool
1655
    {
1656 1
        return isset($this->namedNativeQueries[$queryName]);
1657
    }
1658
1659
    /**
1660
     * Checks whether the class has a named native query with the given query name.
1661
     *
1662
     * @param string $name
1663
     */
1664 1
    public function hasSqlResultSetMapping($name) : bool
1665
    {
1666 1
        return isset($this->sqlResultSetMappings[$name]);
1667
    }
1668
1669
    /**
1670
     * Marks this class as read only, no change tracking is applied to it.
1671
     */
1672 2
    public function asReadOnly() : void
1673
    {
1674 2
        $this->readOnly = true;
1675 2
    }
1676
1677
    /**
1678
     * Whether this class is read only or not.
1679
     */
1680 422
    public function isReadOnly() : bool
1681
    {
1682 422
        return $this->readOnly;
1683
    }
1684
1685 976
    public function isVersioned() : bool
1686
    {
1687 976
        return $this->versionProperty !== null;
1688
    }
1689
1690
    /**
1691
     * Map Embedded Class
1692
     *
1693
     * @param mixed[] $mapping
1694
     *
1695
     * @throws MappingException
1696
     */
1697
    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

1697
    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...
1698
    {
1699
        /*if (isset($this->declaredProperties[$mapping['fieldName']])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1700
            throw MappingException::duplicateProperty($this->className, $this->getProperty($mapping['fieldName']));
1701
        }
1702
1703
        $this->embeddedClasses[$mapping['fieldName']] = [
1704
            'class'          => $this->fullyQualifiedClassName($mapping['class']),
1705
            'columnPrefix'   => $mapping['columnPrefix'],
1706
            'declaredField'  => $mapping['declaredField'] ?? null,
1707
            'originalField'  => $mapping['originalField'] ?? null,
1708
            'declaringClass' => $this,
1709
        ];*/
1710
    }
1711
1712
    /**
1713
     * Inline the embeddable class
1714
     *
1715
     * @param string $property
1716
     */
1717
    public function inlineEmbeddable($property, ClassMetadata $embeddable) : void
0 ignored issues
show
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

1717
    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...
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

1717
    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...
1718
    {
1719
        /*foreach ($embeddable->fieldMappings as $fieldName => $fieldMapping) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1720
            $fieldMapping['fieldName']     = $property . "." . $fieldName;
1721
            $fieldMapping['originalClass'] = $fieldMapping['originalClass'] ?? $embeddable->getClassName();
1722
            $fieldMapping['originalField'] = $fieldMapping['originalField'] ?? $fieldName;
1723
            $fieldMapping['declaredField'] = isset($fieldMapping['declaredField'])
1724
                ? $property . '.' . $fieldMapping['declaredField']
1725
                : $property;
1726
1727
            if (! empty($this->embeddedClasses[$property]['columnPrefix'])) {
1728
                $fieldMapping['columnName'] = $this->embeddedClasses[$property]['columnPrefix'] . $fieldMapping['columnName'];
1729
            } elseif ($this->embeddedClasses[$property]['columnPrefix'] !== false) {
1730
                $fieldMapping['columnName'] = $this->namingStrategy->embeddedFieldToColumnName(
1731
                    $property,
1732
                    $fieldMapping['columnName'],
1733
                    $this->reflectionClass->getName(),
1734
                    $embeddable->reflectionClass->getName()
1735
                );
1736
            }
1737
1738
            $this->mapField($fieldMapping);
1739
        }*/
1740
    }
1741
}
1742