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 Loco 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 Loco, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class Loco implements TranslationServiceInterface |
||
17 | { |
||
18 | const BASE_URL = 'https://localise.biz/api/'; |
||
19 | |||
20 | /** |
||
21 | * @var RequestManager |
||
22 | */ |
||
23 | private $requestManager; |
||
24 | |||
25 | /** |
||
26 | * @var array projects |
||
27 | */ |
||
28 | private $projects; |
||
29 | |||
30 | /** |
||
31 | * @var FilesystemUpdater filesystemService |
||
32 | */ |
||
33 | private $filesystemService; |
||
34 | |||
35 | /** |
||
36 | * @var TranslatorInterface filesystemService |
||
37 | */ |
||
38 | private $translator; |
||
39 | |||
40 | /** |
||
41 | * @param TranslatorInterface $translator |
||
42 | * @param RequestManager $requestManager |
||
43 | * @param FilesystemUpdater $fs |
||
44 | * @param array $projects |
||
45 | */ |
||
46 | 1 | public function __construct(RequestManager $requestManager, FilesystemUpdater $fs, TranslatorInterface $translator, array $projects) |
|
53 | |||
54 | /** |
||
55 | * @param $key |
||
56 | * @param $method |
||
57 | * @param $resource |
||
58 | * @param null $body |
||
59 | * @param string $type |
||
60 | * @param array $extraQuery |
||
61 | * @return array |
||
62 | * @throws HttpException |
||
63 | */ |
||
64 | protected function makeApiRequest($key, $method, $resource, $body = null, $type = 'form', $extraQuery = array()) |
||
84 | |||
85 | /** |
||
86 | * Fetch a translation form Loco. |
||
87 | * |
||
88 | * @param Message $message |
||
89 | */ |
||
90 | public function fetchTranslation(Message $message, $updateFs = false) |
||
116 | |||
117 | /** |
||
118 | * Update the translation in Loco. |
||
119 | * |
||
120 | * @param Message $message |
||
121 | */ |
||
122 | public function updateTranslation(Message $message) |
||
146 | |||
147 | /** |
||
148 | * If there is something wrong with the translation, please flag it. |
||
149 | * |
||
150 | * @param Message $message |
||
151 | * @param int $type 0: Fuzzy, 1: Incorrect, 2: Provisional, 3: Unapproved, 4: Incomplete |
||
152 | * |
||
153 | * @return bool |
||
154 | */ |
||
155 | public function flagTranslation(Message $message, $type = 0) |
||
173 | |||
174 | /** |
||
175 | * Create a new asset in Loco. |
||
176 | * |
||
177 | * @param Message $message |
||
178 | * |
||
179 | * @return bool |
||
180 | */ |
||
181 | public function createAsset(Message $message) |
||
225 | |||
226 | /** |
||
227 | * @param Message $message |
||
228 | * |
||
229 | * @return array |
||
230 | */ |
||
231 | protected function getProject(Message $message) |
||
246 | |||
247 | /** |
||
248 | * @param $project |
||
249 | * @param $messageId |
||
250 | * @param $domain |
||
251 | */ |
||
252 | protected function addTagToAsset($project, $messageId, $domain) |
||
257 | |||
258 | /** |
||
259 | * Download all the translations from Loco. This will replace all the local files. |
||
260 | * This is a quick method of getting all the latest translations and assets. |
||
261 | */ |
||
262 | public function downloadAllTranslations() |
||
276 | |||
277 | /** |
||
278 | * Upload all the translations from the symfony project into Loco. This will override |
||
279 | * every changed strings in loco |
||
280 | */ |
||
281 | View Code Duplication | public function uploadAllTranslations() |
|
293 | |||
294 | /** |
||
295 | * @param array $config |
||
296 | * @param $domain |
||
297 | * @param $useDomainAsFilter |
||
298 | */ |
||
299 | protected function doUploadDomains(array &$config, $domain, $useDomainAsFilter) |
||
327 | |||
328 | /** |
||
329 | * Synchronize all the translations with Loco. This will keep placeholders. This function is slower |
||
330 | * than just to download the translations. |
||
331 | */ |
||
332 | View Code Duplication | public function synchronizeAllTranslations() |
|
344 | |||
345 | /** |
||
346 | * @param array $config |
||
347 | * @param $domain |
||
348 | * @param $useDomainAsFilter |
||
349 | */ |
||
350 | protected function doSynchronizeDomain(array &$config, $domain, $useDomainAsFilter) |
||
379 | |||
380 | /** |
||
381 | * Flattens an nested array of translations. |
||
382 | * |
||
383 | * The scheme used is: |
||
384 | * 'key' => array('key2' => array('key3' => 'value')) |
||
385 | * Becomes: |
||
386 | * 'key.key2.key3' => 'value' |
||
387 | * |
||
388 | * This function takes an array by reference and will modify it |
||
389 | * |
||
390 | * @param array &$messages The array that will be flattened |
||
391 | * @param array $subnode Current subnode being parsed, used internally for recursive calls |
||
392 | * @param string $path Current path being parsed, used internally for recursive calls |
||
393 | */ |
||
394 | private function flatten(array &$messages, array $subnode = null, $path = null) |
||
411 | |||
412 | /** |
||
413 | * @param array $data |
||
414 | * @param array $config |
||
415 | * @param string $domain |
||
416 | * @param bool $useDomainAsFilter |
||
417 | */ |
||
418 | protected function getUrls(array &$data, array $config, $domain, $useDomainAsFilter) |
||
434 | |||
435 | /** |
||
436 | * @param array $config |
||
437 | * |
||
438 | * @return array |
||
439 | */ |
||
440 | private function getExportQueryParams($key) |
||
458 | } |
||
459 |
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.