Failed Conditions
Pull Request — master (#6959)
by Matthew
12:08
created

validateAndCompleteAssociationMapping()   C

Complexity

Conditions 12
Paths 19

Size

Total Lines 55
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 12.667

Importance

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

230
            $iterator->offsetSet($this->discriminatorColumn->getColumnName(), /** @scrutinizer ignore-type */ $this->discriminatorColumn);
Loading history...
231
        }
232
233
        return $iterator;
234
    }
235
236 11
    public function getAncestorsIterator() : \ArrayIterator
237
    {
238 11
        $ancestors = new \ArrayIterator();
239 11
        $parent    = $this;
240
241 11
        while (($parent = $parent->parent) !== null) {
242 8
            if ($parent instanceof ClassMetadata && $parent->isMappedSuperclass) {
243 1
                continue;
244
            }
245
246 7
            $ancestors->append($parent);
247
        }
248
249 11
        return $ancestors;
250
    }
251
252 1253
    public function getRootClassName() : string
253
    {
254 1253
        return ($this->parent instanceof ClassMetadata && ! $this->parent->isMappedSuperclass)
255 399
            ? $this->parent->getRootClassName()
256 1253
            : $this->className
257
        ;
258
    }
259
260
    /**
261
     * Handles metadata cloning nicely.
262
     */
263 13
    public function __clone()
264
    {
265 13
        if ($this->cache) {
266 12
            $this->cache = clone $this->cache;
267
        }
268
269 13
        foreach ($this->declaredProperties as $name => $property) {
270 13
            $this->declaredProperties[$name] = clone $property;
271
        }
272 13
    }
273
274
    /**
275
     * Creates a string representation of this instance.
276
     *
277
     * @return string The string representation of this instance.
278
     *
279
     * @todo Construct meaningful string representation.
280
     */
281
    public function __toString()
282
    {
283
        return __CLASS__ . '@' . spl_object_id($this);
284
    }
285
286
    /**
287
     * Determines which fields get serialized.
288
     *
289
     * It is only serialized what is necessary for best unserialization performance.
290
     * That means any metadata properties that are not set or empty or simply have
291
     * their default value are NOT serialized.
292
     *
293
     * Parts that are also NOT serialized because they can not be properly unserialized:
294
     * - reflectionClass
295
     *
296
     * @return string[] The names of all the fields that should be serialized.
297
     */
298 5
    public function __sleep()
299
    {
300 5
        $serialized = [];
301
302
        // This metadata is always serialized/cached.
303 5
        $serialized = array_merge($serialized, [
304 5
            'declaredProperties',
305
            'fieldNames',
306
            //'embeddedClasses',
307
            'identifier',
308
            'className',
309
            'parent',
310
            'table',
311
            'valueGenerationPlan',
312
        ]);
313
314
        // The rest of the metadata is only serialized if necessary.
315 5
        if ($this->changeTrackingPolicy !== ChangeTrackingPolicy::DEFERRED_IMPLICIT) {
316
            $serialized[] = 'changeTrackingPolicy';
317
        }
318
319 5
        if ($this->customRepositoryClassName) {
320 1
            $serialized[] = 'customRepositoryClassName';
321
        }
322
323 5
        if ($this->inheritanceType !== InheritanceType::NONE) {
324 1
            $serialized[] = 'inheritanceType';
325 1
            $serialized[] = 'discriminatorColumn';
326 1
            $serialized[] = 'discriminatorValue';
327 1
            $serialized[] = 'discriminatorMap';
328 1
            $serialized[] = 'subClasses';
329
        }
330
331 5
        if ($this->isMappedSuperclass) {
332
            $serialized[] = 'isMappedSuperclass';
333
        }
334
335 5
        if ($this->isEmbeddedClass) {
336
            $serialized[] = 'isEmbeddedClass';
337
        }
338
339 5
        if ($this->isVersioned()) {
340
            $serialized[] = 'versionProperty';
341
        }
342
343 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...
344
            $serialized[] = 'lifecycleCallbacks';
345
        }
346
347 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...
348 1
            $serialized[] = 'entityListeners';
349
        }
350
351 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...
352
            $serialized[] = 'namedNativeQueries';
353
        }
354
355 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...
356
            $serialized[] = 'sqlResultSetMappings';
357
        }
358
359 5
        if ($this->cache) {
360
            $serialized[] = 'cache';
361
        }
362
363 5
        if ($this->readOnly) {
364 1
            $serialized[] = 'readOnly';
365
        }
366
367 5
        return $serialized;
368
    }
369
370
    /**
371
     * Restores some state that can not be serialized/unserialized.
372
     */
373 1629
    public function wakeupReflection(ReflectionService $reflectionService) : void
374
    {
375
        // Restore ReflectionClass and properties
376 1629
        $this->reflectionClass = $reflectionService->getClass($this->className);
377
378 1629
        if (! $this->reflectionClass) {
379
            return;
380
        }
381
382 1629
        $this->className = $this->reflectionClass->getName();
383
384 1629
        foreach ($this->declaredProperties as $property) {
385
            /** @var Property $property */
386 1628
            $property->wakeupReflection($reflectionService);
387
        }
388 1629
    }
389
390
    /**
391
     * Validates Identifier.
392
     *
393
     * @throws MappingException
394
     */
395 359
    public function validateIdentifier() : void
396
    {
397 359
        if ($this->isMappedSuperclass || $this->isEmbeddedClass) {
398 29
            return;
399
        }
400
401
        // Verify & complete identifier mapping
402 358
        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...
403 4
            throw MappingException::identifierRequired($this->className);
404
        }
405
406 354
        $explicitlyGeneratedProperties = array_filter($this->declaredProperties, function (Property $property) : bool {
407 354
            return $property instanceof FieldMetadata
408 354
                && $property->isPrimaryKey()
409 354
                && $property->hasValueGenerator();
410 354
        });
411
412 354
        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...
413
            throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->className);
414
        }
415 354
    }
416
417
    /**
418
     * Validates association targets actually exist.
419
     *
420
     * @throws MappingException
421
     */
422 358
    public function validateAssociations() : void
423
    {
424 358
        foreach ($this->declaredProperties as $property) {
425 358
            if (! ($property instanceof AssociationMetadata)) {
426 354
                continue;
427
            }
428
429 247
            $targetEntity = $property->getTargetEntity();
430
431 247
            if (! class_exists($targetEntity)) {
432 247
                throw MappingException::invalidTargetEntityClass($targetEntity, $this->className, $property->getName());
433
            }
434
        }
435 357
    }
436
437
    /**
438
     * Validates lifecycle callbacks.
439
     *
440
     * @throws MappingException
441
     */
442 358
    public function validateLifecycleCallbacks(ReflectionService $reflectionService) : void
443
    {
444 358
        foreach ($this->lifecycleCallbacks as $callbacks) {
445
            /** @var array $callbacks */
446 11
            foreach ($callbacks as $callbackFuncName) {
447 11
                if (! $reflectionService->hasPublicMethod($this->className, $callbackFuncName)) {
448 11
                    throw MappingException::lifecycleCallbackMethodNotFound($this->className, $callbackFuncName);
449
                }
450
            }
451
        }
452 357
    }
453
454
    /**
455
     * Sets the change tracking policy used by this class.
456
     */
457 102
    public function setChangeTrackingPolicy(string $policy) : void
458
    {
459 102
        $this->changeTrackingPolicy = $policy;
460 102
    }
461
462
    /**
463
     * Checks whether a field is part of the identifier/primary key field(s).
464
     *
465
     * @param string $fieldName The field name.
466
     *
467
     * @return bool TRUE if the field is part of the table identifier/primary key field(s), FALSE otherwise.
468
     */
469 1016
    public function isIdentifier(string $fieldName) : bool
470
    {
471 1016
        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...
472 1
            return false;
473
        }
474
475 1015
        if (! $this->isIdentifierComposite()) {
476 1011
            return $fieldName === $this->identifier[0];
477
        }
478
479 90
        return in_array($fieldName, $this->identifier, true);
480
    }
481
482 1200
    public function isIdentifierComposite() : bool
483
    {
484 1200
        return isset($this->identifier[1]);
485
    }
486
487
    /**
488
     * Gets the named native query.
489
     *
490
     * @see ClassMetadata::$namedNativeQueries
491
     *
492
     * @param string $queryName The query name.
493
     *
494
     * @return string[]
495
     *
496
     * @throws MappingException
497
     */
498 15
    public function getNamedNativeQuery($queryName) : array
499
    {
500 15
        if (! isset($this->namedNativeQueries[$queryName])) {
501
            throw MappingException::queryNotFound($this->className, $queryName);
502
        }
503
504 15
        return $this->namedNativeQueries[$queryName];
505
    }
506
507
    /**
508
     * Gets all named native queries of the class.
509
     *
510
     * @return string[]
511
     */
512 3
    public function getNamedNativeQueries() : array
513
    {
514 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...
515
    }
516
517
    /**
518
     * Gets the result set mapping.
519
     *
520
     * @see ClassMetadata::$sqlResultSetMappings
521
     *
522
     * @param string $name The result set mapping name.
523
     *
524
     * @return mixed[]
525
     *
526
     * @throws MappingException
527
     */
528 13
    public function getSqlResultSetMapping($name)
529
    {
530 13
        if (! isset($this->sqlResultSetMappings[$name])) {
531
            throw MappingException::resultMappingNotFound($this->className, $name);
532
        }
533
534 13
        return $this->sqlResultSetMappings[$name];
535
    }
536
537
    /**
538
     * Gets all sql result set mappings of the class.
539
     *
540
     * @return mixed[][]
541
     */
542 5
    public function getSqlResultSetMappings()
543
    {
544 5
        return $this->sqlResultSetMappings;
545
    }
546
547
    /**
548
     * Validates & completes the basic mapping information for field mapping.
549
     *
550
     * @throws MappingException If something is wrong with the mapping.
551
     */
552 398
    protected function validateAndCompleteFieldMapping(FieldMetadata $property)
553
    {
554 398
        $fieldName  = $property->getName();
555 398
        $columnName = $property->getColumnName();
556
557 398
        if (empty($columnName)) {
558 341
            $columnName = $this->namingStrategy->propertyToColumnName($fieldName, $this->className);
559
560 341
            $property->setColumnName($columnName);
561
        }
562
563 398
        if (! $this->isMappedSuperclass) {
564 391
            $property->setTableName($this->getTableName());
565
        }
566
567
        // Check for already declared column
568 398
        if (isset($this->fieldNames[$columnName]) ||
569 398
            ($this->discriminatorColumn !== null && $this->discriminatorColumn->getColumnName() === $columnName)) {
570 2
            throw MappingException::duplicateColumnName($this->className, $columnName);
571
        }
572
573
        // Complete id mapping
574 397
        if ($property->isPrimaryKey()) {
575 382
            if ($this->versionProperty !== null && $this->versionProperty->getName() === $fieldName) {
576
                throw MappingException::cannotVersionIdField($this->className, $fieldName);
577
            }
578
579 382
            if ($property->getType()->canRequireSQLConversion()) {
580
                throw MappingException::sqlConversionNotAllowedForPrimaryKeyProperties($this->className, $property);
581
            }
582
583 382
            if (! in_array($fieldName, $this->identifier, true)) {
584 382
                $this->identifier[] = $fieldName;
585
            }
586
        }
587
588 397
        $this->fieldNames[$columnName] = $fieldName;
589 397
    }
590
591
    /**
592
     * Validates & completes the basic mapping information for field mapping.
593
     *
594
     * @throws MappingException If something is wrong with the mapping.
595
     */
596 19
    protected function validateAndCompleteVersionFieldMapping(VersionFieldMetadata $property)
597
    {
598 19
        $this->versionProperty = $property;
599
600 19
        $options = $property->getOptions();
601
602 19
        if (isset($options['default'])) {
603
            return;
604
        }
605
606 19
        if (in_array($property->getTypeName(), ['integer', 'bigint', 'smallint'], true)) {
607 18
            $property->setOptions(array_merge($options, ['default' => 1]));
608
609 18
            return;
610
        }
611
612 2
        if ($property->getTypeName() === 'datetime') {
613 1
            $property->setOptions(array_merge($options, ['default' => 'CURRENT_TIMESTAMP']));
614
615 1
            return;
616
        }
617
618 1
        throw MappingException::unsupportedOptimisticLockingType($property->getType());
619
    }
620
621
    /**
622
     * Validates & completes the basic mapping information that is common to all
623
     * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
624
     *
625
     * @throws MappingException If something is wrong with the mapping.
626
     * @throws CacheException   If entity is not cacheable.
627
     */
628 279
    protected function validateAndCompleteAssociationMapping(AssociationMetadata $property)
629
    {
630 279
        $fieldName    = $property->getName();
631 279
        $targetEntity = $property->getTargetEntity();
632
633 279
        if (! $targetEntity) {
634
            throw MappingException::missingTargetEntity($fieldName);
635
        }
636
637 279
        $property->setSourceEntity($this->className);
638 279
        $property->setOwningSide($property->getMappedBy() === null);
639 279
        $property->setTargetEntity($targetEntity);
640
641
        // Complete id mapping
642 279
        if ($property->isPrimaryKey()) {
643 44
            if ($property->isOrphanRemoval()) {
644 1
                throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->className, $fieldName);
645
            }
646
647 43
            if (! in_array($property->getName(), $this->identifier, true)) {
648 43
                if ($property instanceof ToOneAssociationMetadata && count($property->getJoinColumns()) >= 2) {
649
                    throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
650
                        $property->getTargetEntity(),
651
                        $this->className,
652
                        $fieldName
653
                    );
654
                }
655
656 43
                $this->identifier[] = $property->getName();
657
            }
658
659 43
            if ($this->cache && ! $property->getCache()) {
660 2
                throw CacheException::nonCacheableEntityAssociation($this->className, $fieldName);
661
            }
662
663 41
            if ($property instanceof ToManyAssociationMetadata) {
664 1
                throw MappingException::illegalToManyIdentifierAssociation($this->className, $property->getName());
665
            }
666
        }
667
668
        // Cascades
669 275
        $cascadeTypes = ['remove', 'persist', 'refresh'];
670 275
        $cascades     = array_map('strtolower', $property->getCascade());
671
672 275
        if (in_array('all', $cascades, true)) {
673 3
            $cascades = $cascadeTypes;
674
        }
675
676 275
        if (count($cascades) !== count(array_intersect($cascades, $cascadeTypes))) {
677 1
            $diffCascades = array_diff($cascades, array_intersect($cascades, $cascadeTypes));
678
679 1
            throw MappingException::invalidCascadeOption($diffCascades, $this->className, $fieldName);
680
        }
681
682 274
        $property->setCascade($cascades);
683 274
    }
684
685
    /**
686
     * Validates & completes a to-one association mapping.
687
     *
688
     * @param ToOneAssociationMetadata $property The association mapping to validate & complete.
689
     *
690
     * @throws \RuntimeException
691
     * @throws MappingException
692
     */
693 238
    protected function validateAndCompleteToOneAssociationMetadata(ToOneAssociationMetadata $property)
694
    {
695 238
        $fieldName = $property->getName();
696
697 238
        if ($property->getJoinColumns()) {
698 167
            $property->setOwningSide(true);
699
        }
700
701 238
        if ($property->isOwningSide()) {
702 235
            if (empty($property->getJoinColumns())) {
703
                // Apply default join column
704 81
                $property->addJoinColumn(new JoinColumnMetadata());
705
            }
706
707 235
            $uniqueConstraintColumns = [];
708
709 235
            foreach ($property->getJoinColumns() as $joinColumn) {
710
                /** @var JoinColumnMetadata $joinColumn */
711 235
                if ($property instanceof OneToOneAssociationMetadata && $this->inheritanceType !== InheritanceType::SINGLE_TABLE) {
712 115
                    if (count($property->getJoinColumns()) === 1) {
713 113
                        if (! $property->isPrimaryKey()) {
714 113
                            $joinColumn->setUnique(true);
715
                        }
716
                    } else {
717 2
                        $uniqueConstraintColumns[] = $joinColumn->getColumnName();
718
                    }
719
                }
720
721 235
                $joinColumn->setTableName(! $this->isMappedSuperclass ? $this->getTableName() : null);
722
723 235
                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...
724 99
                    $joinColumn->setColumnName($this->namingStrategy->joinColumnName($fieldName, $this->className));
725
                }
726
727 235
                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...
728 81
                    $joinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
729
                }
730
731 235
                $this->fieldNames[$joinColumn->getColumnName()] = $fieldName;
732
            }
733
734 235
            if ($uniqueConstraintColumns) {
0 ignored issues
show
introduced by
The condition $uniqueConstraintColumns can never be true.
Loading history...
735 2
                if (! $this->table) {
736
                    throw new \RuntimeException(
737
                        'ClassMetadata::setTable() has to be called before defining a one to one relationship.'
738
                    );
739
                }
740
741 2
                $this->table->addUniqueConstraint(
742
                    [
743 2
                        'name'    => sprintf('%s_uniq', $fieldName),
744 2
                        'columns' => $uniqueConstraintColumns,
745
                        'options' => [],
746
                        'flags'   => [],
747
                    ]
748
                );
749
            }
750
        }
751
752 238
        if ($property->isOrphanRemoval()) {
753 9
            $cascades = $property->getCascade();
754
755 9
            if (! in_array('remove', $cascades, true)) {
756 8
                $cascades[] = 'remove';
757
758 8
                $property->setCascade($cascades);
759
            }
760
761
            // @todo guilhermeblanco where is this used?
762
            // @todo guilhermeblanco Shouldn￿'t we iterate through JoinColumns to set non-uniqueness?
763
            //$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...
764
        }
765
766 238
        if ($property->isPrimaryKey() && ! $property->isOwningSide()) {
767 1
            throw MappingException::illegalInverseIdentifierAssociation($this->className, $fieldName);
768
        }
769 237
    }
770
771
    /**
772
     * Validates & completes a to-many association mapping.
773
     *
774
     * @param ToManyAssociationMetadata $property The association mapping to validate & complete.
775
     *
776
     * @throws MappingException
777
     */
778 165
    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

778
    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...
779
    {
780
        // Do nothing
781 165
    }
782
783
    /**
784
     * Validates & completes a one-to-one association mapping.
785
     *
786
     * @param OneToOneAssociationMetadata $property The association mapping to validate & complete.
787
     */
788 122
    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

788
    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...
789
    {
790
        // Do nothing
791 122
    }
792
793
    /**
794
     * Validates & completes a many-to-one association mapping.
795
     *
796
     * @param ManyToOneAssociationMetadata $property The association mapping to validate & complete.
797
     *
798
     * @throws MappingException
799
     */
800 139
    protected function validateAndCompleteManyToOneMapping(ManyToOneAssociationMetadata $property)
801
    {
802
        // A many-to-one mapping is essentially a one-one backreference
803 139
        if ($property->isOrphanRemoval()) {
804
            throw MappingException::illegalOrphanRemoval($this->className, $property->getName());
805
        }
806 139
    }
807
808
    /**
809
     * Validates & completes a one-to-many association mapping.
810
     *
811
     * @param OneToManyAssociationMetadata $property The association mapping to validate & complete.
812
     *
813
     * @throws MappingException
814
     */
815 111
    protected function validateAndCompleteOneToManyMapping(OneToManyAssociationMetadata $property)
816
    {
817
        // OneToMany MUST be inverse side
818 111
        $property->setOwningSide(false);
819
820
        // OneToMany MUST have mappedBy
821 111
        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...
822
            throw MappingException::oneToManyRequiresMappedBy($property->getName());
823
        }
824
825 111
        if ($property->isOrphanRemoval()) {
826 21
            $cascades = $property->getCascade();
827
828 21
            if (! in_array('remove', $cascades, true)) {
829 18
                $cascades[] = 'remove';
830
831 18
                $property->setCascade($cascades);
832
            }
833
        }
834 111
    }
835
836
    /**
837
     * Validates & completes a many-to-many association mapping.
838
     *
839
     * @param ManyToManyAssociationMetadata $property The association mapping to validate & complete.
840
     *
841
     * @throws MappingException
842
     */
843 104
    protected function validateAndCompleteManyToManyMapping(ManyToManyAssociationMetadata $property)
844
    {
845 104
        if ($property->isOwningSide()) {
846
            // owning side MUST have a join table
847 92
            $joinTable = $property->getJoinTable() ?: new JoinTableMetadata();
848
849 92
            $property->setJoinTable($joinTable);
850
851 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...
852 18
                $joinTableName = $this->namingStrategy->joinTableName(
853 18
                    $property->getSourceEntity(),
854 18
                    $property->getTargetEntity(),
855 18
                    $property->getName()
856
                );
857
858 18
                $joinTable->setName($joinTableName);
859
            }
860
861 92
            $selfReferencingEntityWithoutJoinColumns = $property->getSourceEntity() === $property->getTargetEntity() && ! $joinTable->hasColumns();
862
863 92
            if (! $joinTable->getJoinColumns()) {
864 16
                $referencedColumnName = $this->namingStrategy->referenceColumnName();
865 16
                $sourceReferenceName  = $selfReferencingEntityWithoutJoinColumns ? 'source' : $referencedColumnName;
866 16
                $columnName           = $this->namingStrategy->joinKeyColumnName($property->getSourceEntity(), $sourceReferenceName);
867 16
                $joinColumn           = new JoinColumnMetadata();
868
869 16
                $joinColumn->setColumnName($columnName);
870 16
                $joinColumn->setReferencedColumnName($referencedColumnName);
871 16
                $joinColumn->setOnDelete('CASCADE');
872
873 16
                $joinTable->addJoinColumn($joinColumn);
874
            }
875
876 92
            if (! $joinTable->getInverseJoinColumns()) {
877 16
                $referencedColumnName = $this->namingStrategy->referenceColumnName();
878 16
                $targetReferenceName  = $selfReferencingEntityWithoutJoinColumns ? 'target' : $referencedColumnName;
879 16
                $columnName           = $this->namingStrategy->joinKeyColumnName($property->getTargetEntity(), $targetReferenceName);
880 16
                $joinColumn           = new JoinColumnMetadata();
881
882 16
                $joinColumn->setColumnName($columnName);
883 16
                $joinColumn->setReferencedColumnName($referencedColumnName);
884 16
                $joinColumn->setOnDelete('CASCADE');
885
886 16
                $joinTable->addInverseJoinColumn($joinColumn);
887
            }
888
889 92
            foreach ($joinTable->getJoinColumns() as $joinColumn) {
890
                /** @var JoinColumnMetadata $joinColumn */
891 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...
892 2
                    $joinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
893
                }
894
895 92
                $referencedColumnName = $joinColumn->getReferencedColumnName();
896
897 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...
898 2
                    $columnName = $this->namingStrategy->joinKeyColumnName(
899 2
                        $property->getSourceEntity(),
900 2
                        $referencedColumnName
901
                    );
902
903 92
                    $joinColumn->setColumnName($columnName);
904
                }
905
            }
906
907 92
            foreach ($joinTable->getInverseJoinColumns() as $inverseJoinColumn) {
908
                /** @var JoinColumnMetadata $inverseJoinColumn */
909 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...
910 2
                    $inverseJoinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
911
                }
912
913 92
                $referencedColumnName = $inverseJoinColumn->getReferencedColumnName();
914
915 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...
916 2
                    $columnName = $this->namingStrategy->joinKeyColumnName(
917 2
                        $property->getTargetEntity(),
918 2
                        $referencedColumnName
919
                    );
920
921 92
                    $inverseJoinColumn->setColumnName($columnName);
922
                }
923
            }
924
        }
925 104
    }
926
927
    /**
928
     * {@inheritDoc}
929
     */
930 393
    public function getIdentifierFieldNames()
931
    {
932 393
        return $this->identifier;
933
    }
934
935
    /**
936
     * Gets the name of the single id field. Note that this only works on
937
     * entity classes that have a single-field pk.
938
     *
939
     * @return string
940
     *
941
     * @throws MappingException If the class has a composite primary key.
942
     */
943 149
    public function getSingleIdentifierFieldName()
944
    {
945 149
        if ($this->isIdentifierComposite()) {
946 1
            throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->className);
947
        }
948
949 148
        if (! isset($this->identifier[0])) {
950 1
            throw MappingException::noIdDefined($this->className);
951
        }
952
953 147
        return $this->identifier[0];
954
    }
955
956
    /**
957
     * INTERNAL:
958
     * Sets the mapped identifier/primary key fields of this class.
959
     * Mainly used by the ClassMetadataFactory to assign inherited identifiers.
960
     *
961
     * @param mixed[] $identifier
962
     */
963 99
    public function setIdentifier(array $identifier)
964
    {
965 99
        $this->identifier = $identifier;
966 99
    }
967
968
    /**
969
     * {@inheritDoc}
970
     */
971 1041
    public function getIdentifier()
972
    {
973 1041
        return $this->identifier;
974
    }
975
976
    /**
977
     * {@inheritDoc}
978
     */
979 184
    public function hasField($fieldName)
980
    {
981 184
        return isset($this->declaredProperties[$fieldName])
982 184
            && $this->declaredProperties[$fieldName] instanceof FieldMetadata;
983
    }
984
985
    /**
986
     * Returns an array with identifier column names and their corresponding ColumnMetadata.
987
     *
988
     * @return ColumnMetadata[]
989
     */
990 434
    public function getIdentifierColumns(EntityManagerInterface $em) : array
991
    {
992 434
        $columns = [];
993
994 434
        foreach ($this->identifier as $idProperty) {
995 434
            $property = $this->getProperty($idProperty);
996
997 434
            if ($property instanceof FieldMetadata) {
998 429
                $columns[$property->getColumnName()] = $property;
999
1000 429
                continue;
1001
            }
1002
1003
            /** @var AssociationMetadata $property */
1004
1005
            // Association defined as Id field
1006 24
            $targetClass = $em->getClassMetadata($property->getTargetEntity());
1007
1008 24
            if (! $property->isOwningSide()) {
1009
                $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

1009
                /** @scrutinizer ignore-call */ 
1010
                $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...
1010
                $targetClass = $em->getClassMetadata($property->getTargetEntity());
1011
            }
1012
1013 24
            $joinColumns = $property instanceof ManyToManyAssociationMetadata
1014
                ? $property->getJoinTable()->getInverseJoinColumns()
1015 24
                : $property->getJoinColumns()
1016
            ;
1017
1018 24
            foreach ($joinColumns as $joinColumn) {
1019
                /** @var JoinColumnMetadata $joinColumn */
1020 24
                $columnName           = $joinColumn->getColumnName();
1021 24
                $referencedColumnName = $joinColumn->getReferencedColumnName();
1022
1023 24
                if (! $joinColumn->getType()) {
1024 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

1024
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, /** @scrutinizer ignore-type */ $targetClass, $em));
Loading history...
1025
                }
1026
1027 24
                $columns[$columnName] = $joinColumn;
1028
            }
1029
        }
1030
1031 434
        return $columns;
1032
    }
1033
1034
    /**
1035
     * Gets the name of the primary table.
1036
     */
1037 1572
    public function getTableName() : ?string
1038
    {
1039 1572
        return $this->table->getName();
1040
    }
1041
1042
    /**
1043
     * Gets primary table's schema name.
1044
     */
1045 14
    public function getSchemaName() : ?string
1046
    {
1047 14
        return $this->table->getSchema();
1048
    }
1049
1050
    /**
1051
     * Gets the table name to use for temporary identifier tables of this class.
1052
     */
1053 7
    public function getTemporaryIdTableName() : string
1054
    {
1055 7
        $schema = $this->getSchemaName() === null
1056 6
            ? ''
1057 7
            : $this->getSchemaName() . '_'
1058
        ;
1059
1060
        // replace dots with underscores because PostgreSQL creates temporary tables in a special schema
1061 7
        return $schema . $this->getTableName() . '_id_tmp';
1062
    }
1063
1064
    /**
1065
     * Sets the mapped subclasses of this class.
1066
     *
1067
     * @todo guilhermeblanco Only used for ClassMetadataTest. Remove if possible!
1068
     *
1069
     * @param string[] $subclasses The names of all mapped subclasses.
1070
     */
1071 4
    public function setSubclasses(array $subclasses) : void
1072
    {
1073 4
        foreach ($subclasses as $subclass) {
1074 3
            $this->subClasses[] = $subclass;
1075
        }
1076 4
    }
1077
1078
    /**
1079
     * @return string[]
1080
     */
1081 1070
    public function getSubClasses() : array
1082
    {
1083 1070
        return $this->subClasses;
1084
    }
1085
1086
    /**
1087
     * Sets the inheritance type used by the class and its subclasses.
1088
     *
1089
     * @param int $type
1090
     *
1091
     * @throws MappingException
1092
     */
1093 117
    public function setInheritanceType($type) : void
1094
    {
1095 117
        if (! $this->isInheritanceType($type)) {
1096
            throw MappingException::invalidInheritanceType($this->className, $type);
1097
        }
1098
1099 117
        $this->inheritanceType = $type;
1100 117
    }
1101
1102
    /**
1103
     * Sets the override property mapping for an entity relationship.
1104
     *
1105
     * @throws \RuntimeException
1106
     * @throws MappingException
1107
     * @throws CacheException
1108
     */
1109 12
    public function setPropertyOverride(Property $property) : void
1110
    {
1111 12
        $fieldName = $property->getName();
1112
1113 12
        if (! isset($this->declaredProperties[$fieldName])) {
1114 2
            throw MappingException::invalidOverrideFieldName($this->className, $fieldName);
1115
        }
1116
1117 10
        $originalProperty          = $this->getProperty($fieldName);
1118 10
        $originalPropertyClassName = get_class($originalProperty);
1119
1120
        // If moving from transient to persistent, assume it's a new property
1121 10
        if ($originalPropertyClassName === TransientMetadata::class) {
1122 1
            unset($this->declaredProperties[$fieldName]);
1123
1124 1
            $this->addProperty($property);
1125
1126 1
            return;
1127
        }
1128
1129
        // Do not allow to change property type
1130 9
        if ($originalPropertyClassName !== get_class($property)) {
1131
            throw MappingException::invalidOverridePropertyType($this->className, $fieldName);
1132
        }
1133
1134
        // Do not allow to change version property
1135 9
        if ($originalProperty instanceof VersionFieldMetadata) {
1136
            throw MappingException::invalidOverrideVersionField($this->className, $fieldName);
1137
        }
1138
1139 9
        unset($this->declaredProperties[$fieldName]);
1140
1141 9
        if ($property instanceof FieldMetadata) {
1142
            // Unset defined fieldName prior to override
1143 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

1143
            unset($this->fieldNames[$originalProperty->/** @scrutinizer ignore-call */ getColumnName()]);
Loading history...
1144
1145
            // Revert what should not be allowed to change
1146 5
            $property->setDeclaringClass($originalProperty->getDeclaringClass());
1147 5
            $property->setPrimaryKey($originalProperty->isPrimaryKey());
1148 9
        } elseif ($property instanceof AssociationMetadata) {
1149
            // Unset all defined fieldNames prior to override
1150 9
            if ($originalProperty instanceof ToOneAssociationMetadata && $originalProperty->isOwningSide()) {
1151 5
                foreach ($originalProperty->getJoinColumns() as $joinColumn) {
1152 5
                    unset($this->fieldNames[$joinColumn->getColumnName()]);
1153
                }
1154
            }
1155
1156
            // Override what it should be allowed to change
1157 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...
1158 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

1158
                $originalProperty->/** @scrutinizer ignore-call */ 
1159
                                   setInversedBy($property->getInversedBy());
Loading history...
1159
            }
1160
1161 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

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

1162
                $originalProperty->/** @scrutinizer ignore-call */ 
1163
                                   setFetchMode($property->getFetchMode());
Loading history...
1163
            }
1164
1165 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

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

1167
            } elseif ($originalProperty instanceof ManyToManyAssociationMetadata && $property->/** @scrutinizer ignore-call */ getJoinTable()) {
Loading history...
1168 4
                $originalProperty->setJoinTable($property->getJoinTable());
1169
            }
1170
1171 9
            $property = $originalProperty;
1172
        }
1173
1174 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

1174
        $this->addProperty(/** @scrutinizer ignore-type */ $property);
Loading history...
1175 9
    }
1176
1177
    /**
1178
     * Checks if this entity is the root in any entity-inheritance-hierarchy.
1179
     *
1180
     * @return bool
1181
     */
1182 333
    public function isRootEntity()
1183
    {
1184 333
        return $this->className === $this->getRootClassName();
1185
    }
1186
1187
    /**
1188
     * Checks whether a mapped field is inherited from a superclass.
1189
     *
1190
     * @param string $fieldName
1191
     *
1192
     * @return bool TRUE if the field is inherited, FALSE otherwise.
1193
     */
1194 613
    public function isInheritedProperty($fieldName)
1195
    {
1196 613
        $declaringClass = $this->declaredProperties[$fieldName]->getDeclaringClass();
1197
1198 613
        return ! ($declaringClass->className === $this->className);
1199
    }
1200
1201
    /**
1202
     * {@inheritdoc}
1203
     */
1204 439
    public function setTable(TableMetadata $table) : void
1205
    {
1206 439
        $this->table = $table;
1207
1208 439
        if (empty($table->getName())) {
1209
            $table->setName($this->namingStrategy->classToTableName($this->className));
1210
        }
1211 439
    }
1212
1213
    /**
1214
     * Checks whether the given type identifies an inheritance type.
1215
     *
1216
     * @param int $type
1217
     *
1218
     * @return bool TRUE if the given type identifies an inheritance type, FALSe otherwise.
1219
     */
1220 117
    private function isInheritanceType($type)
1221
    {
1222 117
        return $type === InheritanceType::NONE
1223 91
            || $type === InheritanceType::SINGLE_TABLE
1224 51
            || $type === InheritanceType::JOINED
1225 117
            || $type === InheritanceType::TABLE_PER_CLASS;
1226
    }
1227
1228 906
    public function getColumn(string $columnName) : ?LocalColumnMetadata
1229
    {
1230 906
        foreach ($this->declaredProperties as $property) {
1231 906
            if ($property instanceof LocalColumnMetadata && $property->getColumnName() === $columnName) {
1232 906
                return $property;
1233
            }
1234
        }
1235
1236
        return null;
1237
    }
1238
1239
    /**
1240
     * Add a property mapping.
1241
     *
1242
     * @throws \RuntimeException
1243
     * @throws MappingException
1244
     * @throws CacheException
1245
     */
1246 421
    public function addProperty(Property $property)
1247
    {
1248 421
        $fieldName = $property->getName();
1249
1250
        // Check for empty field name
1251 421
        if (empty($fieldName)) {
1252 1
            throw MappingException::missingFieldName($this->className);
1253
        }
1254
1255 420
        $property->setDeclaringClass($this);
1256
1257
        switch (true) {
1258 420
            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...
1259 19
                $this->validateAndCompleteFieldMapping($property);
1260 19
                $this->validateAndCompleteVersionFieldMapping($property);
1261 18
                break;
1262
1263 419
            case ($property instanceof FieldMetadata):
1264 397
                $this->validateAndCompleteFieldMapping($property);
1265 396
                break;
1266
1267 282
            case ($property instanceof OneToOneAssociationMetadata):
1268 124
                $this->validateAndCompleteAssociationMapping($property);
1269 123
                $this->validateAndCompleteToOneAssociationMetadata($property);
1270 122
                $this->validateAndCompleteOneToOneMapping($property);
1271 122
                break;
1272
1273 220
            case ($property instanceof OneToManyAssociationMetadata):
1274 111
                $this->validateAndCompleteAssociationMapping($property);
1275 111
                $this->validateAndCompleteToManyAssociationMetadata($property);
1276 111
                $this->validateAndCompleteOneToManyMapping($property);
1277 111
                break;
1278
1279 216
            case ($property instanceof ManyToOneAssociationMetadata):
1280 142
                $this->validateAndCompleteAssociationMapping($property);
1281 139
                $this->validateAndCompleteToOneAssociationMetadata($property);
1282 139
                $this->validateAndCompleteManyToOneMapping($property);
1283 139
                break;
1284
1285 122
            case ($property instanceof ManyToManyAssociationMetadata):
1286 105
                $this->validateAndCompleteAssociationMapping($property);
1287 104
                $this->validateAndCompleteToManyAssociationMetadata($property);
1288 104
                $this->validateAndCompleteManyToManyMapping($property);
1289 104
                break;
1290
1291
            default:
1292
                // Transient properties are ignored on purpose here! =)
1293 32
                break;
1294
        }
1295
1296 412
        $this->addDeclaredProperty($property);
1297 412
    }
1298
1299
    /**
1300
     * INTERNAL:
1301
     * Adds a property mapping without completing/validating it.
1302
     * This is mainly used to add inherited property mappings to derived classes.
1303
     */
1304 97
    public function addInheritedProperty(Property $property)
1305
    {
1306 97
        $inheritedProperty = clone $property;
1307
        /** @var ClassMetadata $declaringClass */
1308 97
        $declaringClass    = $property->getDeclaringClass();
1309
1310 97
        assert($declaringClass instanceof ClassMetadata);
1311
1312 97
        if ($inheritedProperty instanceof FieldMetadata) {
1313 96
            if (! $declaringClass->isMappedSuperclass) {
1314 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

1314
                $inheritedProperty->setTableName($property->/** @scrutinizer ignore-call */ getTableName());
Loading history...
1315
            }
1316
1317 96
            $this->fieldNames[$property->getColumnName()] = $property->getName();
1318 43
        } elseif ($inheritedProperty instanceof AssociationMetadata) {
1319 42
            if ($declaringClass->isMappedSuperclass) {
1320 10
                $inheritedProperty->setSourceEntity($this->className);
1321
            }
1322
1323
            // Need to add inherited fieldNames
1324 42
            if ($inheritedProperty instanceof ToOneAssociationMetadata && $inheritedProperty->isOwningSide()) {
1325 35
                foreach ($inheritedProperty->getJoinColumns() as $joinColumn) {
1326
                    /** @var JoinColumnMetadata $joinColumn */
1327 34
                    $this->fieldNames[$joinColumn->getColumnName()] = $property->getName();
1328
                }
1329
            }
1330
        }
1331
1332 97
        if (isset($this->declaredProperties[$property->getName()])) {
1333 1
            throw MappingException::duplicateProperty($this->className, $this->getProperty($property->getName()));
1334
        }
1335
1336 97
        $this->declaredProperties[$property->getName()] = $inheritedProperty;
1337
1338 97
        if ($inheritedProperty instanceof VersionFieldMetadata) {
1339 4
            $this->versionProperty = $inheritedProperty;
1340
        }
1341 97
    }
1342
1343
    /**
1344
     * INTERNAL:
1345
     * Adds a named native query to this class.
1346
     *
1347
     * @param mixed[] $queryMapping
1348
     *
1349
     * @throws MappingException
1350
     */
1351 25
    public function addNamedNativeQuery(string $name, string $query, array $queryMapping)
1352
    {
1353 25
        if (isset($this->namedNativeQueries[$name])) {
1354 1
            throw MappingException::duplicateQueryMapping($this->className, $name);
1355
        }
1356
1357 25
        if (! isset($queryMapping['resultClass']) && ! isset($queryMapping['resultSetMapping'])) {
1358
            throw MappingException::missingQueryMapping($this->className, $name);
1359
        }
1360
1361 25
        $this->namedNativeQueries[$name] = array_merge(['query' => $query], $queryMapping);
1362 25
    }
1363
1364
    /**
1365
     * INTERNAL:
1366
     * Adds a sql result set mapping to this class.
1367
     *
1368
     * @param mixed[] $resultMapping
1369
     *
1370
     * @throws MappingException
1371
     */
1372 25
    public function addSqlResultSetMapping(array $resultMapping)
1373
    {
1374 25
        if (! isset($resultMapping['name'])) {
1375
            throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->className);
1376
        }
1377
1378 25
        if (isset($this->sqlResultSetMappings[$resultMapping['name']])) {
1379 1
            throw MappingException::duplicateResultSetMapping($this->className, $resultMapping['name']);
1380
        }
1381
1382 25
        if (isset($resultMapping['entities'])) {
1383 25
            foreach ($resultMapping['entities'] as $key => $entityResult) {
1384 25
                if (! isset($entityResult['entityClass'])) {
1385 1
                    throw MappingException::missingResultSetMappingEntity($this->className, $resultMapping['name']);
1386
                }
1387
1388 24
                $entityClassName                                = $entityResult['entityClass'];
1389 24
                $resultMapping['entities'][$key]['entityClass'] = $entityClassName;
1390
1391 24
                if (isset($entityResult['fields'])) {
1392 20
                    foreach ($entityResult['fields'] as $k => $field) {
1393 20
                        if (! isset($field['name'])) {
1394
                            throw MappingException::missingResultSetMappingFieldName($this->className, $resultMapping['name']);
1395
                        }
1396
1397 20
                        if (! isset($field['column'])) {
1398 12
                            $fieldName = $field['name'];
1399
1400 12
                            if (strpos($fieldName, '.')) {
1401 6
                                list(, $fieldName) = explode('.', $fieldName);
1402
                            }
1403
1404 24
                            $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
1405
                        }
1406
                    }
1407
                }
1408
            }
1409
        }
1410
1411 24
        $this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping;
1412 24
    }
1413
1414
    /**
1415
     * Registers a custom repository class for the entity class.
1416
     *
1417
     * @param string|null $repositoryClassName The class name of the custom mapper.
1418
     */
1419 31
    public function setCustomRepositoryClassName(?string $repositoryClassName)
1420
    {
1421 31
        $this->customRepositoryClassName = $repositoryClassName;
1422 31
    }
1423
1424 173
    public function getCustomRepositoryClassName() : ?string
1425
    {
1426 173
        return $this->customRepositoryClassName;
1427
    }
1428
1429
    /**
1430
     * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
1431
     *
1432
     * @param string $lifecycleEvent
1433
     *
1434
     * @return bool
1435
     */
1436
    public function hasLifecycleCallbacks($lifecycleEvent)
1437
    {
1438
        return isset($this->lifecycleCallbacks[$lifecycleEvent]);
1439
    }
1440
1441
    /**
1442
     * Gets the registered lifecycle callbacks for an event.
1443
     *
1444
     * @param string $event
1445
     *
1446
     * @return string[]
1447
     */
1448
    public function getLifecycleCallbacks($event)
1449
    {
1450
        return $this->lifecycleCallbacks[$event] ?? [];
1451
    }
1452
1453
    /**
1454
     * Adds a lifecycle callback for entities of this class.
1455
     *
1456
     * @param string $callback
1457
     * @param string $event
1458
     */
1459 17
    public function addLifecycleCallback($callback, $event)
1460
    {
1461 17
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event], true)) {
1462 3
            return;
1463
        }
1464
1465 17
        $this->lifecycleCallbacks[$event][] = $callback;
1466 17
    }
1467
1468
    /**
1469
     * Sets the lifecycle callbacks for entities of this class.
1470
     * Any previously registered callbacks are overwritten.
1471
     *
1472
     * @param string[][] $callbacks
1473
     */
1474 97
    public function setLifecycleCallbacks(array $callbacks) : void
1475
    {
1476 97
        $this->lifecycleCallbacks = $callbacks;
1477 97
    }
1478
1479
    /**
1480
     * Adds a entity listener for entities of this class.
1481
     *
1482
     * @param string $eventName The entity lifecycle event.
1483
     * @param string $class     The listener class.
1484
     * @param string $method    The listener callback method.
1485
     *
1486
     * @throws \Doctrine\ORM\Mapping\MappingException
1487
     */
1488 19
    public function addEntityListener(string $eventName, string $class, string $method) : void
1489
    {
1490
        $listener = [
1491 19
            'class'  => $class,
1492 19
            'method' => $method,
1493
        ];
1494
1495 19
        if (! class_exists($class)) {
1496 1
            throw MappingException::entityListenerClassNotFound($class, $this->className);
1497
        }
1498
1499 18
        if (! method_exists($class, $method)) {
1500 1
            throw MappingException::entityListenerMethodNotFound($class, $method, $this->className);
1501
        }
1502
1503 17
        if (isset($this->entityListeners[$eventName]) && in_array($listener, $this->entityListeners[$eventName], true)) {
1504 1
            throw MappingException::duplicateEntityListener($class, $method, $this->className);
1505
        }
1506
1507 17
        $this->entityListeners[$eventName][] = $listener;
1508 17
    }
1509
1510
    /**
1511
     * Sets the discriminator column definition.
1512
     *
1513
     * @throws MappingException
1514
     *
1515
     * @see getDiscriminatorColumn()
1516
     */
1517 93
    public function setDiscriminatorColumn(DiscriminatorColumnMetadata $discriminatorColumn) : void
1518
    {
1519 93
        if (isset($this->fieldNames[$discriminatorColumn->getColumnName()])) {
1520 1
            throw MappingException::duplicateColumnName($this->className, $discriminatorColumn->getColumnName());
1521
        }
1522
1523 92
        $discriminatorColumn->setTableName($discriminatorColumn->getTableName() ?? $this->getTableName());
1524
1525 92
        $allowedTypeList = ['boolean', 'array', 'object', 'datetime', 'time', 'date'];
1526
1527 92
        if (in_array($discriminatorColumn->getTypeName(), $allowedTypeList, true)) {
1528
            throw MappingException::invalidDiscriminatorColumnType($discriminatorColumn->getTypeName());
1529
        }
1530
1531 92
        $this->discriminatorColumn = $discriminatorColumn;
1532 92
    }
1533
1534
    /**
1535
     * Sets the discriminator values used by this class.
1536
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
1537
     *
1538
     * @param string[] $map
1539
     *
1540
     * @throws MappingException
1541
     */
1542 90
    public function setDiscriminatorMap(array $map) : void
1543
    {
1544 90
        foreach ($map as $value => $className) {
1545 90
            $this->addDiscriminatorMapClass($value, $className);
1546
        }
1547 90
    }
1548
1549
    /**
1550
     * Adds one entry of the discriminator map with a new class and corresponding name.
1551
     *
1552
     * @param string|int $name
1553
     *
1554
     * @throws MappingException
1555
     */
1556 90
    public function addDiscriminatorMapClass($name, string $className) : void
1557
    {
1558 90
        $this->discriminatorMap[$name] = $className;
1559
1560 90
        if ($this->className === $className) {
1561 76
            $this->discriminatorValue = $name;
1562
1563 76
            return;
1564
        }
1565
1566 89
        if (! (class_exists($className) || interface_exists($className))) {
1567
            throw MappingException::invalidClassInDiscriminatorMap($className, $this->className);
1568
        }
1569
1570 89
        if (is_subclass_of($className, $this->className) && ! in_array($className, $this->subClasses, true)) {
1571 84
            $this->subClasses[] = $className;
1572
        }
1573 89
    }
1574
1575 1020
    public function getValueGenerationPlan() : ValueGenerationPlan
1576
    {
1577 1020
        return $this->valueGenerationPlan;
1578
    }
1579
1580 359
    public function setValueGenerationPlan(ValueGenerationPlan $valueGenerationPlan) : void
1581
    {
1582 359
        $this->valueGenerationPlan = $valueGenerationPlan;
1583 359
    }
1584
1585
    /**
1586
     * Checks whether the class has a named native query with the given query name.
1587
     *
1588
     * @param string $queryName
1589
     */
1590 1
    public function hasNamedNativeQuery($queryName) : bool
1591
    {
1592 1
        return isset($this->namedNativeQueries[$queryName]);
1593
    }
1594
1595
    /**
1596
     * Checks whether the class has a named native query with the given query name.
1597
     *
1598
     * @param string $name
1599
     */
1600 1
    public function hasSqlResultSetMapping($name) : bool
1601
    {
1602 1
        return isset($this->sqlResultSetMappings[$name]);
1603
    }
1604
1605
    /**
1606
     * Marks this class as read only, no change tracking is applied to it.
1607
     */
1608 2
    public function asReadOnly() : void
1609
    {
1610 2
        $this->readOnly = true;
1611 2
    }
1612
1613
    /**
1614
     * Whether this class is read only or not.
1615
     */
1616 443
    public function isReadOnly() : bool
1617
    {
1618 443
        return $this->readOnly;
1619
    }
1620
1621 1057
    public function isVersioned() : bool
1622
    {
1623 1057
        return $this->versionProperty !== null;
1624
    }
1625
1626
    /**
1627
     * Map Embedded Class
1628
     *
1629
     * @param mixed[] $mapping
1630
     *
1631
     * @throws MappingException
1632
     */
1633
    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

1633
    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...
1634
    {
1635
        /*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...
1636
            throw MappingException::duplicateProperty($this->className, $this->getProperty($mapping['fieldName']));
1637
        }
1638
1639
        $this->embeddedClasses[$mapping['fieldName']] = [
1640
            'class'          => $this->fullyQualifiedClassName($mapping['class']),
1641
            'columnPrefix'   => $mapping['columnPrefix'],
1642
            'declaredField'  => $mapping['declaredField'] ?? null,
1643
            'originalField'  => $mapping['originalField'] ?? null,
1644
            'declaringClass' => $this,
1645
        ];*/
1646
    }
1647
1648
    /**
1649
     * Inline the embeddable class
1650
     *
1651
     * @param string $property
1652
     */
1653
    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

1653
    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

1653
    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...
1654
    {
1655
        /*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...
1656
            $fieldMapping['fieldName']     = $property . "." . $fieldName;
1657
            $fieldMapping['originalClass'] = $fieldMapping['originalClass'] ?? $embeddable->getClassName();
1658
            $fieldMapping['originalField'] = $fieldMapping['originalField'] ?? $fieldName;
1659
            $fieldMapping['declaredField'] = isset($fieldMapping['declaredField'])
1660
                ? $property . '.' . $fieldMapping['declaredField']
1661
                : $property;
1662
1663
            if (! empty($this->embeddedClasses[$property]['columnPrefix'])) {
1664
                $fieldMapping['columnName'] = $this->embeddedClasses[$property]['columnPrefix'] . $fieldMapping['columnName'];
1665
            } elseif ($this->embeddedClasses[$property]['columnPrefix'] !== false) {
1666
                $fieldMapping['columnName'] = $this->namingStrategy->embeddedFieldToColumnName(
1667
                    $property,
1668
                    $fieldMapping['columnName'],
1669
                    $this->reflectionClass->getName(),
1670
                    $embeddable->reflectionClass->getName()
1671
                );
1672
            }
1673
1674
            $this->mapField($fieldMapping);
1675
        }*/
1676
    }
1677
}
1678