Completed
Pull Request — master (#7825)
by
unknown
61:51
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\Mapping\TransientMetadata;
19
use Doctrine\ORM\Utility\PersisterHelper;
20
use function array_combine;
21
use function array_keys;
22
use function implode;
23
use function is_array;
24
25
/**
26
 * The joined subclass persister maps a single entity instance to several tables in the
27
 * database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
28
 *
29
 * @see https://martinfowler.com/eaaCatalog/classTableInheritance.html
30
 */
31
class JoinedSubclassPersister extends AbstractEntityInheritancePersister
32
{
33
    /**
34
     * {@inheritdoc}
35 295
     */
36
    public function insert($entity)
37 295
    {
38 289
        $rootClass      = ! $this->class->isRootEntity()
39 295
            ? $this->em->getClassMetadata($this->class->getRootClassName())
40 295
            : $this->class;
41
        $generationPlan = $this->class->getValueGenerationPlan();
42
43 295
        // Prepare statement for the root table
44 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

44
        $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...
45 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

45
        /** @scrutinizer ignore-call */ 
46
        $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...
46
        $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

46
        $rootTableStmt = $this->conn->prepare($rootPersister->/** @scrutinizer ignore-call */ getInsertSQL());
Loading history...
47
48 295
        // Prepare statements for sub tables.
49
        $subTableStmts = [];
50 295
51 289
        if ($rootClass !== $this->class) {
52
            $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
53
        }
54 295
55
        $parentClass = $this->class;
56 295
57 289
        while (($parentClass = $parentClass->getParent()) !== null) {
58
            if (! $parentClass->isMappedSuperclass) {
59 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

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

153
            /** @scrutinizer ignore-call */ 
154
            $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...
154 2
            $versionedTable = $versionedClass->getTableName();
155
156 2
            if (! isset($updateData[$versionedTable])) {
157
                $tableName = $versionedClass->table->getQuotedQualifiedName($this->platform);
158
159 4
                $this->updateTable($entity, $tableName, [], true);
160
            }
161 4
162
            $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
163 28
164
            $this->assignDefaultVersionValue($entity, $identifiers);
165
        }
166
    }
167
168 4
    /**
169
     * {@inheritdoc}
170 4
     */
171 4
    public function delete($entity)
172
    {
173 4
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
174
        $id         = array_combine(array_keys($this->class->getIdentifierColumns($this->em)), $identifier);
175
176
        $this->deleteJoinTableRecords($identifier);
177 4
178
        // If the database platform supports FKs, just
179
        // delete the row from the root table. Cascades do the rest.
180
        if ($this->platform->supportsForeignKeyConstraints()) {
181
            $rootClass = $this->em->getClassMetadata($this->class->getRootClassName());
182
            $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...
183
184
            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

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

387
        $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, /** @scrutinizer ignore-type */ $discrColumnType);
Loading history...
388
389 46
        $columnList[] = $discrColumnType->convertToDatabaseValueSQL($discrTableAlias . '.' . $quotedColumnName, $this->platform);
390 46
391 46
        // sub tables
392
        foreach ($this->class->getSubClasses() as $subClassName) {
393 32
            $subClass = $this->em->getClassMetadata($subClassName);
394 32
395
            // Add columns
396 32
            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

396
            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...
397
                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

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

478
                || ! $this->class->getProperty($name)->/** @scrutinizer ignore-call */ hasValueGenerator()
Loading history...
479 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

479
                || $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...
480
                || $this->class->identifier[0] !== $name
481 295
            ) {
482
                $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

482
                /** @scrutinizer ignore-call */ 
483
                $columnName = $property->getColumnName();
Loading history...
483 295
484
                $columns[] = $columnName;
485
486 295
                $this->columns[$columnName] = $property;
487
            }
488
        }
489
490
        // Add discriminator column if it is the topmost class.
491
        if ($this->class->isRootEntity()) {
492
            $discrColumn     = $this->class->discriminatorColumn;
493
            $discrColumnName = $discrColumn->getColumnName();
494 73
495
            $columns[] = $discrColumnName;
496 73
497 73
            $this->columns[$discrColumnName] = $discrColumn;
498
        }
499
500 73
        return $columns;
501
    }
502 73
503 49
    /**
504 49
     * @param string $baseTableAlias
505 49
     *
506 49
     * @return string
507
     */
508 49
    private function getJoinSql($baseTableAlias)
509 49
    {
510
        $joinSql           = '';
511 49
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
512
513
        // INNER JOIN parent tables
514 49
        $parentClass = $this->class;
515
516
        while (($parentClass = $parentClass->getParent()) !== null) {
517
            if (! $parentClass->isMappedSuperclass) {
518 73
                $conditions = [];
519 52
                $tableName  = $parentClass->table->getQuotedQualifiedName($this->platform);
520 52
                $tableAlias = $this->getSQLTableAlias($parentClass->getTableName());
521 52
                $joinSql   .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
522 52
523 52
                foreach ($identifierColumns as $idColumn) {
524
                    $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
525 52
526 52
                    $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
527
                }
528 52
529
                $joinSql .= implode(' AND ', $conditions);
530
            }
531 52
        }
532
533
        // OUTER JOIN sub tables
534 73
        foreach ($this->class->getSubClasses() as $subClassName) {
535
            $conditions = [];
536
            $subClass   = $this->em->getClassMetadata($subClassName);
537
            $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...
538
            $tableAlias = $this->getSQLTableAlias($subClass->getTableName());
539
            $joinSql   .= ' LEFT JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
540
541
            foreach ($identifierColumns as $idColumn) {
542
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
543
544
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
545
            }
546
547
            $joinSql .= implode(' AND ', $conditions);
548
        }
549
550
        return $joinSql;
551
    }
552
}
553