Completed
Pull Request — master (#7825)
by
unknown
09:24
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 295
    public function insert($entity)
36
    {
37 295
        $rootClass      = ! $this->class->isRootEntity()
38 289
            ? $this->em->getClassMetadata($this->class->getRootClassName())
39 295
            : $this->class;
40 295
        $generationPlan = $this->class->getValueGenerationPlan();
41
42
        // Prepare statement for the root table
43 295
        $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 295
        $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 295
        $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 295
        $subTableStmts = [];
49
50 295
        if ($rootClass !== $this->class) {
51 289
            $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
52
        }
53
54 295
        $parentClass = $this->class;
55
56 295
        while (($parentClass = $parentClass->getParent()) !== null) {
57 289
            if (! $parentClass->isMappedSuperclass) {
58 289
                $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 289
                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 295
        $insertData = $this->prepareInsertData($entity);
72
73
        // Execute insert on root table
74 295
        $paramIndex = 1;
75
76 295
        foreach ($insertData[$rootTableName] as $columnName => $value) {
77 295
            $type = $this->columns[$columnName]->getType();
78
79 295
            $rootTableStmt->bindValue($paramIndex++, $value, $type);
80
        }
81
82 295
        $rootTableStmt->execute();
83
84 295
        if ($generationPlan->containsDeferred()) {
85 291
            $generationPlan->executeDeferred($this->em, $entity);
86 291
            $id = $this->getIdentifier($entity);
87
        } else {
88 4
            $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
89
        }
90
91 295
        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 295
        foreach ($subTableStmts as $tableName => $stmt) {
98
            /** @var Statement $stmt */
99 289
            $paramIndex = 1;
100 289
            $data       = $insertData[$tableName] ?? [];
101
102 289
            foreach ((array) $id as $idName => $idVal) {
103 289
                $type = Type::getType('string');
104
105 289
                if (isset($this->columns[$idName])) {
106 289
                    $type = $this->columns[$idName]->getType();
107
                }
108
109 289
                $stmt->bindValue($paramIndex++, $idVal, $type);
110
            }
111
112 289
            foreach ($data as $columnName => $value) {
113 224
                if (! is_array($id) || ! isset($id[$columnName])) {
114 224
                    $type = $this->columns[$columnName]->getType();
115
116 224
                    $stmt->bindValue($paramIndex++, $value, $type);
117
                }
118
            }
119
120 289
            $stmt->execute();
121
        }
122
123 295
        $rootTableStmt->closeCursor();
124
125 295
        foreach ($subTableStmts as $stmt) {
126 289
            $stmt->closeCursor();
127
        }
128 295
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 30
    public function update($entity)
134
    {
135 30
        $updateData = $this->prepareUpdateData($entity);
136
137 30
        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 30
        $isVersioned = $this->class->isVersioned();
142
143 30
        foreach ($updateData as $tableName => $data) {
144 30
            $versioned = $isVersioned && $this->class->versionProperty->getTableName() === $tableName;
145
146 30
            $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 29
        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 28
    }
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 68
    public function getSelectSQL(
206
        $criteria,
207
        ?AssociationMetadata $association = null,
208
        $lockMode = null,
209
        $limit = null,
210
        $offset = null,
211
        array $orderBy = []
212
    ) {
213 68
        $this->switchPersisterContext($offset, $limit);
214
215 68
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
216 68
        $joinSql        = $this->getJoinSql($baseTableAlias);
217
218 68
        if ($association instanceof ManyToManyAssociationMetadata) {
219 2
            $joinSql .= $this->getSelectManyToManyJoinSQL($association);
220
        }
221
222 68
        if ($association instanceof ToManyAssociationMetadata && $association->getOrderBy()) {
223 1
            $orderBy = $association->getOrderBy();
224
        }
225
226 68
        $orderBySql   = $this->getOrderBySQL($orderBy, $baseTableAlias);
227 68
        $conditionSql = $criteria instanceof Criteria
228
            ? $this->getSelectConditionCriteriaSQL($criteria)
229 68
            : $this->getSelectConditionSQL($criteria, $association);
230
231
        // If the current class in the root entity, add the filters
232 68
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
233 68
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
234 68
        $filterSql  = $this->generateFilterConditionSQL($rootClass, $tableAlias);
235
236 68
        if ($filterSql) {
237 4
            $conditionSql .= $conditionSql
238 2
                ? ' AND ' . $filterSql
239 4
                : $filterSql;
240
        }
241
242 68
        $lockSql = '';
243
244
        switch ($lockMode) {
245 68
            case LockMode::PESSIMISTIC_READ:
246
                $lockSql = ' ' . $this->platform->getReadLockSQL();
247
                break;
248
249 68
            case LockMode::PESSIMISTIC_WRITE:
250
                $lockSql = ' ' . $this->platform->getWriteLockSQL();
251
                break;
252
        }
253
254 68
        $tableName  = $this->class->table->getQuotedQualifiedName($this->platform);
255 68
        $from       = ' FROM ' . $tableName . ' ' . $baseTableAlias;
256 68
        $where      = $conditionSql !== '' ? ' WHERE ' . $conditionSql : '';
257 68
        $lock       = $this->platform->appendLockHint($from, $lockMode);
258 68
        $columnList = $this->getSelectColumnsSQL();
259 68
        $query      = 'SELECT ' . $columnList
260 68
                    . $lock
261 68
                    . $joinSql
262 68
                    . $where
263 68
                    . $orderBySql;
264
265 68
        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 68
    protected function getSelectColumnsSQL()
335
    {
336
        // Create the column list fragment only once
337 68
        if ($this->currentPersisterContext->selectColumnListSql !== null) {
338 13
            return $this->currentPersisterContext->selectColumnListSql;
339
        }
340
341 68
        $this->currentPersisterContext->rsm->addEntityResult($this->class->getClassName(), 'r');
342
343 68
        $columnList = [];
344
345
        // Add columns
346 68
        foreach ($this->class->getPropertiesIterator() as $fieldName => $property) {
347 68
            if ($property instanceof FieldMetadata) {
348 68
                $tableClass = $parentClass = $this->class;
349 68
                while ($parentClass !== $property->getDeclaringClass() && ($parentClass = $parentClass->getParent()) !== null) {
350 46
                    if (! $parentClass->isMappedSuperclass) {
351 46
                        $tableClass = $parentClass;
352
                    }
353
                }
354 68
                $columnList[] = $this->getSelectColumnSQL($fieldName, $tableClass);
355
356 68
                continue;
357
            }
358
359 55
            if (! ($property instanceof ToOneAssociationMetadata) || ! $property->isOwningSide()) {
360 43
                continue;
361
            }
362
363 54
            $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
364
365 54
            foreach ($property->getJoinColumns() as $joinColumn) {
366
                /** @var JoinColumnMetadata $joinColumn */
367 54
                $referencedColumnName = $joinColumn->getReferencedColumnName();
368
369 54
                if (! $joinColumn->getType()) {
370
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
371
                }
372
373 54
                $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
374
            }
375
        }
376
377
        // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
378 68
        $discrColumn      = $this->class->discriminatorColumn;
379 68
        $discrTableAlias  = $this->getSQLTableAlias($discrColumn->getTableName());
380 68
        $discrColumnName  = $discrColumn->getColumnName();
381 68
        $discrColumnType  = $discrColumn->getType();
382 68
        $resultColumnName = $this->platform->getSQLResultCasing($discrColumnName);
383 68
        $quotedColumnName = $this->platform->quoteIdentifier($discrColumn->getColumnName());
384
385 68
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
386 68
        $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 68
        $columnList[] = $discrColumnType->convertToDatabaseValueSQL($discrTableAlias . '.' . $quotedColumnName, $this->platform);
389
390
        // sub tables
391 68
        foreach ($this->class->getSubClasses() as $subClassName) {
392 49
            $subClass = $this->em->getClassMetadata($subClassName);
393
394
            // Add columns
395 49
            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 49
                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 49
                    continue;
398
                }
399
400
                switch (true) {
401 45
                    case $property instanceof FieldMetadata:
402 45
                        $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
403 45
                        break;
404
405 31
                    case $property instanceof ToOneAssociationMetadata && $property->isOwningSide():
406 31
                        $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
407
408 31
                        foreach ($property->getJoinColumns() as $joinColumn) {
409
                            /** @var JoinColumnMetadata $joinColumn */
410 31
                            $referencedColumnName = $joinColumn->getReferencedColumnName();
411
412 31
                            if (! $joinColumn->getType()) {
413
                                $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
414
                            }
415
416 31
                            $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
417
                        }
418
419 31
                        break;
420
                }
421
            }
422
        }
423
424 68
        $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
425
426 68
        return $this->currentPersisterContext->selectColumnListSql;
427
    }
428
429
    /**
430
     * {@inheritdoc}
431
     */
432 295
    protected function getInsertColumnList()
433
    {
434
        // Identifier columns must always come first in the column list of subclasses.
435 295
        $columns       = [];
436 295
        $parentColumns = $this->class->isRootEntity()
437 295
            ? []
438 295
            : $this->class->getIdentifierColumns($this->em);
439
440 295
        foreach ($parentColumns as $columnName => $column) {
441 289
            $columns[] = $columnName;
442
443 289
            $this->columns[$columnName] = $column;
444
        }
445
446 295
        foreach ($this->class->getPropertiesIterator() as $name => $property) {
447 295
            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 295
                || ($property instanceof AssociationMetadata && $this->class->isInheritedProperty($name))
449
                /*|| isset($this->class->embeddedClasses[$name])*/) {
450 293
                continue;
451
            }
452
453 295
            if ($property instanceof AssociationMetadata) {
454 264
                if ($property->isOwningSide() && $property instanceof ToOneAssociationMetadata) {
455 263
                    $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
456
457 263
                    foreach ($property->getJoinColumns() as $joinColumn) {
458
                        /** @var JoinColumnMetadata $joinColumn */
459 263
                        $columnName           = $joinColumn->getColumnName();
460 263
                        $referencedColumnName = $joinColumn->getReferencedColumnName();
461
462 263
                        if (! $joinColumn->getType()) {
463 12
                            $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
464
                        }
465
466 263
                        $columns[] = $columnName;
467
468 263
                        $this->columns[$columnName] = $joinColumn;
469
                    }
470
                }
471
472 264
                continue;
473
            }
474
475 295
            if ($this->class->getClassName() !== $this->class->getRootClassName()
476 295
                || ! $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 291
                || $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 295
                || $this->class->identifier[0] !== $name
479
            ) {
480 233
                $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 233
                $columns[] = $columnName;
483
484 233
                $this->columns[$columnName] = $property;
485
            }
486
        }
487
488
        // Add discriminator column if it is the topmost class.
489 295
        if ($this->class->isRootEntity()) {
490 295
            $discrColumn     = $this->class->discriminatorColumn;
491 295
            $discrColumnName = $discrColumn->getColumnName();
492
493 295
            $columns[] = $discrColumnName;
494
495 295
            $this->columns[$discrColumnName] = $discrColumn;
496
        }
497
498 295
        return $columns;
499
    }
500
501
    /**
502
     * @param string $baseTableAlias
503
     *
504
     * @return string
505
     */
506 73
    private function getJoinSql($baseTableAlias)
507
    {
508 73
        $joinSql           = '';
509 73
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
510
511
        // INNER JOIN parent tables
512 73
        $parentClass = $this->class;
513
514 73
        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 73
        foreach ($this->class->getSubClasses() as $subClassName) {
533 51
            $conditions = [];
534 51
            $subClass   = $this->em->getClassMetadata($subClassName);
535 51
            $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 51
            $tableAlias = $this->getSQLTableAlias($subClass->getTableName());
537 51
            $joinSql   .= ' LEFT JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
538
539 51
            foreach ($identifierColumns as $idColumn) {
540 51
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
541
542 51
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
543
            }
544
545 51
            $joinSql .= implode(' AND ', $conditions);
546
        }
547
548 73
        return $joinSql;
549
    }
550
}
551