Failed Conditions
Push — master ( ee4e26...e98654 )
by Marco
13:06
created

ClassMetadata::getSingleIdentifierFieldName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 0
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
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 457
    public function __construct(
212
        string $entityName,
213
        ClassMetadataBuildingContext $metadataBuildingContext
214
    ) {
215 457
        parent::__construct($entityName, $metadataBuildingContext);
216
217 457
        $this->namingStrategy = $metadataBuildingContext->getNamingStrategy();
218 457
    }
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 358
    public function validateIdentifier() : void
396
    {
397 358
        if ($this->isMappedSuperclass || $this->isEmbeddedClass) {
398 29
            return;
399
        }
400
401
        // Verify & complete identifier mapping
402 357
        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 353
        $explicitlyGeneratedProperties = array_filter($this->declaredProperties, function (Property $property) : bool {
407 353
            return $property instanceof FieldMetadata
408 353
                && $property->isPrimaryKey()
409 353
                && $property->hasValueGenerator();
410 353
        });
411
412 353
        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 353
    }
416
417
    /**
418
     * Validates association targets actually exist.
419
     *
420
     * @throws MappingException
421
     */
422 357
    public function validateAssociations() : void
423
    {
424 357
        array_map(
425 357
            function (Property $property) {
426 357
                if (! ($property instanceof AssociationMetadata)) {
427 353
                    return;
428
                }
429
430 246
                $targetEntity = $property->getTargetEntity();
431
432 246
                if (! class_exists($targetEntity)) {
433 1
                    throw MappingException::invalidTargetEntityClass($targetEntity, $this->className, $property->getName());
434
                }
435 357
            },
436 357
            $this->declaredProperties
437
        );
438 356
    }
439
440
    /**
441
     * Validates lifecycle callbacks.
442
     *
443
     * @throws MappingException
444
     */
445 357
    public function validateLifecycleCallbacks(ReflectionService $reflectionService) : void
446
    {
447 357
        foreach ($this->lifecycleCallbacks as $callbacks) {
448
            /** @var array $callbacks */
449 11
            foreach ($callbacks as $callbackFuncName) {
450 11
                if (! $reflectionService->hasPublicMethod($this->className, $callbackFuncName)) {
451 11
                    throw MappingException::lifecycleCallbackMethodNotFound($this->className, $callbackFuncName);
452
                }
453
            }
454
        }
455 356
    }
456
457
    /**
458
     * Sets the change tracking policy used by this class.
459
     */
460 102
    public function setChangeTrackingPolicy(string $policy) : void
461
    {
462 102
        $this->changeTrackingPolicy = $policy;
463 102
    }
464
465
    /**
466
     * Checks whether a field is part of the identifier/primary key field(s).
467
     *
468
     * @param string $fieldName The field name.
469
     *
470
     * @return bool TRUE if the field is part of the table identifier/primary key field(s), FALSE otherwise.
471
     */
472 1016
    public function isIdentifier(string $fieldName) : bool
473
    {
474 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...
475 1
            return false;
476
        }
477
478 1015
        if (! $this->isIdentifierComposite()) {
479 1011
            return $fieldName === $this->identifier[0];
480
        }
481
482 90
        return in_array($fieldName, $this->identifier, true);
483
    }
484
485 1200
    public function isIdentifierComposite() : bool
486
    {
487 1200
        return isset($this->identifier[1]);
488
    }
489
490
    /**
491
     * Gets the named native query.
492
     *
493
     * @see ClassMetadata::$namedNativeQueries
494
     *
495
     * @param string $queryName The query name.
496
     *
497
     * @return string[]
498
     *
499
     * @throws MappingException
500
     */
501 15
    public function getNamedNativeQuery($queryName) : array
502
    {
503 15
        if (! isset($this->namedNativeQueries[$queryName])) {
504
            throw MappingException::queryNotFound($this->className, $queryName);
505
        }
506
507 15
        return $this->namedNativeQueries[$queryName];
508
    }
509
510
    /**
511
     * Gets all named native queries of the class.
512
     *
513
     * @return string[]
514
     */
515 3
    public function getNamedNativeQueries() : array
516
    {
517 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...
518
    }
519
520
    /**
521
     * Gets the result set mapping.
522
     *
523
     * @see ClassMetadata::$sqlResultSetMappings
524
     *
525
     * @param string $name The result set mapping name.
526
     *
527
     * @return mixed[]
528
     *
529
     * @throws MappingException
530
     */
531 13
    public function getSqlResultSetMapping($name)
532
    {
533 13
        if (! isset($this->sqlResultSetMappings[$name])) {
534
            throw MappingException::resultMappingNotFound($this->className, $name);
535
        }
536
537 13
        return $this->sqlResultSetMappings[$name];
538
    }
539
540
    /**
541
     * Gets all sql result set mappings of the class.
542
     *
543
     * @return mixed[][]
544
     */
545 5
    public function getSqlResultSetMappings()
546
    {
547 5
        return $this->sqlResultSetMappings;
548
    }
549
550
    /**
551
     * Validates & completes the basic mapping information for field mapping.
552
     *
553
     * @throws MappingException If something is wrong with the mapping.
554
     */
555 397
    protected function validateAndCompleteFieldMapping(FieldMetadata $property)
556
    {
557 397
        $fieldName  = $property->getName();
558 397
        $columnName = $property->getColumnName();
559
560 397
        if (empty($columnName)) {
561 340
            $columnName = $this->namingStrategy->propertyToColumnName($fieldName, $this->className);
562
563 340
            $property->setColumnName($columnName);
564
        }
565
566 397
        if (! $this->isMappedSuperclass) {
567 390
            $property->setTableName($this->getTableName());
568
        }
569
570
        // Check for already declared column
571 397
        if (isset($this->fieldNames[$columnName]) ||
572 397
            ($this->discriminatorColumn !== null && $this->discriminatorColumn->getColumnName() === $columnName)) {
573 2
            throw MappingException::duplicateColumnName($this->className, $columnName);
574
        }
575
576
        // Complete id mapping
577 396
        if ($property->isPrimaryKey()) {
578 381
            if ($this->versionProperty !== null && $this->versionProperty->getName() === $fieldName) {
579
                throw MappingException::cannotVersionIdField($this->className, $fieldName);
580
            }
581
582 381
            if ($property->getType()->canRequireSQLConversion()) {
583
                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

583
                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

583
                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...
584
            }
585
586 381
            if (! in_array($fieldName, $this->identifier, true)) {
587 381
                $this->identifier[] = $fieldName;
588
            }
589
        }
590
591 396
        $this->fieldNames[$columnName] = $fieldName;
592 396
    }
593
594
    /**
595
     * Validates & completes the basic mapping information for field mapping.
596
     *
597
     * @throws MappingException If something is wrong with the mapping.
598
     */
599 19
    protected function validateAndCompleteVersionFieldMapping(VersionFieldMetadata $property)
600
    {
601 19
        $this->versionProperty = $property;
602
603 19
        $options = $property->getOptions();
604
605 19
        if (isset($options['default'])) {
606
            return;
607
        }
608
609 19
        if (in_array($property->getTypeName(), ['integer', 'bigint', 'smallint'], true)) {
610 18
            $property->setOptions(array_merge($options, ['default' => 1]));
611
612 18
            return;
613
        }
614
615 2
        if ($property->getTypeName() === 'datetime') {
616 1
            $property->setOptions(array_merge($options, ['default' => 'CURRENT_TIMESTAMP']));
617
618 1
            return;
619
        }
620
621 1
        throw MappingException::unsupportedOptimisticLockingType($property->getType());
622
    }
623
624
    /**
625
     * Validates & completes the basic mapping information that is common to all
626
     * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
627
     *
628
     * @throws MappingException If something is wrong with the mapping.
629
     * @throws CacheException   If entity is not cacheable.
630
     */
631 278
    protected function validateAndCompleteAssociationMapping(AssociationMetadata $property)
632
    {
633 278
        $fieldName    = $property->getName();
634 278
        $targetEntity = $property->getTargetEntity();
635
636 278
        if (! $targetEntity) {
637
            throw MappingException::missingTargetEntity($fieldName);
638
        }
639
640 278
        $property->setSourceEntity($this->className);
641 278
        $property->setOwningSide($property->getMappedBy() === null);
642 278
        $property->setTargetEntity($targetEntity);
643
644
        // Complete id mapping
645 278
        if ($property->isPrimaryKey()) {
646 44
            if ($property->isOrphanRemoval()) {
647 1
                throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->className, $fieldName);
648
            }
649
650 43
            if (! in_array($property->getName(), $this->identifier, true)) {
651 43
                if ($property instanceof ToOneAssociationMetadata && count($property->getJoinColumns()) >= 2) {
652
                    throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
653
                        $property->getTargetEntity(),
654
                        $this->className,
655
                        $fieldName
656
                    );
657
                }
658
659 43
                $this->identifier[] = $property->getName();
660
            }
661
662 43
            if ($this->cache && ! $property->getCache()) {
663 2
                throw CacheException::nonCacheableEntityAssociation($this->className, $fieldName);
664
            }
665
666 41
            if ($property instanceof ToManyAssociationMetadata) {
667 1
                throw MappingException::illegalToManyIdentifierAssociation($this->className, $property->getName());
668
            }
669
        }
670
671
        // Cascades
672 274
        $cascadeTypes = ['remove', 'persist', 'refresh'];
673 274
        $cascades     = array_map('strtolower', $property->getCascade());
674
675 274
        if (in_array('all', $cascades, true)) {
676 3
            $cascades = $cascadeTypes;
677
        }
678
679 274
        if (count($cascades) !== count(array_intersect($cascades, $cascadeTypes))) {
680 1
            $diffCascades = array_diff($cascades, array_intersect($cascades, $cascadeTypes));
681
682 1
            throw MappingException::invalidCascadeOption($diffCascades, $this->className, $fieldName);
683
        }
684
685 273
        $property->setCascade($cascades);
686 273
    }
687
688
    /**
689
     * Validates & completes a to-one association mapping.
690
     *
691
     * @param ToOneAssociationMetadata $property The association mapping to validate & complete.
692
     *
693
     * @throws \RuntimeException
694
     * @throws MappingException
695
     */
696 238
    protected function validateAndCompleteToOneAssociationMetadata(ToOneAssociationMetadata $property)
697
    {
698 238
        $fieldName = $property->getName();
699
700 238
        if ($property->getJoinColumns()) {
701 167
            $property->setOwningSide(true);
702
        }
703
704 238
        if ($property->isOwningSide()) {
705 235
            if (empty($property->getJoinColumns())) {
706
                // Apply default join column
707 81
                $property->addJoinColumn(new JoinColumnMetadata());
708
            }
709
710 235
            $uniqueConstraintColumns = [];
711
712 235
            foreach ($property->getJoinColumns() as $joinColumn) {
713
                /** @var JoinColumnMetadata $joinColumn */
714 235
                if ($property instanceof OneToOneAssociationMetadata && $this->inheritanceType !== InheritanceType::SINGLE_TABLE) {
715 115
                    if (count($property->getJoinColumns()) === 1) {
716 113
                        if (! $property->isPrimaryKey()) {
717 113
                            $joinColumn->setUnique(true);
718
                        }
719
                    } else {
720 2
                        $uniqueConstraintColumns[] = $joinColumn->getColumnName();
721
                    }
722
                }
723
724 235
                $joinColumn->setTableName(! $this->isMappedSuperclass ? $this->getTableName() : null);
725
726 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...
727 99
                    $joinColumn->setColumnName($this->namingStrategy->joinColumnName($fieldName, $this->className));
728
                }
729
730 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...
731 81
                    $joinColumn->setReferencedColumnName($this->namingStrategy->referenceColumnName());
732
                }
733
734 235
                $this->fieldNames[$joinColumn->getColumnName()] = $fieldName;
735
            }
736
737 235
            if ($uniqueConstraintColumns) {
0 ignored issues
show
introduced by
The condition $uniqueConstraintColumns can never be true.
Loading history...
738 2
                if (! $this->table) {
739
                    throw new \RuntimeException(
740
                        'ClassMetadata::setTable() has to be called before defining a one to one relationship.'
741
                    );
742
                }
743
744 2
                $this->table->addUniqueConstraint(
745
                    [
746 2
                        'name'    => sprintf('%s_uniq', $fieldName),
747 2
                        'columns' => $uniqueConstraintColumns,
748
                        'options' => [],
749
                        'flags'   => [],
750
                    ]
751
                );
752
            }
753
        }
754
755 238
        if ($property->isOrphanRemoval()) {
756 9
            $cascades = $property->getCascade();
757
758 9
            if (! in_array('remove', $cascades, true)) {
759 8
                $cascades[] = 'remove';
760
761 8
                $property->setCascade($cascades);
762
            }
763
764
            // @todo guilhermeblanco where is this used?
765
            // @todo guilhermeblanco Shouldn￿'t we iterate through JoinColumns to set non-uniqueness?
766
            //$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...
767
        }
768
769 238
        if ($property->isPrimaryKey() && ! $property->isOwningSide()) {
770 1
            throw MappingException::illegalInverseIdentifierAssociation($this->className, $fieldName);
771
        }
772 237
    }
773
774
    /**
775
     * Validates & completes a to-many association mapping.
776
     *
777
     * @param ToManyAssociationMetadata $property The association mapping to validate & complete.
778
     *
779
     * @throws MappingException
780
     */
781 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

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

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

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

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

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

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

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

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

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

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

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