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