Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like JoinedSubclassPersister often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use JoinedSubclassPersister, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class JoinedSubclassPersister extends AbstractEntityInheritancePersister |
||
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) |
||
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: |
||
247 | 5 | $lockSql = ' ' . $this->platform->getReadLockSQL(); |
|
248 | break; |
||
249 | 5 | ||
250 | 5 | case LockMode::PESSIMISTIC_WRITE: |
|
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): |
|
397 | $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass); |
||
398 | break; |
||
399 | 6 | ||
400 | case ($property instanceof ToOneAssociationMetadata && $property->isOwningSide()): |
||
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])*/) { |
||
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 | } |
|
545 |
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.