Completed
Pull Request — master (#7825)
by
unknown
61:48
created

JoinedSubclassPersister::getSelectColumnsSQL()   D

Complexity

Conditions 19
Paths 65

Size

Total Lines 93
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 19.0296

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 44
cts 46
cp 0.9565
crap 19.0296
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
                $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 289
60 170
                if ($parentClass !== $rootClass) {
61
                    $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClass->getClassName());
62 170
63
                    $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL());
64
                }
65
            }
66
        }
67
68
        // Execute all inserts. For each entity:
69 295
        // 1) Insert on root table
70
        // 2) Insert on sub tables
71
        $insertData = $this->prepareInsertData($entity);
72 295
73
        // Execute insert on root table
74 295
        $paramIndex = 1;
75 295
76
        foreach ($insertData[$rootTableName] as $columnName => $value) {
77 295
            $type = $this->columns[$columnName]->getType();
78
79
            $rootTableStmt->bindValue($paramIndex++, $value, $type);
80 295
        }
81
82 295
        $rootTableStmt->execute();
83 291
84 291
        if ($generationPlan->containsDeferred()) {
85
            $generationPlan->executeDeferred($this->em, $entity);
86 4
            $id = $this->getIdentifier($entity);
87
        } else {
88
            $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
89 295
        }
90 9
91
        if ($this->class->isVersioned()) {
92
            $this->assignDefaultVersionValue($entity, $id);
93
        }
94
95 295
        // Execute inserts on subtables.
96
        // The order doesn't matter because all child tables link to the root table via FK.
97 289
        foreach ($subTableStmts as $tableName => $stmt) {
98 289
            /** @var Statement $stmt */
99
            $paramIndex = 1;
100 289
            $data       = $insertData[$tableName] ?? [];
101 289
102
            foreach ((array) $id as $idName => $idVal) {
103 289
                $type = Type::getType('string');
104 289
105
                if (isset($this->columns[$idName])) {
106
                    $type = $this->columns[$idName]->getType();
107 289
                }
108
109
                $stmt->bindValue($paramIndex++, $idVal, $type);
110 289
            }
111 224
112 224
            foreach ($data as $columnName => $value) {
113
                if (! is_array($id) || ! isset($id[$columnName])) {
114 224
                    $type = $this->columns[$columnName]->getType();
115
116
                    $stmt->bindValue($paramIndex++, $value, $type);
117
                }
118 289
            }
119
120
            $stmt->execute();
121 295
        }
122
123 295
        $rootTableStmt->closeCursor();
124 289
125
        foreach ($subTableStmts as $stmt) {
126 295
            $stmt->closeCursor();
127
        }
128
    }
129
130
    /**
131 30
     * {@inheritdoc}
132
     */
133 30
    public function update($entity)
134
    {
135 30
        $updateData = $this->prepareUpdateData($entity);
136
137
        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 30
        }
140
141 30
        $isVersioned = $this->class->isVersioned();
142 30
143
        foreach ($updateData as $tableName => $data) {
144 30
            $versioned = $isVersioned && $this->class->versionProperty->getTableName() === $tableName;
145
146
            $this->updateTable($entity, $this->platform->quoteIdentifier($tableName), $data, $versioned);
147
        }
148
149 29
        // Make sure the table with the version column is updated even if no columns on that
150 5
        // table were affected.
151 5
        if ($isVersioned) {
152
            $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 2
155
            if (! isset($updateData[$versionedTable])) {
156 2
                $tableName = $versionedClass->table->getQuotedQualifiedName($this->platform);
157
158
                $this->updateTable($entity, $tableName, [], true);
159 4
            }
160
161 4
            $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
162
163 28
            $this->assignDefaultVersionValue($entity, $identifiers);
164
        }
165
    }
166
167
    /**
168 4
     * {@inheritdoc}
169
     */
170 4
    public function delete($entity)
171 4
    {
172
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
173 4
        $id         = array_combine(array_keys($this->class->getIdentifierColumns($this->em)), $identifier);
174
175
        $this->deleteJoinTableRecords($identifier);
176
177 4
        // If the database platform supports FKs, just
178
        // delete the row from the root table. Cascades do the rest.
179
        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 4
186 4
        // Delete from all tables individually, starting from this class' table up to the root table.
187 4
        $rootTable    = $this->class->table->getQuotedQualifiedName($this->platform);
188
        $affectedRows = $this->conn->delete($rootTable, $id);
189 4
        $parentClass  = $this->class;
190 3
191
        while (($parentClass = $parentClass->getParent()) !== null) {
192 3
            if (! $parentClass->isMappedSuperclass) {
193
                $parentTable = $parentClass->table->getQuotedQualifiedName($this->platform);
194
195 4
                $this->conn->delete($parentTable, $id);
196
            }
197
        }
198
199
        return (bool) $affectedRows;
200
    }
201 68
202
    /**
203
     * {@inheritdoc}
204
     */
205
    public function getSelectSQL(
206
        $criteria,
207
        ?AssociationMetadata $association = null,
208
        $lockMode = null,
209 68
        $limit = null,
210
        $offset = null,
211 68
        array $orderBy = []
212 68
    ) {
213
        $this->switchPersisterContext($offset, $limit);
214 68
215 2
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
216
        $joinSql        = $this->getJoinSql($baseTableAlias);
217
218 68
        if ($association instanceof ManyToManyAssociationMetadata) {
219 1
            $joinSql .= $this->getSelectManyToManyJoinSQL($association);
220
        }
221
222 68
        if ($association instanceof ToManyAssociationMetadata && $association->getOrderBy()) {
223 68
            $orderBy = $association->getOrderBy();
224
        }
225 68
226
        $orderBySql   = $this->getOrderBySQL($orderBy, $baseTableAlias);
227
        $conditionSql = $criteria instanceof Criteria
228 68
            ? $this->getSelectConditionCriteriaSQL($criteria)
229 68
            : $this->getSelectConditionSQL($criteria, $association);
230 68
231
        // If the current class in the root entity, add the filters
232 68
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
233 4
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
234 2
        $filterSql  = $this->generateFilterConditionSQL($rootClass, $tableAlias);
235 4
236
        if ($filterSql) {
237
            $conditionSql .= $conditionSql
238 68
                ? ' AND ' . $filterSql
239
                : $filterSql;
240
        }
241 68
242
        $lockSql = '';
243
244
        switch ($lockMode) {
245 68
            case LockMode::PESSIMISTIC_READ:
246
                $lockSql = ' ' . $this->platform->getReadLockSQL();
247
                break;
248
249
            case LockMode::PESSIMISTIC_WRITE:
250 68
                $lockSql = ' ' . $this->platform->getWriteLockSQL();
251 68
                break;
252 68
        }
253 68
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
                    . $lock
261 68
                    . $joinSql
262
                    . $where
263
                    . $orderBySql;
264
265
        return $this->platform->modifyLimitQuery($query, $limit, $offset ?? 0) . $lockSql;
266
    }
267 6
268
    /**
269 6
     * {@inheritDoc}
270 6
     */
271 6
    public function getCountSQL($criteria = [])
272
    {
273 6
        $tableName      = $this->class->table->getQuotedQualifiedName($this->platform);
274 1
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
275 6
        $joinSql        = $this->getJoinSql($baseTableAlias);
276
277 6
        $conditionSql = $criteria instanceof Criteria
278 6
            ? $this->getSelectConditionCriteriaSQL($criteria)
279 6
            : $this->getSelectConditionSQL($criteria);
280
281 6
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
282 1
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
283 1
        $filterSql  = $this->generateFilterConditionSQL($rootClass, $tableAlias);
284 1
285
        if ($filterSql !== '') {
286
            $conditionSql = $conditionSql
287
                ? $conditionSql . ' AND ' . $filterSql
288 6
                : $filterSql;
289 6
        }
290 6
291
        return 'SELECT COUNT(*) '
292
            . 'FROM ' . $tableName . ' ' . $baseTableAlias
293
            . $joinSql
294
            . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
295
    }
296 6
297
    /**
298 6
     * {@inheritdoc}
299 6
     */
300 6
    protected function getLockTablesSql($lockMode)
301
    {
302
        $joinSql           = '';
303 6
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
304
        $baseTableAlias    = $this->getSQLTableAlias($this->class->getTableName());
305 6
306 5
        // INNER JOIN parent tables
307 5
        $parentClass = $this->class;
308 5
309 5
        while (($parentClass = $parentClass->getParent()) !== null) {
310
            if (! $parentClass->isMappedSuperclass) {
311 5
                $conditions = [];
312 5
                $tableName  = $parentClass->table->getQuotedQualifiedName($this->platform);
313
                $tableAlias = $this->getSQLTableAlias($parentClass->getTableName());
314 5
                $joinSql   .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
315
316
                foreach ($identifierColumns as $idColumn) {
317 5
                    $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
318
319
                    $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
320 6
                }
321
322
                $joinSql .= implode(' AND ', $conditions);
323
            }
324
        }
325
326
        return parent::getLockTablesSql($lockMode) . $joinSql;
327
    }
328 68
329
    /**
330
     * Ensure this method is never called. This persister overrides getSelectEntitiesSQL directly.
331 68
     *
332 12
     * @return string
333
     */
334
    protected function getSelectColumnsSQL()
335 68
    {
336
        // Create the column list fragment only once
337 68
        if ($this->currentPersisterContext->selectColumnListSql !== null) {
338
            return $this->currentPersisterContext->selectColumnListSql;
339
        }
340 68
341 68
        $this->currentPersisterContext->rsm->addEntityResult($this->class->getClassName(), 'r');
342 68
343
        $columnList = [];
344 68
345
        // Add columns
346
        foreach ($this->class->getPropertiesIterator() as $fieldName => $property) {
347 56
            if ($property instanceof FieldMetadata) {
348 44
                $tableClass = $parentClass = $this->class;
349
                while ($parentClass !== $property->getDeclaringClass() && ($parentClass = $parentClass->getParent()) !== null) {
350
                    if (! $parentClass->isMappedSuperclass) {
351 55
                        $tableClass = $parentClass;
352
                    }
353 55
                }
354
                $columnList[] = $this->getSelectColumnSQL($fieldName, $tableClass);
355 55
356
                continue;
357 55
            }
358
359
            if (! ($property instanceof ToOneAssociationMetadata) || ! $property->isOwningSide()) {
360
                continue;
361 55
            }
362
363
            $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
364
365
            foreach ($property->getJoinColumns() as $joinColumn) {
366 68
                /** @var JoinColumnMetadata $joinColumn */
367 68
                $referencedColumnName = $joinColumn->getReferencedColumnName();
368 68
369 68
                if (! $joinColumn->getType()) {
370 68
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
371 68
                }
372
373 68
                $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
374 68
            }
375
        }
376 68
377
        // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
378
        $discrColumn      = $this->class->discriminatorColumn;
379 68
        $discrTableAlias  = $this->getSQLTableAlias($discrColumn->getTableName());
380 50
        $discrColumnName  = $discrColumn->getColumnName();
381
        $discrColumnType  = $discrColumn->getType();
382
        $resultColumnName = $this->platform->getSQLResultCasing($discrColumnName);
383 50
        $quotedColumnName = $this->platform->quoteIdentifier($discrColumn->getColumnName());
384 50
385 50
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
386
        $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
        $columnList[] = $discrColumnType->convertToDatabaseValueSQL($discrTableAlias . '.' . $quotedColumnName, $this->platform);
389 46
390 46
        // sub tables
391 46
        foreach ($this->class->getSubClasses() as $subClassName) {
392
            $subClass = $this->em->getClassMetadata($subClassName);
393 32
394 32
            // Add columns
395
            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 32
                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
                    continue;
398 32
                }
399
400 32
                switch (true) {
401
                    case $property instanceof FieldMetadata:
402
                        $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
403
                        break;
404 32
405
                    case $property instanceof ToOneAssociationMetadata && $property->isOwningSide():
406
                        $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
407 32
408
                        foreach ($property->getJoinColumns() as $joinColumn) {
409
                            /** @var JoinColumnMetadata $joinColumn */
410
                            $referencedColumnName = $joinColumn->getReferencedColumnName();
411
412 68
                            if (! $joinColumn->getType()) {
413
                                $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
414 68
                            }
415
416
                            $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
417
                        }
418
419
                        break;
420 295
                }
421
            }
422
        }
423 295
424 295
        $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
425 289
426 295
        return $this->currentPersisterContext->selectColumnListSql;
427
    }
428 295
429 289
    /**
430
     * {@inheritdoc}
431 289
     */
432
    protected function getInsertColumnList()
433
    {
434 295
        // Identifier columns must always come first in the column list of subclasses.
435 295
        $columns       = [];
436 295
        $parentColumns = $this->class->isRootEntity()
437
            ? []
438 293
            : $this->class->getIdentifierColumns($this->em);
439
440
        foreach ($parentColumns as $columnName => $column) {
441 295
            $columns[] = $columnName;
442 265
443 264
            $this->columns[$columnName] = $column;
444
        }
445 264
446
        foreach ($this->class->getPropertiesIterator() as $name => $property) {
447 264
            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 264
                || ($property instanceof AssociationMetadata && $this->class->isInheritedProperty($name))
449
                /*|| isset($this->class->embeddedClasses[$name])*/) {
450 264
                continue;
451 12
            }
452
453
            if ($property instanceof AssociationMetadata) {
454 264
                if ($property->isOwningSide() && $property instanceof ToOneAssociationMetadata) {
455
                    $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
456 264
457
                    foreach ($property->getJoinColumns() as $joinColumn) {
458
                        /** @var JoinColumnMetadata $joinColumn */
459
                        $columnName           = $joinColumn->getColumnName();
460 265
                        $referencedColumnName = $joinColumn->getReferencedColumnName();
461
462
                        if (! $joinColumn->getType()) {
463 295
                            $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
464 295
                        }
465 291
466 295
                        $columns[] = $columnName;
467
468 233
                        $this->columns[$columnName] = $joinColumn;
469
                    }
470 233
                }
471
472 233
                continue;
473
            }
474
475
            if ($this->class->getClassName() !== $this->class->getRootClassName()
476
                || ! $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 295
                || $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 295
            ) {
480
                $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 295
482
                $columns[] = $columnName;
483 295
484
                $this->columns[$columnName] = $property;
485
            }
486 295
        }
487
488
        // Add discriminator column if it is the topmost class.
489
        if ($this->class->isRootEntity()) {
490
            $discrColumn     = $this->class->discriminatorColumn;
491
            $discrColumnName = $discrColumn->getColumnName();
492
493
            $columns[] = $discrColumnName;
494 73
495
            $this->columns[$discrColumnName] = $discrColumn;
496 73
        }
497 73
498
        return $columns;
499
    }
500 73
501
    /**
502 73
     * @param string $baseTableAlias
503 49
     *
504 49
     * @return string
505 49
     */
506 49
    private function getJoinSql($baseTableAlias)
507
    {
508 49
        $joinSql           = '';
509 49
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
510
511 49
        // INNER JOIN parent tables
512
        $parentClass = $this->class;
513
514 49
        while (($parentClass = $parentClass->getParent()) !== null) {
515
            if (! $parentClass->isMappedSuperclass) {
516
                $conditions = [];
517
                $tableName  = $parentClass->table->getQuotedQualifiedName($this->platform);
518 73
                $tableAlias = $this->getSQLTableAlias($parentClass->getTableName());
519 52
                $joinSql   .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
520 52
521 52
                foreach ($identifierColumns as $idColumn) {
522 52
                    $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
523 52
524
                    $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
525 52
                }
526 52
527
                $joinSql .= implode(' AND ', $conditions);
528 52
            }
529
        }
530
531 52
        // OUTER JOIN sub tables
532
        foreach ($this->class->getSubClasses() as $subClassName) {
533
            $conditions = [];
534 73
            $subClass   = $this->em->getClassMetadata($subClassName);
535
            $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
            $tableAlias = $this->getSQLTableAlias($subClass->getTableName());
537
            $joinSql   .= ' LEFT JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
538
539
            foreach ($identifierColumns as $idColumn) {
540
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
541
542
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
543
            }
544
545
            $joinSql .= implode(' AND ', $conditions);
546
        }
547
548
        return $joinSql;
549
    }
550
}
551