Completed
Pull Request — master (#7825)
by
unknown
09:20
created

JoinedSubclassPersister::getSelectColumnsSQL()   D

Complexity

Conditions 19
Paths 65

Size

Total Lines 93
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 19.0261

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 19
eloc 48
c 1
b 0
f 0
nc 65
nop 0
dl 0
loc 93
ccs 46
cts 48
cp 0.9583
crap 19.0261
rs 4.5166

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\Persisters\Entity;
6
7
use Doctrine\Common\Collections\Criteria;
8
use Doctrine\DBAL\LockMode;
9
use Doctrine\DBAL\Statement;
10
use Doctrine\DBAL\Types\Type;
11
use Doctrine\ORM\Mapping\AssociationMetadata;
12
use Doctrine\ORM\Mapping\FieldMetadata;
13
use Doctrine\ORM\Mapping\GeneratorType;
14
use Doctrine\ORM\Mapping\JoinColumnMetadata;
15
use Doctrine\ORM\Mapping\ManyToManyAssociationMetadata;
16
use Doctrine\ORM\Mapping\ToManyAssociationMetadata;
17
use Doctrine\ORM\Mapping\ToOneAssociationMetadata;
18
use Doctrine\ORM\Utility\PersisterHelper;
19
use function array_combine;
20
use function array_keys;
21
use function implode;
22
use function is_array;
23
24
/**
25
 * The joined subclass persister maps a single entity instance to several tables in the
26
 * database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
27
 *
28
 * @see https://martinfowler.com/eaaCatalog/classTableInheritance.html
29
 */
30
class JoinedSubclassPersister extends AbstractEntityInheritancePersister
31
{
32
    /**
33
     * {@inheritdoc}
34
     */
35 296
    public function insert($entity)
36
    {
37 296
        $rootClass      = ! $this->class->isRootEntity()
38 290
            ? $this->em->getClassMetadata($this->class->getRootClassName())
39 296
            : $this->class;
40 296
        $generationPlan = $this->class->getValueGenerationPlan();
41
42
        // Prepare statement for the root table
43 296
        $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->getClassName());
0 ignored issues
show
Bug introduced by
The method getClassName() 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

43
        $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->/** @scrutinizer ignore-call */ getClassName());

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...
44 296
        $rootTableName = $rootClass->getTableName();
0 ignored issues
show
Bug introduced by
The method getTableName() 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

44
        /** @scrutinizer ignore-call */ 
45
        $rootTableName = $rootClass->getTableName();

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...
45 296
        $rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL());
0 ignored issues
show
Bug introduced by
The method getInsertSQL() does not exist on Doctrine\ORM\Persisters\Entity\EntityPersister. It seems like you code against a sub-type of said class. However, the method does not exist in Doctrine\ORM\Cache\Persi...y\CachedEntityPersister. Are you sure you never get one of those? ( Ignorable by Annotation )

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

45
        $rootTableStmt = $this->conn->prepare($rootPersister->/** @scrutinizer ignore-call */ getInsertSQL());
Loading history...
46
47
        // Prepare statements for sub tables.
48 296
        $subTableStmts = [];
49
50 296
        if ($rootClass !== $this->class) {
51 290
            $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
52
        }
53
54 296
        $parentClass = $this->class;
55
56 296
        while (($parentClass = $parentClass->getParent()) !== null) {
57 290
            if (! $parentClass->isMappedSuperclass) {
58 290
                $parentTableName = $parentClass->getTableName();
0 ignored issues
show
Bug introduced by
The method getTableName() does not exist on Doctrine\ORM\Mapping\ComponentMetadata. It seems like you code against a sub-type of Doctrine\ORM\Mapping\ComponentMetadata such as Doctrine\ORM\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

58
                /** @scrutinizer ignore-call */ 
59
                $parentTableName = $parentClass->getTableName();
Loading history...
59
60 290
                if ($parentClass !== $rootClass) {
61 170
                    $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClass->getClassName());
62
63 170
                    $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL());
64
                }
65
            }
66
        }
67
68
        // Execute all inserts. For each entity:
69
        // 1) Insert on root table
70
        // 2) Insert on sub tables
71 296
        $insertData = $this->prepareInsertData($entity);
72
73
        // Execute insert on root table
74 296
        $paramIndex = 1;
75
76 296
        foreach ($insertData[$rootTableName] as $columnName => $value) {
77 296
            $type = $this->columns[$columnName]->getType();
78
79 296
            $rootTableStmt->bindValue($paramIndex++, $value, $type);
80
        }
81
82 296
        $rootTableStmt->execute();
83
84 296
        if ($generationPlan->containsDeferred()) {
85 292
            $generationPlan->executeDeferred($this->em, $entity);
86 292
            $id = $this->getIdentifier($entity);
87
        } else {
88 4
            $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
89
        }
90
91 296
        if ($this->class->isVersioned()) {
92 9
            $this->assignDefaultVersionValue($entity, $id);
93
        }
94
95
        // Execute inserts on subtables.
96
        // The order doesn't matter because all child tables link to the root table via FK.
97 296
        foreach ($subTableStmts as $tableName => $stmt) {
98
            /** @var Statement $stmt */
99 290
            $paramIndex = 1;
100 290
            $data       = $insertData[$tableName] ?? [];
101
102 290
            foreach ((array) $id as $idName => $idVal) {
103 290
                $type = Type::getType('string');
104
105 290
                if (isset($this->columns[$idName])) {
106 290
                    $type = $this->columns[$idName]->getType();
107
                }
108
109 290
                $stmt->bindValue($paramIndex++, $idVal, $type);
110
            }
111
112 290
            foreach ($data as $columnName => $value) {
113 225
                if (! is_array($id) || ! isset($id[$columnName])) {
114 225
                    $type = $this->columns[$columnName]->getType();
115
116 225
                    $stmt->bindValue($paramIndex++, $value, $type);
117
                }
118
            }
119
120 290
            $stmt->execute();
121
        }
122
123 296
        $rootTableStmt->closeCursor();
124
125 296
        foreach ($subTableStmts as $stmt) {
126 290
            $stmt->closeCursor();
127
        }
128 296
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 31
    public function update($entity)
134
    {
135 31
        $updateData = $this->prepareUpdateData($entity);
136
137 31
        if (! $updateData) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $updateData of type 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...
138
            return;
139
        }
140
141 31
        $isVersioned = $this->class->isVersioned();
142
143 31
        foreach ($updateData as $tableName => $data) {
144 31
            $versioned = $isVersioned && $this->class->versionProperty->getTableName() === $tableName;
145
146 31
            $this->updateTable($entity, $this->platform->quoteIdentifier($tableName), $data, $versioned);
147
        }
148
149
        // Make sure the table with the version column is updated even if no columns on that
150
        // table were affected.
151 30
        if ($isVersioned) {
152 5
            $versionedClass = $this->class->versionProperty->getDeclaringClass();
0 ignored issues
show
Bug introduced by
The method getDeclaringClass() does not exist on null. ( Ignorable by Annotation )

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

152
            /** @scrutinizer ignore-call */ 
153
            $versionedClass = $this->class->versionProperty->getDeclaringClass();

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...
153 5
            $versionedTable = $versionedClass->getTableName();
154
155 5
            if (! isset($updateData[$versionedTable])) {
156 2
                $tableName = $versionedClass->table->getQuotedQualifiedName($this->platform);
157
158 2
                $this->updateTable($entity, $tableName, [], true);
159
            }
160
161 4
            $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
162
163 4
            $this->assignDefaultVersionValue($entity, $identifiers);
164
        }
165 29
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 5
    public function delete($entity)
171
    {
172 5
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
173 5
        $id         = array_combine(array_keys($this->class->getIdentifierColumns($this->em)), $identifier);
174
175 5
        $this->deleteJoinTableRecords($identifier);
176
177
        // If the database platform supports FKs, just
178
        // delete the row from the root table. Cascades do the rest.
179 5
        if ($this->platform->supportsForeignKeyConstraints()) {
180
            $rootClass = $this->em->getClassMetadata($this->class->getRootClassName());
181
            $rootTable = $rootClass->table->getQuotedQualifiedName($this->platform);
0 ignored issues
show
Bug introduced by
Accessing table on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
182
183
            return (bool) $this->conn->delete($rootTable, $id);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type false; however, parameter $identifier of Doctrine\DBAL\Connection::delete() does only seem to accept array, 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

183
            return (bool) $this->conn->delete($rootTable, /** @scrutinizer ignore-type */ $id);
Loading history...
184
        }
185
186
        // Delete from all tables individually, starting from this class' table up to the root table.
187 5
        $rootTable    = $this->class->table->getQuotedQualifiedName($this->platform);
188 5
        $affectedRows = $this->conn->delete($rootTable, $id);
189 5
        $parentClass  = $this->class;
190
191 5
        while (($parentClass = $parentClass->getParent()) !== null) {
192 4
            if (! $parentClass->isMappedSuperclass) {
193 4
                $parentTable = $parentClass->table->getQuotedQualifiedName($this->platform);
194
195 4
                $this->conn->delete($parentTable, $id);
196
            }
197
        }
198
199 5
        return (bool) $affectedRows;
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205 69
    public function getSelectSQL(
206
        $criteria,
207
        ?AssociationMetadata $association = null,
208
        $lockMode = null,
209
        $limit = null,
210
        $offset = null,
211
        array $orderBy = []
212
    ) {
213 69
        $this->switchPersisterContext($offset, $limit);
214
215 69
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
216 69
        $joinSql        = $this->getJoinSql($baseTableAlias);
217
218 69
        if ($association instanceof ManyToManyAssociationMetadata) {
219 2
            $joinSql .= $this->getSelectManyToManyJoinSQL($association);
220
        }
221
222 69
        if ($association instanceof ToManyAssociationMetadata && $association->getOrderBy()) {
223 1
            $orderBy = $association->getOrderBy();
224
        }
225
226 69
        $orderBySql   = $this->getOrderBySQL($orderBy, $baseTableAlias);
227 69
        $conditionSql = $criteria instanceof Criteria
228
            ? $this->getSelectConditionCriteriaSQL($criteria)
229 69
            : $this->getSelectConditionSQL($criteria, $association);
230
231
        // If the current class in the root entity, add the filters
232 69
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
233 69
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
234 69
        $filterSql  = $this->generateFilterConditionSQL($rootClass, $tableAlias);
235
236 69
        if ($filterSql) {
237 4
            $conditionSql .= $conditionSql
238 2
                ? ' AND ' . $filterSql
239 4
                : $filterSql;
240
        }
241
242 69
        $lockSql = '';
243
244
        switch ($lockMode) {
245 69
            case LockMode::PESSIMISTIC_READ:
246
                $lockSql = ' ' . $this->platform->getReadLockSQL();
247
                break;
248
249 69
            case LockMode::PESSIMISTIC_WRITE:
250
                $lockSql = ' ' . $this->platform->getWriteLockSQL();
251
                break;
252
        }
253
254 69
        $tableName  = $this->class->table->getQuotedQualifiedName($this->platform);
255 69
        $from       = ' FROM ' . $tableName . ' ' . $baseTableAlias;
256 69
        $where      = $conditionSql !== '' ? ' WHERE ' . $conditionSql : '';
257 69
        $lock       = $this->platform->appendLockHint($from, $lockMode);
258 69
        $columnList = $this->getSelectColumnsSQL();
259 69
        $query      = 'SELECT ' . $columnList
260 69
                    . $lock
261 69
                    . $joinSql
262 69
                    . $where
263 69
                    . $orderBySql;
264
265 69
        return $this->platform->modifyLimitQuery($query, $limit, $offset ?? 0) . $lockSql;
266
    }
267
268
    /**
269
     * {@inheritDoc}
270
     */
271 6
    public function getCountSQL($criteria = [])
272
    {
273 6
        $tableName      = $this->class->table->getQuotedQualifiedName($this->platform);
274 6
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
275 6
        $joinSql        = $this->getJoinSql($baseTableAlias);
276
277 6
        $conditionSql = $criteria instanceof Criteria
278 1
            ? $this->getSelectConditionCriteriaSQL($criteria)
279 6
            : $this->getSelectConditionSQL($criteria);
280
281 6
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
282 6
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
283 6
        $filterSql  = $this->generateFilterConditionSQL($rootClass, $tableAlias);
284
285 6
        if ($filterSql !== '') {
286 1
            $conditionSql = $conditionSql
287 1
                ? $conditionSql . ' AND ' . $filterSql
288 1
                : $filterSql;
289
        }
290
291
        return 'SELECT COUNT(*) '
292 6
            . 'FROM ' . $tableName . ' ' . $baseTableAlias
293 6
            . $joinSql
294 6
            . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
295
    }
296
297
    /**
298
     * {@inheritdoc}
299
     */
300 7
    protected function getLockTablesSql($lockMode)
301
    {
302 7
        $joinSql           = '';
303 7
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
304 7
        $baseTableAlias    = $this->getSQLTableAlias($this->class->getTableName());
305
306
        // INNER JOIN parent tables
307 7
        $parentClass = $this->class;
308
309 7
        while (($parentClass = $parentClass->getParent()) !== null) {
310 6
            if (! $parentClass->isMappedSuperclass) {
311 6
                $conditions = [];
312 6
                $tableName  = $parentClass->table->getQuotedQualifiedName($this->platform);
313 6
                $tableAlias = $this->getSQLTableAlias($parentClass->getTableName());
314 6
                $joinSql   .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
315
316 6
                foreach ($identifierColumns as $idColumn) {
317 6
                    $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
318
319 6
                    $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
320
                }
321
322 6
                $joinSql .= implode(' AND ', $conditions);
323
            }
324
        }
325
326 7
        return parent::getLockTablesSql($lockMode) . $joinSql;
327
    }
328
329
    /**
330
     * Ensure this method is never called. This persister overrides getSelectEntitiesSQL directly.
331
     *
332
     * @return string
333
     */
334 69
    protected function getSelectColumnsSQL()
335
    {
336
        // Create the column list fragment only once
337 69
        if ($this->currentPersisterContext->selectColumnListSql !== null) {
338 13
            return $this->currentPersisterContext->selectColumnListSql;
339
        }
340
341 69
        $this->currentPersisterContext->rsm->addEntityResult($this->class->getClassName(), 'r');
342
343 69
        $columnList = [];
344
345
        // Add columns
346 69
        foreach ($this->class->getPropertiesIterator() as $fieldName => $property) {
347 69
            if ($property instanceof FieldMetadata) {
348 69
                $tableClass = $parentClass = $this->class;
349 69
                while ($parentClass !== $property->getDeclaringClass() && ($parentClass = $parentClass->getParent()) !== null) {
350 46
                    if (! $parentClass->isMappedSuperclass) {
351 46
                        $tableClass = $parentClass;
352
                    }
353
                }
354 69
                $columnList[] = $this->getSelectColumnSQL($fieldName, $tableClass);
355
356 69
                continue;
357
            }
358
359 57
            if (! ($property instanceof ToOneAssociationMetadata) || ! $property->isOwningSide()) {
360 44
                continue;
361
            }
362
363 56
            $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
364
365 56
            foreach ($property->getJoinColumns() as $joinColumn) {
366
                /** @var JoinColumnMetadata $joinColumn */
367 56
                $referencedColumnName = $joinColumn->getReferencedColumnName();
368
369 56
                if (! $joinColumn->getType()) {
370
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
371
                }
372
373 56
                $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
374
            }
375
        }
376
377
        // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
378 69
        $discrColumn      = $this->class->discriminatorColumn;
379 69
        $discrTableAlias  = $this->getSQLTableAlias($discrColumn->getTableName());
380 69
        $discrColumnName  = $discrColumn->getColumnName();
381 69
        $discrColumnType  = $discrColumn->getType();
382 69
        $resultColumnName = $this->platform->getSQLResultCasing($discrColumnName);
383 69
        $quotedColumnName = $this->platform->quoteIdentifier($discrColumn->getColumnName());
384
385 69
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
386 69
        $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType);
0 ignored issues
show
Bug introduced by
It seems like $discrColumnType can also be of type null; however, parameter $type of Doctrine\ORM\Query\Resul...apping::addMetaResult() does only seem to accept Doctrine\DBAL\Types\Type, 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

386
        $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, /** @scrutinizer ignore-type */ $discrColumnType);
Loading history...
387
388 69
        $columnList[] = $discrColumnType->convertToDatabaseValueSQL($discrTableAlias . '.' . $quotedColumnName, $this->platform);
389
390
        // sub tables
391 69
        foreach ($this->class->getSubClasses() as $subClassName) {
392 50
            $subClass = $this->em->getClassMetadata($subClassName);
393
394
            // Add columns
395 50
            foreach ($subClass->getPropertiesIterator() as $fieldName => $property) {
0 ignored issues
show
Bug introduced by
The method getPropertiesIterator() 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

395
            foreach ($subClass->/** @scrutinizer ignore-call */ getPropertiesIterator() as $fieldName => $property) {

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...
396 50
                if ($subClass->isInheritedProperty($fieldName)) {
0 ignored issues
show
Bug introduced by
The method isInheritedProperty() 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

396
                if ($subClass->/** @scrutinizer ignore-call */ isInheritedProperty($fieldName)) {

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...
397 50
                    continue;
398
                }
399
400
                switch (true) {
401 46
                    case $property instanceof FieldMetadata:
402 46
                        $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
403 46
                        break;
404
405 32
                    case $property instanceof ToOneAssociationMetadata && $property->isOwningSide():
406 32
                        $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
407
408 32
                        foreach ($property->getJoinColumns() as $joinColumn) {
409
                            /** @var JoinColumnMetadata $joinColumn */
410 32
                            $referencedColumnName = $joinColumn->getReferencedColumnName();
411
412 32
                            if (! $joinColumn->getType()) {
413
                                $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
414
                            }
415
416 32
                            $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
417
                        }
418
419 32
                        break;
420
                }
421
            }
422
        }
423
424 69
        $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
425
426 69
        return $this->currentPersisterContext->selectColumnListSql;
427
    }
428
429
    /**
430
     * {@inheritdoc}
431
     */
432 296
    protected function getInsertColumnList()
433
    {
434
        // Identifier columns must always come first in the column list of subclasses.
435 296
        $columns       = [];
436 296
        $parentColumns = $this->class->isRootEntity()
437 296
            ? []
438 296
            : $this->class->getIdentifierColumns($this->em);
439
440 296
        foreach ($parentColumns as $columnName => $column) {
441 290
            $columns[] = $columnName;
442
443 290
            $this->columns[$columnName] = $column;
444
        }
445
446 296
        foreach ($this->class->getPropertiesIterator() as $name => $property) {
447 296
            if (($property instanceof FieldMetadata && ($property->isVersioned() || $this->class->isInheritedProperty($name)))
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($property instanceof Do...nheritedProperty($name), Probably Intended Meaning: $property instanceof Doc...heritedProperty($name))
Loading history...
448 296
                || ($property instanceof AssociationMetadata && $this->class->isInheritedProperty($name))
449
                /*|| isset($this->class->embeddedClasses[$name])*/) {
450 294
                continue;
451
            }
452
453 296
            if ($property instanceof AssociationMetadata) {
454 266
                if ($property->isOwningSide() && $property instanceof ToOneAssociationMetadata) {
455 265
                    $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
456
457 265
                    foreach ($property->getJoinColumns() as $joinColumn) {
458
                        /** @var JoinColumnMetadata $joinColumn */
459 265
                        $columnName           = $joinColumn->getColumnName();
460 265
                        $referencedColumnName = $joinColumn->getReferencedColumnName();
461
462 265
                        if (! $joinColumn->getType()) {
463 13
                            $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
464
                        }
465
466 265
                        $columns[] = $columnName;
467
468 265
                        $this->columns[$columnName] = $joinColumn;
469
                    }
470
                }
471
472 266
                continue;
473
            }
474
475 296
            if ($this->class->getClassName() !== $this->class->getRootClassName()
476 296
                || ! $this->class->getProperty($name)->hasValueGenerator()
0 ignored issues
show
Bug introduced by
The method hasValueGenerator() 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

476
                || ! $this->class->getProperty($name)->/** @scrutinizer ignore-call */ hasValueGenerator()
Loading history...
477 292
                || $this->class->getProperty($name)->getValueGenerator()->getType() !== GeneratorType::IDENTITY
0 ignored issues
show
Bug introduced by
The method getValueGenerator() does not exist on Doctrine\ORM\Mapping\Property. Did you maybe mean getValue()? ( Ignorable by Annotation )

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

477
                || $this->class->getProperty($name)->/** @scrutinizer ignore-call */ getValueGenerator()->getType() !== GeneratorType::IDENTITY

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...
478 296
                || $this->class->identifier[0] !== $name
479
            ) {
480 234
                $columnName = $property->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

480
                /** @scrutinizer ignore-call */ 
481
                $columnName = $property->getColumnName();
Loading history...
481
482 234
                $columns[] = $columnName;
483
484 234
                $this->columns[$columnName] = $property;
485
            }
486
        }
487
488
        // Add discriminator column if it is the topmost class.
489 296
        if ($this->class->isRootEntity()) {
490 296
            $discrColumn     = $this->class->discriminatorColumn;
491 296
            $discrColumnName = $discrColumn->getColumnName();
492
493 296
            $columns[] = $discrColumnName;
494
495 296
            $this->columns[$discrColumnName] = $discrColumn;
496
        }
497
498 296
        return $columns;
499
    }
500
501
    /**
502
     * @param string $baseTableAlias
503
     *
504
     * @return string
505
     */
506 74
    private function getJoinSql($baseTableAlias)
507
    {
508 74
        $joinSql           = '';
509 74
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
510
511
        // INNER JOIN parent tables
512 74
        $parentClass = $this->class;
513
514 74
        while (($parentClass = $parentClass->getParent()) !== null) {
515 50
            if (! $parentClass->isMappedSuperclass) {
516 50
                $conditions = [];
517 50
                $tableName  = $parentClass->table->getQuotedQualifiedName($this->platform);
518 50
                $tableAlias = $this->getSQLTableAlias($parentClass->getTableName());
519 50
                $joinSql   .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
520
521 50
                foreach ($identifierColumns as $idColumn) {
522 50
                    $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
523
524 50
                    $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
525
                }
526
527 50
                $joinSql .= implode(' AND ', $conditions);
528
            }
529
        }
530
531
        // OUTER JOIN sub tables
532 74
        foreach ($this->class->getSubClasses() as $subClassName) {
533 52
            $conditions = [];
534 52
            $subClass   = $this->em->getClassMetadata($subClassName);
535 52
            $tableName  = $subClass->table->getQuotedQualifiedName($this->platform);
0 ignored issues
show
Bug introduced by
Accessing table on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
536 52
            $tableAlias = $this->getSQLTableAlias($subClass->getTableName());
537 52
            $joinSql   .= ' LEFT JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
538
539 52
            foreach ($identifierColumns as $idColumn) {
540 52
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
541
542 52
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
543
            }
544
545 52
            $joinSql .= implode(' AND ', $conditions);
546
        }
547
548 74
        return $joinSql;
549
    }
550
}
551