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 ModuleManagerImpl 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 ModuleManagerImpl, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
43 | class ModuleManagerImpl implements ModuleManager |
||
44 | { |
||
45 | /** |
||
46 | * @var ProjectContext |
||
47 | */ |
||
48 | private $context; |
||
49 | |||
50 | /** |
||
51 | * @var string |
||
52 | */ |
||
53 | private $rootDir; |
||
54 | |||
55 | /** |
||
56 | * @var RootModuleFile |
||
57 | */ |
||
58 | private $rootModuleFile; |
||
59 | |||
60 | /** |
||
61 | * @var JsonStorage |
||
62 | */ |
||
63 | private $jsonStorage; |
||
64 | |||
65 | /** |
||
66 | * @var ModuleList |
||
67 | */ |
||
68 | private $modules; |
||
69 | |||
70 | /** |
||
71 | * @var DependencyFile[] |
||
72 | */ |
||
73 | private $dependencyFilesByInstallerName = array(); |
||
|
|||
74 | |||
75 | /** |
||
76 | * Loads the module repository for a given project. |
||
77 | * |
||
78 | * @param ProjectContext $context The project context. |
||
79 | * @param JsonStorage $jsonStorage The module file storage. |
||
80 | * |
||
81 | * @throws FileNotFoundException If the install path of a module not exist. |
||
82 | * @throws NoDirectoryException If the install path of a module points to a file. |
||
83 | * @throws InvalidConfigException If a configuration file contains invalid configuration. |
||
84 | * @throws NameConflictException If a module has the same name as another loaded module. |
||
85 | */ |
||
86 | 53 | public function __construct(ProjectContext $context, JsonStorage $jsonStorage) |
|
93 | |||
94 | /** |
||
95 | * {@inheritdoc} |
||
96 | */ |
||
97 | 12 | public function installModule($installPath, $name = null, $installerName = InstallInfo::DEFAULT_INSTALLER_NAME, $env = Environment::PROD) |
|
153 | |||
154 | /** |
||
155 | * {@inheritdoc} |
||
156 | */ |
||
157 | 8 | public function renameModule($name, $newName) |
|
175 | |||
176 | /** |
||
177 | * {@inheritdoc} |
||
178 | */ |
||
179 | 4 | public function removeModule($name) |
|
202 | |||
203 | /** |
||
204 | * {@inheritdoc} |
||
205 | */ |
||
206 | 3 | public function removeModules(Expression $expr) |
|
233 | |||
234 | /** |
||
235 | * {@inheritdoc} |
||
236 | */ |
||
237 | 1 | public function clearModules() |
|
241 | |||
242 | /** |
||
243 | * {@inheritdoc} |
||
244 | */ |
||
245 | 10 | public function getModule($name) |
|
253 | |||
254 | /** |
||
255 | * {@inheritdoc} |
||
256 | */ |
||
257 | 1 | public function getRootModule() |
|
263 | |||
264 | /** |
||
265 | * {@inheritdoc} |
||
266 | */ |
||
267 | 24 | public function getModules() |
|
274 | |||
275 | /** |
||
276 | * {@inheritdoc} |
||
277 | */ |
||
278 | 4 | public function findModules(Expression $expr) |
|
292 | |||
293 | /** |
||
294 | * {@inheritdoc} |
||
295 | */ |
||
296 | 11 | public function hasModule($name) |
|
304 | |||
305 | /** |
||
306 | * {@inheritdoc} |
||
307 | */ |
||
308 | 1 | View Code Duplication | public function hasModules(Expression $expr = null) |
324 | |||
325 | /** |
||
326 | * {@inheritdoc} |
||
327 | */ |
||
328 | 1 | public function getContext() |
|
332 | |||
333 | /** |
||
334 | * Loads all modules referenced by the install file. |
||
335 | * |
||
336 | * @throws FileNotFoundException If the install path of a module not exist. |
||
337 | * @throws NoDirectoryException If the install path of a module points to a |
||
338 | * file. |
||
339 | * @throws InvalidConfigException If a module is not configured correctly. |
||
340 | * @throws NameConflictException If a module has the same name as another |
||
341 | * loaded module. |
||
342 | */ |
||
343 | 52 | private function loadModules() |
|
352 | |||
353 | /** |
||
354 | * Loads a module for the given install info. |
||
355 | * |
||
356 | * @param InstallInfo $installInfo The install info. |
||
357 | * |
||
358 | * @return Module The module. |
||
359 | */ |
||
360 | 52 | private function loadModule(InstallInfo $installInfo) |
|
380 | |||
381 | /** |
||
382 | * Loads the module file for the module at the given install path. |
||
383 | * |
||
384 | * @param string $installPath The absolute install path of the module |
||
385 | * |
||
386 | * @return ModuleFile|null The loaded module file or `null` if none |
||
387 | * could be found. |
||
388 | */ |
||
389 | 52 | private function loadModuleFile($installPath) |
|
409 | |||
410 | 52 | private function assertModulesLoaded() |
|
416 | |||
417 | 6 | private function assertNoLoadErrors(Module $module) |
|
426 | |||
427 | 2 | private function renameRootModule(RootModule $module, $newName) |
|
444 | |||
445 | 2 | private function renameNonRootModule(Module $module, $newName) |
|
476 | } |
||
477 |
This check marks private properties in classes that are never used. Those properties can be removed.