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 Xhgui_Storage_Mongo 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 Xhgui_Storage_Mongo, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
6 | class Xhgui_Storage_Mongo extends Xhgui_Storage_Abstract implements |
||
7 | \Xhgui_StorageInterface, |
||
8 | \Xhgui_WatchedFunctionsStorageInterface |
||
9 | { |
||
10 | |||
11 | protected $config; |
||
12 | |||
13 | /** |
||
14 | * @var \MongoDB |
||
15 | */ |
||
16 | protected $connection; |
||
17 | |||
18 | /** |
||
19 | * @var int |
||
20 | */ |
||
21 | protected $defaultPerPage = 25; |
||
22 | |||
23 | /** |
||
24 | * @var string |
||
25 | */ |
||
26 | protected $collectionName; |
||
27 | |||
28 | /** |
||
29 | * @var \MongoClient |
||
30 | */ |
||
31 | protected $mongoClient; |
||
32 | |||
33 | /** |
||
34 | * Mongo constructor. |
||
35 | * @param $config |
||
36 | * @throws \MongoConnectionException |
||
37 | * @throws \MongoException |
||
38 | */ |
||
39 | public function __construct($config, $collection = 'results') |
||
55 | |||
56 | /** |
||
57 | * @inheritDoc |
||
58 | * @param $options |
||
59 | * @param bool $projections |
||
60 | * @return Xhgui_Storage_ResultSet |
||
61 | * @throws \MongoCursorException |
||
62 | */ |
||
63 | public function find(\Xhgui_Storage_Filter $filter, $projections = false) |
||
91 | |||
92 | /** |
||
93 | * @inheritDoc |
||
94 | * @param $options |
||
95 | * @return int |
||
96 | * @throws \MongoCursorTimeoutException |
||
97 | * @throws \MongoException |
||
98 | */ |
||
99 | public function count(\Xhgui_Storage_Filter $filter) |
||
106 | |||
107 | /** |
||
108 | * @inheritDoc |
||
109 | * @param $id |
||
110 | * @return array|null |
||
111 | * @throws \MongoException |
||
112 | */ |
||
113 | public function findOne($id) |
||
119 | |||
120 | /** |
||
121 | * @inheritDoc |
||
122 | * @param $id |
||
123 | * @return array|bool |
||
124 | * @throws MongoCursorException |
||
125 | * @throws MongoCursorTimeoutException |
||
126 | * @throws MongoException |
||
127 | */ |
||
128 | public function remove($id) |
||
135 | |||
136 | /** |
||
137 | * @inheritDoc |
||
138 | * @param $data |
||
139 | * @return array|bool |
||
140 | * @throws \MongoCursorException |
||
141 | * @throws \MongoCursorTimeoutException |
||
142 | * @throws \MongoException |
||
143 | */ |
||
144 | public function insert(array $data) |
||
151 | |||
152 | /** |
||
153 | * @inheritDoc |
||
154 | * @param $id |
||
155 | * @param $data |
||
156 | * @return array|bool |
||
157 | * @throws \MongoCursorException |
||
158 | * @throws \MongoException |
||
159 | * @throws \MongoWriteConcernException |
||
160 | */ |
||
161 | public function update($id, array $data) |
||
169 | |||
170 | /** |
||
171 | * @inheritDoc |
||
172 | */ |
||
173 | public function drop() |
||
177 | |||
178 | /** |
||
179 | * @inheritDoc |
||
180 | * @param $match |
||
181 | * @param $col |
||
182 | * @param int $percentile |
||
183 | * @codeCoverageIgnore despite appearances this is very simple function and there is nothing to test here. |
||
184 | * @return array |
||
185 | * @throws \MongoException |
||
186 | */ |
||
187 | public function aggregate(\Xhgui_Storage_Filter $filter, $col, $percentile = 1) |
||
238 | |||
239 | /** |
||
240 | * @inheritDoc |
||
241 | * @return array |
||
242 | */ |
||
243 | public function getWatchedFunctions() |
||
258 | |||
259 | /** |
||
260 | * @inheritDoc |
||
261 | * @param $name |
||
262 | * @return bool |
||
263 | */ |
||
264 | View Code Duplication | public function addWatchedFunction($name) |
|
288 | |||
289 | /** |
||
290 | * @inheritDoc |
||
291 | * @param $id |
||
292 | * @param $name |
||
293 | * @return bool |
||
294 | */ |
||
295 | View Code Duplication | public function updateWatchedFunction($id, $name) |
|
316 | |||
317 | /** |
||
318 | * @inheritDoc |
||
319 | * @param $id |
||
320 | * @return bool |
||
321 | */ |
||
322 | public function removeWatchedFunction($id) |
||
335 | |||
336 | /** |
||
337 | * Convert filter into mongo condition |
||
338 | * |
||
339 | * @param \Xhgui_Storage_Filter $filter |
||
340 | * @return array |
||
341 | */ |
||
342 | protected function getConditions(\Xhgui_Storage_Filter $filter) |
||
377 | |||
378 | /** |
||
379 | * Get mongo client from config |
||
380 | * |
||
381 | * @return MongoClient |
||
382 | * @throws MongoConnectionException |
||
383 | */ |
||
384 | public function getMongoClient() |
||
391 | |||
392 | /** |
||
393 | * Set prepared mongo client. |
||
394 | * |
||
395 | * @param MongoClient $mongoClient |
||
396 | */ |
||
397 | public function setMongoClient($mongoClient) |
||
401 | |||
402 | /** |
||
403 | * Get connection. |
||
404 | * |
||
405 | * @return MongoDB |
||
406 | * @throws MongoConnectionException |
||
407 | */ |
||
408 | public function getConnection() |
||
416 | |||
417 | /** |
||
418 | * Set existing connection |
||
419 | * |
||
420 | * @param MongoDB $connection |
||
421 | */ |
||
422 | public function setConnection($connection) |
||
426 | |||
427 | /** |
||
428 | * Select specific connection |
||
429 | * |
||
430 | * @return MongoCollection |
||
431 | * @throws Exception |
||
432 | */ |
||
433 | public function getCollection() |
||
437 | } |
||
438 |
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.