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 ContentRepository 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 ContentRepository, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | class ContentRepository |
||
13 | { |
||
14 | protected $storagePath; |
||
15 | protected $contentDbHandle; |
||
16 | |||
17 | /** |
||
18 | * ContentRepository constructor. |
||
19 | * @param $storagePath |
||
20 | */ |
||
21 | public function __construct($storagePath) |
||
25 | |||
26 | /** |
||
27 | * @return \PDO |
||
28 | */ |
||
29 | View Code Duplication | public function getContentDbHandle() |
|
36 | |||
37 | /** |
||
38 | * Prepare the sql statement |
||
39 | * @param $sql |
||
40 | * @return \PDOStatement |
||
41 | * @throws \Exception |
||
42 | */ |
||
43 | protected function getDbStatement($sql) |
||
54 | |||
55 | /** |
||
56 | * @param Repository $repository |
||
57 | * @param $document |
||
58 | * @param $db |
||
59 | * @param $documents |
||
60 | * @param $key |
||
61 | * @return mixed |
||
62 | */ |
||
63 | private function setAssetsToDocumentFolders(Repository $repository, $document, $db, $documents, $key) |
||
73 | |||
74 | /** |
||
75 | * @param Repository $repository |
||
76 | * @param string $folderPath |
||
77 | * @return array |
||
78 | * @throws \Exception |
||
79 | */ |
||
80 | public function getDocumentsWithState(Repository $repository, $folderPath = '/') |
||
114 | |||
115 | /** |
||
116 | * Get all documents and folders in a certain path |
||
117 | * |
||
118 | * @param Repository $repository |
||
119 | * @param $folderPath |
||
120 | * @param string $state |
||
121 | * @return array |
||
122 | * @throws \Exception |
||
123 | */ |
||
124 | public function getDocumentsByPath(Repository $repository, $folderPath, $state = 'published') |
||
146 | |||
147 | /** |
||
148 | * @param \CloudControl\Cms\storage\Repository $repository |
||
149 | * @param $path |
||
150 | * @param string $state |
||
151 | * @return bool|Document |
||
152 | * @throws \Exception |
||
153 | */ |
||
154 | public function getDocumentByPath(Repository $repository, $path, $state = 'published') |
||
171 | |||
172 | /** |
||
173 | * Return the result of the query as Document |
||
174 | * @param $sql |
||
175 | * @return mixed |
||
176 | * @throws \Exception |
||
177 | */ |
||
178 | protected function fetchDocument($sql) |
||
183 | |||
184 | /** |
||
185 | * @param Repository $repository |
||
186 | * @param $path |
||
187 | * @return bool|Document |
||
188 | * @throws \Exception |
||
189 | */ |
||
190 | public function getDocumentContainerByPath(Repository $repository, $path) |
||
207 | |||
208 | /** |
||
209 | * Create a (non-existent) root folder Document and return it |
||
210 | * @return Document |
||
211 | */ |
||
212 | protected function getRootFolder() |
||
219 | |||
220 | /** |
||
221 | * Returns the count of all documents stored in the db |
||
222 | * |
||
223 | * @param string $state |
||
224 | * |
||
225 | * @return int |
||
226 | * @throws \Exception |
||
227 | */ |
||
228 | public function getTotalDocumentCount($state = 'published') |
||
245 | |||
246 | /** |
||
247 | * @return array |
||
248 | * @throws \Exception |
||
249 | */ |
||
250 | public function getPublishedDocumentsNoFolders() |
||
267 | |||
268 | /** |
||
269 | * @param $path |
||
270 | * @throws \Exception |
||
271 | */ |
||
272 | public function publishDocumentByPath($path) |
||
276 | |||
277 | /** |
||
278 | * @param $path |
||
279 | * @throws \Exception |
||
280 | */ |
||
281 | public function unpublishDocumentByPath($path) |
||
285 | |||
286 | /** |
||
287 | * @param $path |
||
288 | * @param bool $publish |
||
289 | * @throws \Exception |
||
290 | */ |
||
291 | public function publishOrUnpublishDocumentByPath($path, $publish = true) |
||
314 | |||
315 | public function cleanPublishedDeletedDocuments() |
||
328 | |||
329 | /** |
||
330 | * Save the document to the database |
||
331 | * |
||
332 | * @param Document $documentObject |
||
333 | * @param string $state |
||
334 | * |
||
335 | * @return bool |
||
336 | * @throws \Exception |
||
337 | */ |
||
338 | public function saveDocument($documentObject, $state = 'published') |
||
364 | |||
365 | /** |
||
366 | * Delete the document from the database |
||
367 | * If it's a folder, also delete it's contents |
||
368 | * |
||
369 | * @param Repository $repository |
||
370 | * @param $path |
||
371 | * @throws \Exception |
||
372 | */ |
||
373 | public function deleteDocumentByPath(Repository $repository, $path) |
||
396 | } |
||
397 | |||
399 | } |
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.