Failed Conditions
Pull Request — 2.6 (#7882)
by
unknown
08:05
created

JoinedSubclassPersister::getSelectSQL()   C

Complexity

Conditions 12
Paths 288

Size

Total Lines 60
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 13.0579

Importance

Changes 0
Metric Value
eloc 36
c 0
b 0
f 0
dl 0
loc 60
ccs 29
cts 36
cp 0.8056
rs 5.0333
cc 12
nc 288
nop 6
crap 13.0579

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
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Persisters\Entity;
21
22
use Doctrine\ORM\Mapping\ClassMetadata;
23
24
use Doctrine\DBAL\LockMode;
25
use Doctrine\DBAL\Types\Type;
26
27
use Doctrine\Common\Collections\Criteria;
28
use Doctrine\ORM\Utility\PersisterHelper;
29
30
/**
31
 * The joined subclass persister maps a single entity instance to several tables in the
32
 * database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
33
 *
34
 * @author Roman Borschel <[email protected]>
35
 * @author Benjamin Eberlei <[email protected]>
36
 * @author Alexander <[email protected]>
37
 * @since 2.0
38
 * @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
39
 */
40
class JoinedSubclassPersister extends AbstractEntityInheritancePersister
41
{
42
    /**
43
     * Map that maps column names to the table names that own them.
44
     * This is mainly a temporary cache, used during a single request.
45
     *
46
     * @var array
47
     */
48
    private $owningTableMap = [];
49
50
    /**
51
     * Map of table to quoted table names.
52
     *
53
     * @var array
54
     */
55
    private $quotedTableMap = [];
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 279
    protected function getDiscriminatorColumnTableName()
61
    {
62 279
        $class = ($this->class->name !== $this->class->rootEntityName)
63 274
            ? $this->em->getClassMetadata($this->class->rootEntityName)
64 279
            : $this->class;
65
66 279
        return $class->getTableName();
67
    }
68
69
    /**
70
     * This function finds the ClassMetadata instance in an inheritance hierarchy
71
     * that is responsible for enabling versioning.
72
     *
73
     * @return \Doctrine\ORM\Mapping\ClassMetadata
74
     */
75 16
    private function getVersionedClassMetadata()
76
    {
77 16
        if (isset($this->class->fieldMappings[$this->class->versionField]['inherited'])) {
78 6
            $definingClassName = $this->class->fieldMappings[$this->class->versionField]['inherited'];
79
80 6
            return $this->em->getClassMetadata($definingClassName);
81
        }
82
83 10
        return $this->class;
84
    }
85
86
    /**
87
     * Gets the name of the table that owns the column the given field is mapped to.
88
     *
89
     * @param string $fieldName
90
     *
91
     * @return string
92
     *
93
     * @override
94
     */
95 277
    public function getOwningTable($fieldName)
96
    {
97 277
        if (isset($this->owningTableMap[$fieldName])) {
98 140
            return $this->owningTableMap[$fieldName];
99
        }
100
101
        switch (true) {
102 277
            case isset($this->class->associationMappings[$fieldName]['inherited']):
103 242
                $cm = $this->em->getClassMetadata($this->class->associationMappings[$fieldName]['inherited']);
104 242
                break;
105
106 226
            case isset($this->class->fieldMappings[$fieldName]['inherited']):
107 202
                $cm = $this->em->getClassMetadata($this->class->fieldMappings[$fieldName]['inherited']);
108 202
                break;
109
110
            default:
111 220
                $cm = $this->class;
112 220
                break;
113
        }
114
115 277
        $tableName          = $cm->getTableName();
116 277
        $quotedTableName    = $this->quoteStrategy->getTableName($cm, $this->platform);
117
118 277
        $this->owningTableMap[$fieldName] = $tableName;
119 277
        $this->quotedTableMap[$tableName] = $quotedTableName;
120
121 277
        return $tableName;
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127 290
    public function executeInserts()
128
    {
129 290
        if ( ! $this->queuedInserts) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->queuedInserts of type array 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...
130 198
            return [];
131
        }
132
133 280
        $postInsertIds  = [];
134 280
        $idGenerator    = $this->class->idGenerator;
135 280
        $isPostInsertId = $idGenerator->isPostInsertGenerator();
136 280
        $rootClass      = ($this->class->name !== $this->class->rootEntityName)
137 275
            ? $this->em->getClassMetadata($this->class->rootEntityName)
138 280
            : $this->class;
139
140
        // Prepare statement for the root table
141 280
        $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->name);
142 280
        $rootTableName = $rootClass->getTableName();
143 280
        $rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL());
144
145
        // Prepare statements for sub tables.
146 280
        $subTableStmts = [];
147
148 280
        if ($rootClass !== $this->class) {
149 275
            $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
150
        }
151
152 280
        foreach ($this->class->parentClasses as $parentClassName) {
153 275
            $parentClass = $this->em->getClassMetadata($parentClassName);
154 275
            $parentTableName = $parentClass->getTableName();
155
156 275
            if ($parentClass !== $rootClass) {
157 160
                $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClassName);
158 275
                $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL());
159
            }
160
        }
161
162
        // Execute all inserts. For each entity:
163
        // 1) Insert on root table
164
        // 2) Insert on sub tables
165 280
        foreach ($this->queuedInserts as $entity) {
166 280
            $insertData = $this->prepareInsertData($entity);
167
168
            // Execute insert on root table
169 279
            $paramIndex = 1;
170
171 279
            foreach ($insertData[$rootTableName] as $columnName => $value) {
172 279
                $rootTableStmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
173
            }
174
175 279
            $rootTableStmt->execute();
176
177 279
            if ($isPostInsertId) {
178 274
                $generatedId = $idGenerator->generate($this->em, $entity);
179
                $id = [
180 274
                    $this->class->identifier[0] => $generatedId
181
                ];
182 274
                $postInsertIds[] = [
183 274
                    'generatedId' => $generatedId,
184 274
                    'entity' => $entity,
185
                ];
186
            } else {
187 5
                $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
188
            }
189
190 279
            if ($this->class->isVersioned) {
191 9
                $this->assignDefaultVersionValue($entity, $id);
192
            }
193
194
            // Execute inserts on subtables.
195
            // The order doesn't matter because all child tables link to the root table via FK.
196 279
            foreach ($subTableStmts as $tableName => $stmt) {
197
                /** @var \Doctrine\DBAL\Statement $stmt */
198 274
                $paramIndex = 1;
199 274
                $data       = $insertData[$tableName] ?? [];
200
201 274
                foreach ((array) $id as $idName => $idVal) {
202 274
                    $type = isset($this->columnTypes[$idName]) ? $this->columnTypes[$idName] : Type::STRING;
203
204 274
                    $stmt->bindValue($paramIndex++, $idVal, $type);
205
                }
206
207 274
                foreach ($data as $columnName => $value) {
208 209
                    if (!is_array($id) || !isset($id[$columnName])) {
209 209
                        $stmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
210
                    }
211
                }
212
213 279
                $stmt->execute();
214
            }
215
        }
216
217 279
        $rootTableStmt->closeCursor();
218
219 279
        foreach ($subTableStmts as $stmt) {
220 274
            $stmt->closeCursor();
221
        }
222
223 279
        $this->queuedInserts = [];
224
225 279
        return $postInsertIds;
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231 11
    public function update($entity)
232
    {
233 11
        $updateData = $this->prepareUpdateData($entity);
234
235 11
        if ( ! $updateData) {
236
            return;
237
        }
238
239 11
        if (($isVersioned = $this->class->isVersioned) === false) {
240
            return;
241
        }
242
243 11
        $versionedClass  = $this->getVersionedClassMetadata();
244 11
        $versionedTable  = $versionedClass->getTableName();
245
246 11
        foreach ($updateData as $tableName => $data) {
247 11
            $tableName = $this->quotedTableMap[$tableName];
248 11
            $versioned = $isVersioned && $versionedTable === $tableName;
249
250 11
            $this->updateTable($entity, $tableName, $data, $versioned);
251
        }
252
253
        // Make sure the table with the version column is updated even if no columns on that
254
        // table were affected.
255 10
        if ($isVersioned) {
256 5
            if ( ! isset($updateData[$versionedTable])) {
257 2
                $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform);
258
259 2
                $this->updateTable($entity, $tableName, [], true);
260
            }
261
262 4
            $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
263
264 4
            $this->assignDefaultVersionValue($entity, $identifiers);
265
        }
266 9
    }
267
268
    /**
269
     * {@inheritdoc}
270
     */
271 6
    public function delete($entity)
272
    {
273 6
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
274 6
        $id         = array_combine($this->class->getIdentifierColumnNames(), $identifier);
275
276 6
        $this->deleteJoinTableRecords($identifier);
277
278
        // If the database platform supports FKs, just
279
        // delete the row from the root table. Cascades do the rest.
280 6
        if ($this->platform->supportsForeignKeyConstraints()) {
281
            $rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
282
            $rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform);
283
            $rootTypes = $this->getClassIdentifiersTypes($rootClass);
284
285
            return (bool) $this->conn->delete($rootTable, $id, $rootTypes);
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

285
            return (bool) $this->conn->delete($rootTable, /** @scrutinizer ignore-type */ $id, $rootTypes);
Loading history...
286
        }
287
288
        // Delete from all tables individually, starting from this class' table up to the root table.
289 6
        $rootTable = $this->quoteStrategy->getTableName($this->class, $this->platform);
290 6
        $rootTypes = $this->getClassIdentifiersTypes($this->class);
291
292 6
        $affectedRows = $this->conn->delete($rootTable, $id, $rootTypes);
293
294 6
        foreach ($this->class->parentClasses as $parentClass) {
295 5
            $parentMetadata = $this->em->getClassMetadata($parentClass);
296 5
            $parentTable    = $this->quoteStrategy->getTableName($parentMetadata, $this->platform);
297 5
            $parentTypes    = $this->getClassIdentifiersTypes($parentMetadata);
298
299 5
            $this->conn->delete($parentTable, $id, $parentTypes);
300
        }
301
302 6
        return (bool) $affectedRows;
303
    }
304
305
    /**
306
     * {@inheritdoc}
307
     */
308 63
    public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null)
309
    {
310 63
        $this->switchPersisterContext($offset, $limit);
311
312 63
        $baseTableAlias = $this->getSQLTableAlias($this->class->name);
313 63
        $joinSql        = $this->getJoinSql($baseTableAlias);
314
315 63
        if ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
316 2
            $joinSql .= $this->getSelectManyToManyJoinSQL($assoc);
317
        }
318
319 63
        $conditionSql = ($criteria instanceof Criteria)
320
            ? $this->getSelectConditionCriteriaSQL($criteria)
321 63
            : $this->getSelectConditionSQL($criteria, $assoc);
322
323
        // If the current class in the root entity, add the filters
324 63
        if ($filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName))) {
325 3
            $conditionSql .= $conditionSql
326 1
                ? ' AND ' . $filterSql
327 3
                : $filterSql;
328
        }
329
330 63
        $orderBySql = '';
331
332 63
        if ($assoc !== null && isset($assoc['orderBy'])) {
333
            $orderBy = $assoc['orderBy'];
334
        }
335
336 63
        if ($orderBy) {
337
            $orderBySql = $this->getOrderBySQL($orderBy, $baseTableAlias);
338
        }
339
340 63
        $lockSql = '';
341
342
        switch ($lockMode) {
343 63
            case LockMode::PESSIMISTIC_READ:
344
345
                $lockSql = ' ' . $this->platform->getReadLockSQL();
346
347
                break;
348
349 63
            case LockMode::PESSIMISTIC_WRITE:
350
351
                $lockSql = ' ' . $this->platform->getWriteLockSQL();
352
353
                break;
354
        }
355
356 63
        $tableName  = $this->quoteStrategy->getTableName($this->class, $this->platform);
357 63
        $from       = ' FROM ' . $tableName . ' ' . $baseTableAlias;
358 63
        $where      = $conditionSql != '' ? ' WHERE ' . $conditionSql : '';
359 63
        $lock       = $this->platform->appendLockHint($from, $lockMode);
360 63
        $columnList = $this->getSelectColumnsSQL();
361 63
        $query      = 'SELECT '  . $columnList
362 63
                    . $lock
363 63
                    . $joinSql
364 63
                    . $where
365 63
                    . $orderBySql;
366
367 63
        return $this->platform->modifyLimitQuery($query, $limit, $offset) . $lockSql;
368
    }
369
370
    /**
371
     * {@inheritDoc}
372
     */
373 4
    public function getCountSQL($criteria = [])
374
    {
375 4
        $tableName      = $this->quoteStrategy->getTableName($this->class, $this->platform);
376 4
        $baseTableAlias = $this->getSQLTableAlias($this->class->name);
377 4
        $joinSql        = $this->getJoinSql($baseTableAlias);
378
379 4
        $conditionSql = ($criteria instanceof Criteria)
380 4
            ? $this->getSelectConditionCriteriaSQL($criteria)
381 4
            : $this->getSelectConditionSQL($criteria);
382
383 4
        $filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName));
384
385 4
        if ('' !== $filterSql) {
386
            $conditionSql = $conditionSql
387
                ? $conditionSql . ' AND ' . $filterSql
388
                : $filterSql;
389
        }
390
391
        $sql = 'SELECT COUNT(*) '
392 4
            . 'FROM ' . $tableName . ' ' . $baseTableAlias
393 4
            . $joinSql
394 4
            . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
395
396 4
        return $sql;
397
    }
398
399
    /**
400
     * {@inheritdoc}
401
     */
402 5
    protected function getLockTablesSql($lockMode)
403
    {
404 5
        $joinSql            = '';
405 5
        $identifierColumns  = $this->class->getIdentifierColumnNames();
406 5
        $baseTableAlias     = $this->getSQLTableAlias($this->class->name);
407
408
        // INNER JOIN parent tables
409 5
        foreach ($this->class->parentClasses as $parentClassName) {
410 5
            $conditions     = [];
411 5
            $tableAlias     = $this->getSQLTableAlias($parentClassName);
412 5
            $parentClass    = $this->em->getClassMetadata($parentClassName);
413 5
            $joinSql       .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
414
415 5
            foreach ($identifierColumns as $idColumn) {
416 5
                $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
417
            }
418
419 5
            $joinSql .= implode(' AND ', $conditions);
420
        }
421
422 5
        return parent::getLockTablesSql($lockMode) . $joinSql;
423
    }
424
425
    /**
426
     * Ensure this method is never called. This persister overrides getSelectEntitiesSQL directly.
427
     *
428
     * @return string
429
     */
430 63
    protected function getSelectColumnsSQL()
431
    {
432
        // Create the column list fragment only once
433 63
        if ($this->currentPersisterContext->selectColumnListSql !== null) {
434 14
            return $this->currentPersisterContext->selectColumnListSql;
435
        }
436
437 63
        $columnList         = [];
438 63
        $discrColumn        = $this->class->discriminatorColumn['name'];
439 63
        $discrColumnType    = $this->class->discriminatorColumn['type'];
440 63
        $baseTableAlias     = $this->getSQLTableAlias($this->class->name);
441 63
        $resultColumnName   = $this->platform->getSQLResultCasing($discrColumn);
442
443 63
        $this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r');
444 63
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
445 63
        $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn, false, $discrColumnType);
446
447
        // Add regular columns
448 63
        foreach ($this->class->fieldMappings as $fieldName => $mapping) {
449 63
            $class = isset($mapping['inherited'])
450 46
                ? $this->em->getClassMetadata($mapping['inherited'])
451 63
                : $this->class;
452
453 63
            $columnList[] = $this->getSelectColumnSQL($fieldName, $class);
454
        }
455
456
        // Add foreign key columns
457 63
        foreach ($this->class->associationMappings as $mapping) {
458 49
            if ( ! $mapping['isOwningSide'] || ! ($mapping['type'] & ClassMetadata::TO_ONE)) {
459 40
                continue;
460
            }
461
462 48
            $tableAlias = isset($mapping['inherited'])
463 38
                ? $this->getSQLTableAlias($mapping['inherited'])
464 48
                : $baseTableAlias;
465
466 48
            $targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
467
468 48
            foreach ($mapping['joinColumns'] as $joinColumn) {
469 48
                $columnList[] = $this->getSelectJoinColumnSQL(
470 48
                    $tableAlias,
471 48
                    $joinColumn['name'],
472 48
                    $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform),
473 48
                    PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em)
474
                );
475
            }
476
        }
477
478
        // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
479 63
        $tableAlias = ($this->class->rootEntityName == $this->class->name)
480 19
            ? $baseTableAlias
481 63
            : $this->getSQLTableAlias($this->class->rootEntityName);
482
483 63
        $columnList[] = $tableAlias . '.' . $discrColumn;
484
485
        // sub tables
486 63
        foreach ($this->class->subClasses as $subClassName) {
487 43
            $subClass   = $this->em->getClassMetadata($subClassName);
488 43
            $tableAlias = $this->getSQLTableAlias($subClassName);
489
490
            // Add subclass columns
491 43
            foreach ($subClass->fieldMappings as $fieldName => $mapping) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
492 43
                if (isset($mapping['inherited'])) {
493 43
                    continue;
494
                }
495
496 40
                $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
497
            }
498
499
            // Add join columns (foreign keys)
500 43
            foreach ($subClass->associationMappings as $mapping) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
501 36
                if ( ! $mapping['isOwningSide']
502 36
                        || ! ($mapping['type'] & ClassMetadata::TO_ONE)
503 36
                        || isset($mapping['inherited'])) {
504 35
                    continue;
505
                }
506
507 29
                $targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
508
509 29
                foreach ($mapping['joinColumns'] as $joinColumn) {
510 29
                    $columnList[] = $this->getSelectJoinColumnSQL(
511 29
                        $tableAlias,
512 29
                        $joinColumn['name'],
513 29
                        $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform),
514 43
                        PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em)
515
                    );
516
                }
517
            }
518
        }
519
520 63
        $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
521
522 63
        return $this->currentPersisterContext->selectColumnListSql;
523
    }
524
525
    /**
526
     * {@inheritdoc}
527
     */
528 280
    protected function getInsertColumnList()
529
    {
530
        // Identifier columns must always come first in the column list of subclasses.
531 280
        $columns = $this->class->parentClasses
532 275
            ? $this->class->getIdentifierColumnNames()
533 280
            : [];
534
535 280
        foreach ($this->class->reflFields as $name => $field) {
536 280
            if (isset($this->class->fieldMappings[$name]['inherited'])
537 275
                    && ! isset($this->class->fieldMappings[$name]['id'])
538 280
                    || isset($this->class->associationMappings[$name]['inherited'])
539 280
                    || ($this->class->isVersioned && $this->class->versionField == $name)
540 280
                    || isset($this->class->embeddedClasses[$name])) {
541 261
                continue;
542
            }
543
544 280
            if (isset($this->class->associationMappings[$name])) {
545 248
                $assoc = $this->class->associationMappings[$name];
546 248
                if ($assoc['type'] & ClassMetadata::TO_ONE && $assoc['isOwningSide']) {
547 247
                    foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
548 248
                        $columns[] = $sourceCol;
549
                    }
550
                }
551 280
            } else if ($this->class->name != $this->class->rootEntityName ||
552 280
                    ! $this->class->isIdGeneratorIdentity() || $this->class->identifier[0] != $name) {
553 280
                $columns[]                  = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform);
554 280
                $this->columnTypes[$name]   = $this->class->fieldMappings[$name]['type'];
555
            }
556
        }
557
558
        // Add discriminator column if it is the topmost class.
559 280
        if ($this->class->name == $this->class->rootEntityName) {
560 280
            $columns[] = $this->class->discriminatorColumn['name'];
561
        }
562
563 280
        return $columns;
564
    }
565
566
    /**
567
     * {@inheritdoc}
568
     */
569 9
    protected function assignDefaultVersionValue($entity, array $id)
570
    {
571 9
        $value = $this->fetchVersionValue($this->getVersionedClassMetadata(), $id);
572 9
        $this->class->setFieldValue($entity, $this->class->versionField, $value);
573 9
    }
574
575
    /**
576
     * @param string $baseTableAlias
577
     *
578
     * @return string
579
     */
580 67
    private function getJoinSql($baseTableAlias)
581
    {
582 67
        $joinSql          = '';
583 67
        $identifierColumn = $this->class->getIdentifierColumnNames();
584
585
        // INNER JOIN parent tables
586 67
        foreach ($this->class->parentClasses as $parentClassName) {
587 50
            $conditions   = [];
588 50
            $parentClass  = $this->em->getClassMetadata($parentClassName);
589 50
            $tableAlias   = $this->getSQLTableAlias($parentClassName);
590 50
            $joinSql     .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
591
592
593 50
            foreach ($identifierColumn as $idColumn) {
594 50
                $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
595
            }
596
597 50
            $joinSql .= implode(' AND ', $conditions);
598
        }
599
600
        // OUTER JOIN sub tables
601 67
        foreach ($this->class->subClasses as $subClassName) {
602 44
            $conditions  = [];
603 44
            $subClass    = $this->em->getClassMetadata($subClassName);
604 44
            $tableAlias  = $this->getSQLTableAlias($subClassName);
605 44
            $joinSql    .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON ';
606
607 44
            foreach ($identifierColumn as $idColumn) {
608 44
                $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
609
            }
610
611 44
            $joinSql .= implode(' AND ', $conditions);
612
        }
613
614 67
        return $joinSql;
615
    }
616
}
617