Total Complexity | 63 |
Total Lines | 454 |
Duplicated Lines | 21.59 % |
Coverage | 98.76% |
Changes | 0 |
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 ResultSetMappingBuilder 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.
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 ResultSetMappingBuilder, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | class ResultSetMappingBuilder extends ResultSetMapping |
||
25 | { |
||
26 | /** |
||
27 | * Picking this rename mode will register entity columns as is, |
||
28 | * as they are in the database. This can cause clashes when multiple |
||
29 | * entities are fetched that have columns with the same name. |
||
30 | * |
||
31 | * @var int |
||
32 | */ |
||
33 | const COLUMN_RENAMING_NONE = 1; |
||
34 | |||
35 | /** |
||
36 | * Picking custom renaming allows the user to define the renaming |
||
37 | * of specific columns with a rename array that contains column names as |
||
38 | * keys and result alias as values. |
||
39 | * |
||
40 | * @var int |
||
41 | */ |
||
42 | const COLUMN_RENAMING_CUSTOM = 2; |
||
43 | |||
44 | /** |
||
45 | * Incremental renaming uses a result set mapping internal counter to add a |
||
46 | * number to each column result, leading to uniqueness. This only works if |
||
47 | * you use {@see generateSelectClause()} to generate the SELECT clause for |
||
48 | * you. |
||
49 | * |
||
50 | * @var int |
||
51 | */ |
||
52 | const COLUMN_RENAMING_INCREMENT = 3; |
||
53 | |||
54 | /** |
||
55 | * @var int |
||
56 | */ |
||
57 | private $sqlCounter = 0; |
||
58 | |||
59 | /** |
||
60 | * @var EntityManagerInterface |
||
61 | */ |
||
62 | private $em; |
||
63 | |||
64 | /** |
||
65 | * Default column renaming mode. |
||
66 | * |
||
67 | * @var int |
||
68 | */ |
||
69 | private $defaultRenameMode; |
||
70 | |||
71 | /** |
||
72 | * @param EntityManagerInterface $em |
||
73 | * @param integer $defaultRenameMode |
||
74 | */ |
||
75 | public function __construct(EntityManagerInterface $em, $defaultRenameMode = self::COLUMN_RENAMING_NONE) |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Adds a root entity and all of its fields to the result set. |
||
83 | * |
||
84 | * @param string $class The class name of the root entity. |
||
85 | 57 | * @param string $alias The unique alias to use for the root entity. |
|
86 | * @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName). |
||
87 | 57 | * @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM). |
|
88 | 57 | * |
|
89 | 57 | * @return void |
|
90 | */ |
||
91 | View Code Duplication | public function addRootEntityFromClassMetadata( |
|
102 | } |
||
103 | 38 | ||
104 | 38 | /** |
|
105 | * Adds a joined entity and all of its fields to the result set. |
||
106 | 38 | * |
|
107 | 38 | * @param string $class The class name of the joined entity. |
|
108 | 37 | * @param string $alias The unique alias to use for the joined entity. |
|
109 | * @param string $parentAlias The alias of the entity result that is the parent of this joined result. |
||
110 | * @param string $relation The association field that connects the parent entity result |
||
111 | * with the joined entity result. |
||
112 | * @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName). |
||
113 | * @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM). |
||
114 | * |
||
115 | * @return void |
||
116 | */ |
||
117 | View Code Duplication | public function addJoinedEntityFromClassMetadata( |
|
118 | string $class, |
||
119 | string $alias, |
||
120 | string $parentAlias, |
||
121 | string $relation, |
||
122 | array $renamedColumns = [], |
||
123 | 12 | int $renameMode = null |
|
124 | ) |
||
125 | 12 | { |
|
126 | 12 | $renameMode = $renameMode ?: (empty($renamedColumns) ? $this->defaultRenameMode : self::COLUMN_RENAMING_CUSTOM); |
|
127 | |||
128 | 12 | $this->addJoinedEntityResult($class, $alias, $parentAlias, $relation); |
|
129 | 12 | $this->addAllClassFields($class, $alias, $renamedColumns, $renameMode); |
|
130 | 11 | } |
|
131 | |||
132 | /** |
||
133 | * Adds all fields of the given class to the result set mapping (columns and meta fields). |
||
134 | * |
||
135 | * @param string $class |
||
136 | * @param string $alias |
||
137 | * @param array $customRenameColumns |
||
138 | * |
||
139 | * @return void |
||
140 | * |
||
141 | * @throws \InvalidArgumentException |
||
142 | */ |
||
143 | 38 | protected function addAllClassFields(string $class, string $alias, array $customRenameColumns, int $renameMode) : void |
|
196 | } |
||
197 | } |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Checks if inheritance if supported. |
||
202 | * |
||
203 | 38 | * @param ClassMetadata $metadata |
|
204 | * |
||
205 | * @return boolean |
||
206 | 38 | */ |
|
207 | 3 | private function isInheritanceSupported(ClassMetadata $metadata) |
|
208 | { |
||
209 | 35 | if ($metadata->inheritanceType === InheritanceType::SINGLE_TABLE |
|
210 | 11 | && in_array($metadata->getClassName(), $metadata->discriminatorMap, true)) { |
|
211 | 11 | return true; |
|
212 | } |
||
213 | 34 | ||
214 | 34 | return ! in_array($metadata->inheritanceType, [InheritanceType::SINGLE_TABLE, InheritanceType::JOINED]); |
|
215 | } |
||
216 | |||
217 | /** |
||
218 | * Gets column alias for a given column. |
||
219 | * |
||
220 | * @param string $columnName |
||
221 | * @param int $mode |
||
222 | * @param array $customRenameColumns |
||
223 | * |
||
224 | * @return string |
||
225 | */ |
||
226 | private function getColumnAlias($columnName, $mode, array $customRenameColumns) |
||
227 | { |
||
228 | switch ($mode) { |
||
229 | case self::COLUMN_RENAMING_INCREMENT: |
||
230 | 38 | return $columnName . $this->sqlCounter++; |
|
231 | |||
232 | 38 | case self::COLUMN_RENAMING_CUSTOM: |
|
233 | 11 | return $customRenameColumns[$columnName] ?? $columnName; |
|
234 | |||
235 | case self::COLUMN_RENAMING_NONE: |
||
236 | 38 | return $columnName; |
|
237 | 38 | ||
238 | } |
||
239 | 38 | } |
|
240 | 38 | ||
241 | /** |
||
242 | * Adds the mappings of the results of native SQL queries to the result set. |
||
243 | 38 | * |
|
244 | 29 | * @param ClassMetadata $class |
|
245 | 23 | * @param array $queryMapping |
|
246 | 23 | * |
|
247 | 29 | * @return ResultSetMappingBuilder |
|
248 | */ |
||
249 | public function addNamedNativeQueryMapping(ClassMetadata $class, array $queryMapping) |
||
250 | { |
||
251 | if (isset($queryMapping['resultClass'])) { |
||
252 | 38 | $entityClass = ($queryMapping['resultClass'] === '__CLASS__') |
|
253 | ? $class |
||
254 | : $this->em->getClassMetadata($queryMapping['resultClass']) |
||
255 | ; |
||
256 | |||
257 | $this->addEntityResult($entityClass->getClassName(), 'e0'); |
||
258 | $this->addNamedNativeQueryEntityResultMapping($entityClass, [], 'e0'); |
||
259 | |||
260 | return $this; |
||
261 | } |
||
262 | |||
263 | 10 | return $this->addNamedNativeQueryResultSetMapping($class, $queryMapping['resultSetMapping']); |
|
264 | } |
||
265 | 10 | ||
266 | 3 | /** |
|
267 | * Adds the result set mapping of the results of native SQL queries to the result set. |
||
268 | * |
||
269 | 8 | * @param ClassMetadata $class |
|
270 | * @param string $resultSetMappingName |
||
271 | * |
||
272 | * @return ResultSetMappingBuilder |
||
273 | */ |
||
274 | public function addNamedNativeQueryResultSetMapping(ClassMetadata $class, $resultSetMappingName) |
||
275 | { |
||
276 | $counter = 0; |
||
277 | $resultMapping = $class->getSqlResultSetMapping($resultSetMappingName); |
||
278 | $rootAlias = 'e' . $counter; |
||
279 | |||
280 | 3 | if (isset($resultMapping['entities'])) { |
|
281 | foreach ($resultMapping['entities'] as $key => $entityMapping) { |
||
282 | 3 | $entityMapping['entityClass'] = ($entityMapping['entityClass'] === '__CLASS__') |
|
283 | 3 | ? $class->getClassName() |
|
284 | 3 | : $entityMapping['entityClass'] |
|
285 | ; |
||
286 | 3 | ||
287 | $classMetadata = $this->em->getClassMetadata($entityMapping['entityClass']); |
||
288 | 3 | ||
289 | 1 | if ($class->getClassName() === $classMetadata->getClassName()) { |
|
290 | 1 | $this->addEntityResult($classMetadata->getClassName(), $rootAlias); |
|
291 | 1 | $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $rootAlias); |
|
292 | } else { |
||
293 | 1 | $joinAlias = 'e' . ++$counter; |
|
294 | 1 | ||
295 | $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $joinAlias); |
||
296 | |||
297 | 3 | foreach ($class->getDeclaredPropertiesIterator() as $fieldName => $association) { |
|
298 | 3 | if (! ($association instanceof AssociationMetadata)) { |
|
299 | continue; |
||
300 | 3 | } |
|
301 | |||
302 | if ($association->getTargetEntity() !== $classMetadata->getClassName()) { |
||
303 | 3 | continue; |
|
304 | 3 | } |
|
305 | 3 | ||
306 | $this->addJoinedEntityResult($association->getTargetEntity(), $joinAlias, $rootAlias, $fieldName); |
||
307 | 3 | } |
|
308 | 3 | } |
|
309 | 3 | ||
310 | } |
||
311 | 3 | } |
|
312 | |||
313 | if (isset($resultMapping['columns'])) { |
||
314 | foreach ($resultMapping['columns'] as $entityMapping) { |
||
315 | // @todo guilhermeblanco Collect type information from mapped column |
||
316 | 3 | $this->addScalarResult($entityMapping['name'], $entityMapping['name'], Type::getType('string')); |
|
317 | } |
||
318 | } |
||
319 | |||
320 | return $this; |
||
321 | } |
||
322 | |||
323 | /** |
||
324 | * Adds the entity result mapping of the results of native SQL queries to the result set. |
||
325 | * |
||
326 | * @param ClassMetadata $classMetadata |
||
327 | 8 | * @param array $entityMapping |
|
328 | * @param string $alias |
||
329 | 8 | * |
|
330 | 8 | * @return ResultSetMappingBuilder |
|
331 | 8 | * |
|
332 | 8 | * @throws MappingException |
|
333 | * @throws \InvalidArgumentException |
||
334 | 8 | */ |
|
335 | 8 | public function addNamedNativeQueryEntityResultMapping(ClassMetadata $classMetadata, array $entityMapping, $alias) |
|
431 | } |
||
432 | |||
433 | /** |
||
434 | * Generates the Select clause from this ResultSetMappingBuilder. |
||
435 | * |
||
436 | * Works only for all the entity results. The select parts for scalar |
||
437 | * expressions have to be written manually. |
||
438 | * |
||
439 | * @param array $tableAliases |
||
440 | * |
||
441 | * @return string |
||
442 | 13 | */ |
|
443 | public function generateSelectClause($tableAliases = []) |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * @return string |
||
474 | 1 | */ |
|
475 | public function __toString() |
||
480 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.