Failed Conditions
Pull Request — develop (#6873)
by
unknown
112:44 queued 47:41
created

JoinedSubclassPersister::insert()   F

Complexity

Conditions 15
Paths 1920

Size

Total Lines 93
Code Lines 46

Duplication

Lines 5
Ratio 5.38 %

Code Coverage

Tests 38
CRAP Score 15

Importance

Changes 0
Metric Value
dl 5
loc 93
ccs 38
cts 38
cp 1
rs 2
c 0
b 0
f 0
cc 15
eloc 46
nc 1920
nop 1
crap 15

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
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 37 and the first side effect is on line 32.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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\Types\Type;
10
use Doctrine\ORM\Mapping\AssociationMetadata;
11
use Doctrine\ORM\Mapping\ClassMetadata;
12
use Doctrine\ORM\Mapping\ColumnMetadata;
13
use Doctrine\ORM\Mapping\FieldMetadata;
14
use Doctrine\ORM\Mapping\GeneratorType;
15
use Doctrine\ORM\Mapping\JoinColumnMetadata;
16
use Doctrine\ORM\Mapping\ManyToManyAssociationMetadata;
17
use Doctrine\ORM\Mapping\ToManyAssociationMetadata;
18
use Doctrine\ORM\Mapping\ToOneAssociationMetadata;
19
use Doctrine\ORM\Mapping\VersionFieldMetadata;
20
use Doctrine\ORM\Utility\PersisterHelper;
21
22
/**
23
 * The joined subclass persister maps a single entity instance to several tables in the
24
 * database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
25
 *
26
 * @author Roman Borschel <[email protected]>
27
 * @author Benjamin Eberlei <[email protected]>
28
 * @author Alexander <[email protected]>
29
 * @since 2.0
30
 * @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
31
 */
32
class JoinedSubclassPersister extends AbstractEntityInheritancePersister
0 ignored issues
show
Bug introduced by
Possible parse error: class missing opening or closing brace
Loading history...
33
{
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function insert($entity)
38
    {
39
        $rootClass      = ! $this->class->isRootEntity()
40
            ? $this->em->getClassMetadata($this->class->getRootClassName())
41
            : $this->class;
42
        $generationPlan = $this->class->getValueGenerationPlan();
43
44
        // Prepare statement for the root table
45
        $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->getClassName());
46
        $rootTableName = $rootClass->getTableName();
47
        $rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL());
48
49
        // Prepare statements for sub tables.
50
        $subTableStmts = [];
51
52
        if ($rootClass !== $this->class) {
53
            $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
54
        }
55
56
        $parentClass = $this->class;
57 272
58
        while (($parentClass = $parentClass->getParent()) !== null) {
59 272
            $parentTableName = $parentClass->getTableName();
60
61
            if ($parentClass !== $rootClass) {
62 272
                $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClass->getClassName());
63 249
64 249
                $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL());
65
            }
66 221
        }
67 196
68 196
        // Execute all inserts. For each entity:
69
        // 1) Insert on root table
70
        // 2) Insert on sub tables
71 218
        $insertData = $this->prepareInsertData($entity);
72 218
73
        // Execute insert on root table
74
        $paramIndex = 1;
75 272
76 272
        foreach ($insertData[$rootTableName] as $columnName => $value) {
77
            $type = $this->columns[$columnName]->getType();
78 272
79
            $rootTableStmt->bindValue($paramIndex++, $value, $type);
80 272
        }
81
82
        $rootTableStmt->execute();
83
84
        if ($generationPlan->containsDeferred()) {
85
            $generationPlan->executeDeferred($this->em, $entity);
86 285
            $id = $this->getIdentifier($entity);
87
        } else {
88 285
            $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
89 208
        }
90
91
                foreach ((array) $id as $idName => $idVal) {
92 275
                    $type = $this->columnTypes[$idName] ?? Type::STRING;
93 275
94 275
        if ($this->class->isVersioned()) {
95 275
            $this->assignDefaultVersionValue($entity, $id);
96 269
        }
97 275
98
        // Execute inserts on subtables.
99
        // The order doesn't matter because all child tables link to the root table via FK.
100 275
        foreach ($subTableStmts as $tableName => $stmt) {
101 275
            /** @var \Doctrine\DBAL\Statement $stmt */
102 275
            $paramIndex = 1;
103
            $data       = $insertData[$tableName] ?? [];
104
105 275
            foreach ((array) $id as $idName => $idVal) {
106
                $type = Type::getType('string');
107 275
108 269
                if (isset($this->columns[$idName])) {
109
                    $type = $this->columns[$idName]->getType();
110
                }
111 275
112 269
                $stmt->bindValue($paramIndex++, $idVal, $type);
113 269
            }
114
115 269
            foreach ($data as $columnName => $value) {
116 157
                if (!is_array($id) || !isset($id[$columnName])) {
117
                    $type = $this->columns[$columnName]->getType();
118 269
119
                    $stmt->bindValue($paramIndex++, $value, $type);
120
                }
121
            }
122
123
            $stmt->execute();
124
        }
125 275
126 275
        $rootTableStmt->closeCursor();
127
128
        foreach ($subTableStmts as $stmt) {
129 275
            $stmt->closeCursor();
130
        }
131 275
    }
132 275
133 275
    /**
134 275
     * {@inheritdoc}
135
     */
136
    public function update($entity)
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_PUBLIC on line 136 at column 4
Loading history...
137 275
    {
138
        $updateData = $this->prepareUpdateData($entity);
139
140 275
        if ( ! $updateData) {
141
            return;
142 275
        }
143 273
144 273
        $isVersioned = $this->class->isVersioned();
145
146 273
        foreach ($updateData as $tableName => $data) {
147 273
            $versioned = $isVersioned && $this->class->versionProperty->getTableName() === $tableName;
148 273
149
            $this->updateTable($entity, $this->platform->quoteIdentifier($tableName), $data, $versioned);
150
        }
151 2
152
        // Make sure the table with the version column is updated even if no columns on that
153
        // table were affected.
154 275
        if ($isVersioned) {
155 9
            $versionedClass = $this->class->versionProperty->getDeclaringClass();
156
            $versionedTable = $versionedClass->getTableName();
157
158
            if ( ! isset($updateData[$versionedTable])) {
159
                $tableName = $versionedClass->table->getQuotedQualifiedName($this->platform);
160 275
161
                $this->updateTable($entity, $tableName, [], true);
162 269
            }
163 269
164 210
            $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
165 269
166
            $this->assignDefaultVersionValue($entity, $identifiers);
167 269
        }
168 269
    }
169
170 269
    /**
171 269
     * {@inheritdoc}
172 269
     */
173 269
    public function delete($entity)
174
    {
175
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
176
        $id         = array_combine(array_keys($this->class->getIdentifierColumns($this->em)), $identifier);
177 269
178
        $this->deleteJoinTableRecords($identifier);
179
180 269
        // If the database platform supports FKs, just
181 210
        // delete the row from the root table. Cascades do the rest.
182 210
        if ($this->platform->supportsForeignKeyConstraints()) {
183 207
            $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
184 210
            $rootTable  = $rootClass->table->getQuotedQualifiedName($this->platform);
185
186
            return (bool) $this->conn->delete($rootTable, $id);
187 210
        }
188
189
        // Delete from all tables individually, starting from this class' table up to the root table.
190
        $rootTable    = $this->class->table->getQuotedQualifiedName($this->platform);
191 275
        $affectedRows = $this->conn->delete($rootTable, $id);
192
        $parentClass  = $this->class;
193
194
        while (($parentClass = $parentClass->getParent()) !== null) {
195 275
            $parentTable = $parentClass->table->getQuotedQualifiedName($this->platform);
196
197 275
            $this->conn->delete($parentTable, $id);
198 269
        }
199
200
        return (bool) $affectedRows;
201 275
    }
202
203 275
    /**
204
     * {@inheritdoc}
205
     */
206
    public function getSelectSQL(
207
        $criteria,
208
        AssociationMetadata $association = null,
209 31
        $lockMode = null,
210
        $limit = null,
211 31
        $offset = null,
212
        array $orderBy = []
213 31
    )
214
    {
215
        $this->switchPersisterContext($offset, $limit);
216
217 31
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
218
        $joinSql        = $this->getJoinSql($baseTableAlias);
219 31
220 31
        if ($association instanceof ManyToManyAssociationMetadata) {
221 31
            $joinSql .= $this->getSelectManyToManyJoinSQL($association);
222
        }
223 31
224
        if ($association instanceof ToManyAssociationMetadata && $association->getOrderBy()) {
225
            $orderBy = $association->getOrderBy();
226
        }
227
228 30
        $orderBySql   = $this->getOrderBySQL($orderBy, $baseTableAlias);
229 5
        $conditionSql = ($criteria instanceof Criteria)
230 5
            ? $this->getSelectConditionCriteriaSQL($criteria)
231
            : $this->getSelectConditionSQL($criteria, $association);
232 5
233 2
        // If the current class in the root entity, add the filters
234
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
235 2
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
236
237
        if ($filterSql = $this->generateFilterConditionSQL($rootClass, $tableAlias)) {
238 4
            $conditionSql .= $conditionSql
239
                ? ' AND ' . $filterSql
240 4
                : $filterSql;
241
        }
242 29
243
        $lockSql = '';
244
245
        switch ($lockMode) {
246
            case LockMode::PESSIMISTIC_READ:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
247 5
                $lockSql = ' ' . $this->platform->getReadLockSQL();
248
                break;
249 5
250 5
            case LockMode::PESSIMISTIC_WRITE:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
251
                $lockSql = ' ' . $this->platform->getWriteLockSQL();
252 5
                break;
253
        }
254
255
        $tableName  = $this->class->table->getQuotedQualifiedName($this->platform);
256 5
        $from       = ' FROM ' . $tableName . ' ' . $baseTableAlias;
257
        $where      = $conditionSql !== '' ? ' WHERE ' . $conditionSql : '';
258
        $lock       = $this->platform->appendLockHint($from, $lockMode);
259
        $columnList = $this->getSelectColumnsSQL();
260
        $query      = 'SELECT '  . $columnList
261
                    . $lock
262
                    . $joinSql
263
                    . $where
264 5
                    . $orderBySql;
265
266 5
        return $this->platform->modifyLimitQuery($query, $limit, $offset) . $lockSql;
267
    }
268 5
269 4
    /**
270 4
     * {@inheritDoc}
271
     */
272 4
    public function getCountSQL($criteria = [])
273
    {
274
        $tableName      = $this->class->table->getQuotedQualifiedName($this->platform);
275 5
        $baseTableAlias = $this->getSQLTableAlias($this->class->getTableName());
276
        $joinSql        = $this->getJoinSql($baseTableAlias);
277
278
        $conditionSql = ($criteria instanceof Criteria)
279
            ? $this->getSelectConditionCriteriaSQL($criteria)
280
            : $this->getSelectConditionSQL($criteria);
281 63
282
        $rootClass  = $this->em->getClassMetadata($this->class->getRootClassName());
283 63
        $tableAlias = $this->getSQLTableAlias($rootClass->getTableName());
284
        $filterSql  = $this->generateFilterConditionSQL($rootClass, $tableAlias);
285 63
286 63
        if ('' !== $filterSql) {
287
            $conditionSql = $conditionSql
288 63
                ? $conditionSql . ' AND ' . $filterSql
289 2
                : $filterSql;
290
        }
291
292 63
        $sql = 'SELECT COUNT(*) '
293
            . 'FROM ' . $tableName . ' ' . $baseTableAlias
294 63
            . $joinSql
295
            . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
296
297 63
        return $sql;
298 63
    }
299
300 63
    /**
301 4
     * {@inheritdoc}
302 2
     */
303 4
    protected function getLockTablesSql($lockMode)
304
    {
305
        $joinSql            = '';
306 63
        $identifierColumns  = $this->class->getIdentifierColumns($this->em);
307
        $baseTableAlias     = $this->getSQLTableAlias($this->class->getTableName());
308 63
309 1
        // INNER JOIN parent tables
310
        $parentClass = $this->class;
311
312 63
        while (($parentClass = $parentClass->getParent()) !== null) {
313 1
            $conditions   = [];
314
            $tableName    = $parentClass->table->getQuotedQualifiedName($this->platform);
315
            $tableAlias   = $this->getSQLTableAlias($parentClass->getTableName());
316 63
            $joinSql     .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
317
318
            foreach ($identifierColumns as $idColumn) {
319 63
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
320
321
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
322
            }
323
324
            $joinSql .= implode(' AND ', $conditions);
325 63
        }
326
327
        return parent::getLockTablesSql($lockMode) . $joinSql;
328
    }
329
330
    /**
331
     * Ensure this method is never called. This persister overrides getSelectEntitiesSQL directly.
332 63
     *
333 63
     * @return string
334 63
     */
335 63
    protected function getSelectColumnsSQL()
336 63
    {
337 63
        // Create the column list fragment only once
338 63
        if ($this->currentPersisterContext->selectColumnListSql !== null) {
339 63
            return $this->currentPersisterContext->selectColumnListSql;
340 63
        }
341 63
342
        $this->currentPersisterContext->rsm->addEntityResult($this->class->getClassName(), 'r');
343 63
344
        $columnList = [];
345
346
        // Add columns
347
        foreach ($this->class->getDeclaredPropertiesIterator() as $fieldName => $property) {
348
            if ($property instanceof FieldMetadata) {
349 6
                $columnList[] = $this->getSelectColumnSQL($fieldName, $property->getDeclaringClass());
350
351 6
                continue;
352 6
            }
353 6
354
            if (! ($property instanceof ToOneAssociationMetadata) || ! $property->isOwningSide()) {
355 6
                continue;
356 6
            }
357 6
358
            $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
359 6
360 6
            foreach ($property->getJoinColumns() as $joinColumn) {
361 6
                /** @var JoinColumnMetadata $joinColumn */
362
                $referencedColumnName = $joinColumn->getReferencedColumnName();
363 6
364 1
                if (! $joinColumn->getType()) {
365 1
                    $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
366 1
                }
367
368
                $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
369
            }
370 6
        }
371 6
372 6
        // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
373
        $discrColumn      = $this->class->discriminatorColumn;
374 6
        $discrTableAlias  = $this->getSQLTableAlias($discrColumn->getTableName());
375
        $discrColumnName  = $discrColumn->getColumnName();
376
        $discrColumnType  = $discrColumn->getType();
377
        $resultColumnName = $this->platform->getSQLResultCasing($discrColumnName);
378
        $quotedColumnName = $this->platform->quoteIdentifier($discrColumn->getColumnName());
379
380 7
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
381
        $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType);
382 7
383 7
        $columnList[] = $discrColumnType->convertToDatabaseValueSQL($discrTableAlias . '.' . $quotedColumnName, $this->platform);
384 7
385
        // sub tables
386
        foreach ($this->class->getSubClasses() as $subClassName) {
387 7
            $subClass = $this->em->getClassMetadata($subClassName);
388 6
389 6
            // Add columns
390 6
            foreach ($subClass->getDeclaredPropertiesIterator() as $fieldName => $property) {
391 6
                if ($subClass->isInheritedProperty($fieldName)) {
392
                    continue;
393 6
                }
394 6
395 6
                switch (true) {
396 6
                    case ($property instanceof FieldMetadata):
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
397
                        $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
398
                        break;
399 6
400
                    case ($property instanceof ToOneAssociationMetadata && $property->isOwningSide()):
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
401
                        $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
402 6
403
                        foreach ($property->getJoinColumns() as $joinColumn) {
404
                            /** @var JoinColumnMetadata $joinColumn */
405 7
                            $referencedColumnName = $joinColumn->getReferencedColumnName();
406
407
                            if (! $joinColumn->getType()) {
408
                                $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
409
                            }
410
411
                            $columnList[] = $this->getSelectJoinColumnSQL($joinColumn);
412
                        }
413 63
414
                        break;
415
                }
416 63
            }
417 15
        }
418
419
        $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
420 63
421
        return $this->currentPersisterContext->selectColumnListSql;
422 63
    }
423
424
    /**
425 63
     * {@inheritdoc}
426 63
     */
427
    protected function getInsertColumnList()
428
    {
429
        // Identifier columns must always come first in the column list of subclasses.
430 63
        $columns = [];
431 56
        $parentColumns = $this->class->getParent()
432 44
            ? $this->class->getIdentifierColumns($this->em)
433
            : [];
434
435 55
        foreach ($parentColumns as $columnName => $column) {
436
            $columns[] = $columnName;
437 55
438 55
            $this->columns[$columnName] = $column;
439
        }
440 55
441
        foreach ($this->class->getDeclaredPropertiesIterator() as $name => $property) {
442
            if (($property instanceof FieldMetadata && ($property instanceof VersionFieldMetadata || $this->class->isInheritedProperty($name)))
443
                || ($property instanceof AssociationMetadata && $this->class->isInheritedProperty($name))
444
                /*|| isset($this->class->embeddedClasses[$name])*/) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
77% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
445 63
                continue;
446 63
            }
447 63
448 63
            if ($property instanceof AssociationMetadata) {
449
                if ($property->isOwningSide() && $property instanceof ToOneAssociationMetadata) {
450 63
                    $targetClass = $this->em->getClassMetadata($property->getTargetEntity());
451 63
452
                    foreach ($property->getJoinColumns() as $joinColumn) {
453 63
                        /** @var JoinColumnMetadata $joinColumn */
454 63
                        $columnName           = $joinColumn->getColumnName();
455 63
                        $referencedColumnName = $joinColumn->getReferencedColumnName();
456
457
                        if (! $joinColumn->getType()) {
458
                            $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em));
459 63
                        }
460 46
461
                        $columns[] = $columnName;
462
463 46
                        $this->columns[$columnName] = $joinColumn;
464 46
                    }
465 46
                }
466
467
                continue;
468 41
            }
469
470
            if (
471
                $this->class->getClassName() !== $this->class->getRootClassName()
472 46
                || ! $this->class->getProperty($name)->hasValueGenerator()
473 43
                || $this->class->getProperty($name)->getValueGenerator()->getType() !== GeneratorType::IDENTITY
474 41
                || $this->class->identifier[0] !== $name
475
            ) {
476
                $columnName = $property->getColumnName();
477 33
478
                $columns[] = $columnName;
479 33
480 33
                $this->columns[$columnName] = $property;
481
            }
482 46
        }
483
484
        // Add discriminator column if it is the topmost class.
485
        if ($this->class->isRootEntity()) {
486
            $discrColumn     = $this->class->discriminatorColumn;
487 63
            $discrColumnName = $discrColumn->getColumnName();
488
489 63
            $columns[] = $discrColumnName;
490
491
            $this->columns[$discrColumnName] = $discrColumn;
492
        }
493
494
        return $columns;
495 275
    }
496
497
    /**
498 275
     * @param string $baseTableAlias
499 275
     *
500 269
     * @return string
501 275
     */
502
    private function getJoinSql($baseTableAlias)
503 275
    {
504 269
        $joinSql           = '';
505
        $identifierColumns = $this->class->getIdentifierColumns($this->em);
506 269
507
        // INNER JOIN parent tables
508
        $parentClass = $this->class;
509 275
510 9
        while (($parentClass = $parentClass->getParent()) !== null) {
511 275
            $conditions   = [];
512
            $tableName    = $parentClass->table->getQuotedQualifiedName($this->platform);
513
            $tableAlias   = $this->getSQLTableAlias($parentClass->getTableName());
514 275
            $joinSql     .= ' INNER JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
515 275
516
            foreach ($identifierColumns as $idColumn) {
517 275
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
518 275
519 275
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
520
            }
521 273
522
            $joinSql .= implode(' AND ', $conditions);
523
        }
524 275
525 256
        // OUTER JOIN sub tables
526
        foreach ($this->class->getSubClasses() as $subClassName) {
527 256
            $conditions  = [];
528 255
            $subClass    = $this->em->getClassMetadata($subClassName);
529
            $tableName   = $subClass->table->getQuotedQualifiedName($this->platform);
530 255
            $tableAlias  = $this->getSQLTableAlias($subClass->getTableName());
531 255
            $joinSql    .= ' LEFT JOIN ' . $tableName . ' ' . $tableAlias . ' ON ';
532 255
533
            foreach ($identifierColumns as $idColumn) {
534 255
                $quotedColumnName = $this->platform->quoteIdentifier($idColumn->getColumnName());
535
536 255
                $conditions[] = $baseTableAlias . '.' . $quotedColumnName . ' = ' . $tableAlias . '.' . $quotedColumnName;
537
            }
538 255
539
            $joinSql .= implode(' AND ', $conditions);
540
        }
541
542
        return $joinSql;
543 256
    }
544
}
545