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 ConnectionTrait 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 ConnectionTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | trait ConnectionTrait |
||
25 | { |
||
26 | /** |
||
27 | * The used DBAL driver. |
||
28 | * |
||
29 | * Overwrite for type hint |
||
30 | * |
||
31 | * @var DriverInterface |
||
32 | */ |
||
33 | protected $_driver; |
||
34 | |||
35 | /** |
||
36 | * @var int |
||
37 | */ |
||
38 | protected $reconnectAttempts = 0; |
||
39 | |||
40 | /** |
||
41 | * @var int|bool |
||
42 | */ |
||
43 | protected $forceIgnoreTransactionLevel; |
||
44 | |||
45 | /** |
||
46 | * @var ReflectionProperty|null |
||
47 | */ |
||
48 | private $selfReflectionNestingLevelProperty; |
||
49 | |||
50 | /** |
||
51 | * ConnectionTrait constructor. |
||
52 | * |
||
53 | * @param mixed[] $params |
||
54 | * @param Driver $driver |
||
55 | * @param Configuration|null $config |
||
56 | * @param EventManager|null $eventManager |
||
57 | * |
||
58 | * @throws DBALException |
||
59 | */ |
||
60 | 14 | public function __construct( |
|
82 | |||
83 | /** |
||
84 | * @param string $query |
||
85 | * @param array $params |
||
86 | * @param array $types |
||
87 | * @param QueryCacheProfile $qcp |
||
88 | * |
||
89 | * @return ResultStatement the executed statement |
||
90 | * |
||
91 | * @throws Throwable |
||
92 | */ |
||
93 | public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null) |
||
121 | |||
122 | /** |
||
123 | * @return \Doctrine\DBAL\Driver\Statement |
||
124 | * |
||
125 | * @throws Throwable |
||
126 | */ |
||
127 | public function query() |
||
175 | |||
176 | /** |
||
177 | * @param string $query |
||
178 | * @param array $params |
||
179 | * @param array $types |
||
180 | * |
||
181 | * @return int the number of affected rows |
||
182 | * |
||
183 | * @throws Throwable |
||
184 | */ |
||
185 | public function executeUpdate($query, array $params = [], array $types = []) |
||
213 | |||
214 | /** |
||
215 | * @return bool|void |
||
216 | * |
||
217 | * @throws ReflectionException |
||
218 | * @throws Throwable |
||
219 | */ |
||
220 | public function beginTransaction() |
||
256 | |||
257 | /** |
||
258 | * Prepares an SQL statement. |
||
259 | * |
||
260 | * @param string $sql |
||
261 | * |
||
262 | * @return Statement the prepared statement |
||
263 | */ |
||
264 | public function prepare($sql) |
||
268 | |||
269 | /** |
||
270 | * do not use, only used by Statement-class |
||
271 | * needs to be public for access from the Statement-class. |
||
272 | * |
||
273 | * @param $sql |
||
274 | * |
||
275 | * @return Driver\Statement |
||
276 | * |
||
277 | * @throws DBALException |
||
278 | * |
||
279 | * @internal |
||
280 | */ |
||
281 | public function prepareUnwrapped(string $sql): \Doctrine\DBAL\Driver\Statement |
||
286 | |||
287 | /** |
||
288 | * Forces reconnection by doing a dummy query. |
||
289 | * |
||
290 | * @throws Throwable |
||
291 | */ |
||
292 | public function refresh(): void |
||
296 | |||
297 | /** |
||
298 | * @param $attempt |
||
299 | * @param bool $ignoreTransactionLevel |
||
300 | * |
||
301 | * @return bool |
||
302 | */ |
||
303 | public function canTryAgain(int $attempt, bool $ignoreTransactionLevel = false): bool |
||
312 | |||
313 | /** |
||
314 | * @param Throwable $e |
||
315 | * @param string|null $query |
||
316 | * |
||
317 | * @return bool |
||
318 | */ |
||
319 | public function isRetryableException(Throwable $e, string $query = null): bool |
||
327 | |||
328 | /** |
||
329 | * @param string $query |
||
330 | * |
||
331 | * @return bool |
||
332 | */ |
||
333 | 12 | public function isUpdateQuery($query): bool |
|
337 | |||
338 | /** |
||
339 | * returns a reconnect-wrapper for Statements. |
||
340 | * |
||
341 | * @param $sql |
||
342 | * |
||
343 | * @return Statement |
||
344 | */ |
||
345 | protected function prepareWrapped(string $sql): Driver\Statement |
||
349 | |||
350 | /** |
||
351 | * This is required because beginTransaction increment transactionNestingLevel |
||
352 | * before the real query is executed, and results incremented also on gone away error. |
||
353 | * This should be safe for a new established connection. |
||
354 | * |
||
355 | * @throws ReflectionException |
||
356 | * @throws ReflectionException |
||
357 | */ |
||
358 | private function resetTransactionNestingLevel(): void |
||
375 | } |
||
376 |
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.