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 AppConfig 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 AppConfig, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class AppConfig extends AbstractConfig |
||
29 | { |
||
30 | /** |
||
31 | * The application's timezone. |
||
32 | * |
||
33 | * @var string|null |
||
34 | */ |
||
35 | private $timezone; |
||
36 | |||
37 | /** |
||
38 | * The application's name. |
||
39 | * |
||
40 | * For internal usage. |
||
41 | * |
||
42 | * @var string|null |
||
43 | */ |
||
44 | private $projectName; |
||
45 | |||
46 | /** |
||
47 | * The base path for the Charcoal installation. |
||
48 | * |
||
49 | * @var string|null |
||
50 | */ |
||
51 | private $basePath; |
||
52 | |||
53 | /** |
||
54 | * The base URL (public) for the Charcoal installation. |
||
55 | * |
||
56 | * @var UriInterface|null |
||
57 | */ |
||
58 | private $baseUrl; |
||
59 | |||
60 | /** |
||
61 | * The path to the public / web directory. |
||
62 | * |
||
63 | * @var string|null |
||
64 | */ |
||
65 | private $publicPath; |
||
66 | |||
67 | /** |
||
68 | * The path to the storage directory. |
||
69 | * |
||
70 | * @var string|null |
||
71 | */ |
||
72 | private $storagePath; |
||
73 | |||
74 | /** |
||
75 | * Whether the debug mode is enabled (TRUE) or not (FALSE). |
||
76 | * |
||
77 | * @var boolean |
||
78 | */ |
||
79 | private $devMode = false; |
||
80 | |||
81 | /** |
||
82 | * The application's routes. |
||
83 | * |
||
84 | * @var array |
||
85 | */ |
||
86 | private $routes = []; |
||
87 | |||
88 | /** |
||
89 | * The application's dynamic routes. |
||
90 | * |
||
91 | * @var array |
||
92 | */ |
||
93 | private $routables = []; |
||
94 | |||
95 | /** |
||
96 | * The application's handlers. |
||
97 | * |
||
98 | * @var array |
||
99 | */ |
||
100 | private $handlers = []; |
||
101 | |||
102 | /** |
||
103 | * The application's modules. |
||
104 | * |
||
105 | * @var array |
||
106 | */ |
||
107 | private $modules = []; |
||
108 | |||
109 | /** |
||
110 | * The application's caching configset. |
||
111 | * |
||
112 | * @var CacheConfig |
||
113 | */ |
||
114 | private $cache; |
||
115 | |||
116 | /** |
||
117 | * The application's logging configset. |
||
118 | * |
||
119 | * @var LoggerConfig |
||
120 | */ |
||
121 | private $logger; |
||
122 | |||
123 | /** |
||
124 | * The application's view/rendering configset. |
||
125 | * |
||
126 | * @var ViewConfig |
||
127 | */ |
||
128 | protected $view; |
||
129 | |||
130 | /** |
||
131 | * The application's database configsets. |
||
132 | * |
||
133 | * @var array |
||
134 | */ |
||
135 | private $databases = []; |
||
136 | |||
137 | /** |
||
138 | * The application's default database configset. |
||
139 | * |
||
140 | * @var string |
||
141 | */ |
||
142 | private $defaultDatabase; |
||
143 | |||
144 | /** |
||
145 | * The application's filesystem configset. |
||
146 | * |
||
147 | * @var FilesystemConfig |
||
148 | */ |
||
149 | private $filesystem; |
||
150 | |||
151 | /** |
||
152 | * Default app-config values. |
||
153 | * |
||
154 | * @return array |
||
155 | */ |
||
156 | public function defaults() |
||
179 | |||
180 | /** |
||
181 | * Set the application's absolute root path. |
||
182 | * |
||
183 | * Resolves symlinks with realpath() and ensure trailing slash. |
||
184 | * |
||
185 | * @param string $path The absolute path to the application's root directory. |
||
186 | * @throws InvalidArgumentException If the argument is not a string. |
||
187 | * @return AppConfig Chainable |
||
188 | */ |
||
189 | public function setBasePath($path) |
||
207 | |||
208 | /** |
||
209 | * Retrieve the application's absolute root path. |
||
210 | * |
||
211 | * @return string The absolute path to the application's root directory. |
||
212 | */ |
||
213 | public function basePath() |
||
217 | |||
218 | /** |
||
219 | * Set the application's absolute path to the public web directory. |
||
220 | * |
||
221 | * @param string $path The path to the application's public directory. |
||
222 | * @throws InvalidArgumentException If the argument is not a string. |
||
223 | * @return AppConfig Chainable |
||
224 | */ |
||
225 | View Code Duplication | public function setPublicPath($path) |
|
243 | |||
244 | /** |
||
245 | * Retrieve the application's absolute path to the public web directory. |
||
246 | * |
||
247 | * @return string The absolute path to the application's public directory. |
||
248 | */ |
||
249 | public function publicPath() |
||
257 | |||
258 | /** |
||
259 | * Set the application's absolute path to the storage directory. |
||
260 | * |
||
261 | * @param string|null $path The path to the application's storage directory. |
||
262 | * @throws InvalidArgumentException If the argument is not a string. |
||
263 | * @return $this |
||
264 | */ |
||
265 | View Code Duplication | public function setStoragePath($path) |
|
283 | |||
284 | /** |
||
285 | * Get the path to the storage directory. |
||
286 | * |
||
287 | * Note that the storage space is outside of the public access. |
||
288 | * |
||
289 | * @return string |
||
290 | */ |
||
291 | public function storagePath() |
||
299 | |||
300 | /** |
||
301 | * Set the application's fully qualified base URL to the public web directory. |
||
302 | * |
||
303 | * @param UriInterface|string $uri The base URI to the application's web directory. |
||
304 | * @return AppConfig Chainable |
||
305 | */ |
||
306 | public function setBaseUrl($uri) |
||
312 | |||
313 | /** |
||
314 | * Retrieve the application's fully qualified base URL to the public web directory. |
||
315 | * |
||
316 | * @return UriInterface|null The base URI to the application's web directory. |
||
317 | */ |
||
318 | public function baseUrl() |
||
322 | |||
323 | /** |
||
324 | * Set the application's default timezone. |
||
325 | * |
||
326 | * @param string $timezone The timezone string. |
||
327 | * @throws InvalidArgumentException If the argument is not a string. |
||
328 | * @return AppConfig Chainable |
||
329 | */ |
||
330 | public function setTimezone($timezone) |
||
340 | |||
341 | /** |
||
342 | * Retrieve the application's default timezone. |
||
343 | * |
||
344 | * Will be used by the PHP date and date-time functions. |
||
345 | * |
||
346 | * @return string |
||
347 | */ |
||
348 | public function timezone() |
||
356 | |||
357 | /** |
||
358 | * Sets the project name. |
||
359 | * |
||
360 | * @param string|null $projectName The project name. |
||
361 | * @throws InvalidArgumentException If the project argument is not a string (or null). |
||
362 | * @return AppConfig Chainable |
||
363 | */ |
||
364 | public function setProjectName($projectName) |
||
378 | |||
379 | /** |
||
380 | * @return string|null |
||
381 | */ |
||
382 | public function projectName() |
||
392 | |||
393 | /** |
||
394 | * @param boolean $devMode The "dev mode" flag. |
||
395 | * @return AppConfig Chainable |
||
396 | */ |
||
397 | public function setDevMode($devMode) |
||
402 | |||
403 | /** |
||
404 | * @return boolean |
||
405 | */ |
||
406 | public function devMode() |
||
410 | |||
411 | /** |
||
412 | * @param array $view The view configuration structure to set. |
||
413 | * @return AppConfig Chainable |
||
414 | */ |
||
415 | public function setView(array $view) |
||
425 | |||
426 | /** |
||
427 | * Parse the application's route configuration. |
||
428 | * |
||
429 | * @see \Charcoal\Admin\Config::setRoutes() For a similar implementation. |
||
430 | * @param array $routes The route configuration structure to set. |
||
431 | * @return AppConfig Chainable |
||
432 | */ |
||
433 | public function setRoutes(array $routes) |
||
450 | |||
451 | /** |
||
452 | * @return array |
||
453 | */ |
||
454 | public function routes() |
||
458 | |||
459 | /** |
||
460 | * @param array $routables The routable configuration structure to set. |
||
461 | * @return AppConfig Chainable |
||
462 | */ |
||
463 | public function setRoutables(array $routables) |
||
468 | |||
469 | /** |
||
470 | * @return array |
||
471 | */ |
||
472 | public function routables() |
||
476 | |||
477 | /** |
||
478 | * Define custom response and error handlers. |
||
479 | * |
||
480 | * Slim provides five standard handlers: |
||
481 | * - "foundHandler" |
||
482 | * - "notFoundHandler" |
||
483 | * - "notAllowedHandler" |
||
484 | * - "errorHandler" |
||
485 | * - "phpErrorHandler" |
||
486 | * |
||
487 | * @param array $handlers The handlers configuration structure to set. |
||
488 | * @return AppConfig Chainable |
||
489 | */ |
||
490 | public function setHandlers(array $handlers) |
||
495 | |||
496 | /** |
||
497 | * @return array |
||
498 | */ |
||
499 | public function handlers() |
||
503 | |||
504 | /** |
||
505 | * Set the configuration modules. |
||
506 | * |
||
507 | * The modules are defined in a `key`=>`\Charcoal\App\Module\ModuleConfig` structure. |
||
508 | * |
||
509 | * @param array $modules The module configuration structure to set. |
||
510 | * @return AppConfig Chainable |
||
511 | */ |
||
512 | public function setModules(array $modules) |
||
517 | |||
518 | /** |
||
519 | * @return array |
||
520 | */ |
||
521 | public function modules() |
||
525 | |||
526 | /** |
||
527 | * @param array|CacheConfig $cache The application global cache config. |
||
528 | * @throws InvalidArgumentException If the argument is not an array or a config. |
||
529 | * @return AppConfig Chainable |
||
530 | */ |
||
531 | View Code Duplication | public function setCache($cache) |
|
545 | |||
546 | /** |
||
547 | * Get the application's global `CacheConfig`. |
||
548 | * |
||
549 | * @return CacheConfig |
||
550 | */ |
||
551 | public function cache() |
||
555 | |||
556 | /** |
||
557 | * @param array|LoggerConfig $logger The global logger config. |
||
558 | * @throws InvalidArgumentException If the argument is not an array or a config. |
||
559 | * @return AppConfig Chainable |
||
560 | */ |
||
561 | View Code Duplication | public function setLogger($logger) |
|
575 | |||
576 | /** |
||
577 | * Get the application's global `LoggerConfig` |
||
578 | * |
||
579 | * @return LoggerConfig |
||
580 | */ |
||
581 | public function logger() |
||
585 | |||
586 | /** |
||
587 | * @param array $databases The avaiable databases config. |
||
588 | * @return Config Chainable |
||
589 | */ |
||
590 | public function setDatabases(array $databases) |
||
595 | |||
596 | /** |
||
597 | * @throws Exception If trying to access this method and no databases were set. |
||
598 | * @return array |
||
599 | */ |
||
600 | public function databases() |
||
609 | |||
610 | /** |
||
611 | * @param string $ident The ident of the database to return the configuration of. |
||
612 | * @throws InvalidArgumentException If the ident argument is not a string. |
||
613 | * @throws Exception If trying to access an invalid database. |
||
614 | * @return array |
||
615 | */ |
||
616 | public function databaseConfig($ident) |
||
631 | |||
632 | /** |
||
633 | * @param string $defaultDatabase The default database ident. |
||
634 | * @throws InvalidArgumentException If the argument is not a string. |
||
635 | * @return AppConfig Chainable |
||
636 | */ |
||
637 | public function setDefaultDatabase($defaultDatabase) |
||
647 | |||
648 | /** |
||
649 | * @param string $ident The database ident. |
||
650 | * @param array $config The database options. |
||
651 | * @throws InvalidArgumentException If the arguments are invalid. |
||
652 | * @return AppConfig Chainable |
||
653 | */ |
||
654 | public function addDatabase($ident, array $config) |
||
668 | |||
669 | /** |
||
670 | * @throws Exception If trying to access this method before a setter. |
||
671 | * @return mixed |
||
672 | */ |
||
673 | public function defaultDatabase() |
||
682 | |||
683 | /** |
||
684 | * @param array|FilesystemConfig $filesystem The application global cache config. |
||
685 | * @throws InvalidArgumentException If the argument is not an array or a config. |
||
686 | * @return AppConfig Chainable |
||
687 | */ |
||
688 | View Code Duplication | public function setFilesystem($filesystem) |
|
702 | |||
703 | /** |
||
704 | * Get the application's global `FilesystemConfig` |
||
705 | * |
||
706 | * @return FilesystemConfig |
||
707 | */ |
||
708 | public function filesystem() |
||
712 | } |
||
713 |
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.