Failed Conditions
Pull Request — master (#7825)
by
unknown
65:47 queued 01:43
created

JoinedSubclassPersister::getInsertColumnList()   D

Complexity

Conditions 20
Paths 48

Size

Total Lines 68
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 20

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 20
eloc 35
nc 48
nop 0
dl 0
loc 68
ccs 32
cts 32
cp 1
crap 20
rs 4.1666
c 3
b 0
f 0

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->getPropertyTableClass($this->class->versionProperty->getName());
0 ignored issues
show
Bug introduced by
The method getName() 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
            $versionedClass = $this->class->getPropertyTableClass($this->class->versionProperty->/** @scrutinizer ignore-call */ getName());

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 = $this->class->getPropertyTableClass($fieldName);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
350
                $columnList[] = $this->getSelectColumnSQL($fieldName, $tableClass);
351 55
352
                continue;
353 55
            }
354
355 55
            if (! ($property instanceof ToOneAssociationMetadata) || ! $property->isOwningSide()) {
356
                continue;
357 55
            }
358
359
            $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
360
361 55
            foreach ($property->getJoinColumns() as $joinColumn) {
362
                /** @var JoinColumnMetadata $joinColumn */
363
                $referencedColumnName = $joinColumn->getReferencedColumnName();
364
365
                if (! $joinColumn->getType()) {
366 68
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
367 68
                }
368 68
369 68
                $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
370 68
            }
371 68
        }
372
373 68
        // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
374 68
        $discrColumn      = $this->class->discriminatorColumn;
375
        $discrTableAlias  = $this->getSQLTableAlias($discrColumn->getTableName());
376 68
        $discrColumnName  = $discrColumn->getColumnName();
377
        $discrColumnType  = $discrColumn->getType();
378
        $resultColumnName = $this->platform->getSQLResultCasing($discrColumnName);
379 68
        $quotedColumnName = $this->platform->quoteIdentifier($discrColumn->getColumnName());
380 50
381
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
382
        $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

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

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

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

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

474
                || $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...
475
                || $this->class->identifier[0] !== $name
476
            ) {
477 295
                $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

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