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 Application 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 Application, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | final class Application implements LoggerAwareInterface |
||
35 | { |
||
36 | use LoggerAwareTrait; |
||
37 | |||
38 | /** |
||
39 | * Retrieve the logging instance |
||
40 | * |
||
41 | * @return \Psr\Log\LoggerInterface The logging instance |
||
42 | */ |
||
43 | 21 | private function getLogger() |
|
47 | |||
48 | /** |
||
49 | * List of controllers |
||
50 | * |
||
51 | * @var array |
||
52 | */ |
||
53 | private $controllers = null; |
||
54 | |||
55 | /** |
||
56 | * List of views |
||
57 | * |
||
58 | * @var array |
||
59 | */ |
||
60 | private $views = null; |
||
61 | |||
62 | /** |
||
63 | * List of view controls |
||
64 | * |
||
65 | * @var array |
||
66 | */ |
||
67 | private $viewControls = null; |
||
68 | |||
69 | /** |
||
70 | * The default controller |
||
71 | * |
||
72 | * @var string |
||
73 | */ |
||
74 | private $defaultController = 'Index'; |
||
75 | |||
76 | /** |
||
77 | * The default action |
||
78 | * |
||
79 | * @var string |
||
80 | */ |
||
81 | private $defaultAction = 'index'; |
||
82 | |||
83 | /** |
||
84 | * Singleton instance |
||
85 | * |
||
86 | * @var \Nkey\Caribu\Mvc\Application |
||
87 | */ |
||
88 | private static $instance = null; |
||
89 | |||
90 | /** |
||
91 | * Default headers to send to client |
||
92 | * |
||
93 | * @var array |
||
94 | */ |
||
95 | private $defaultHeaders = array(); |
||
96 | |||
97 | /** |
||
98 | * The client request headers to override |
||
99 | * |
||
100 | * @var array |
||
101 | */ |
||
102 | private $overridenClientHeaders = array(); |
||
103 | |||
104 | /** |
||
105 | * Additional css files to include in view |
||
106 | * |
||
107 | * @var array |
||
108 | */ |
||
109 | private $cssFiles = array(); |
||
110 | |||
111 | /** |
||
112 | * Additional javascript files to include in view |
||
113 | * |
||
114 | * @var array |
||
115 | */ |
||
116 | private $jsFiles = array(); |
||
117 | |||
118 | /** |
||
119 | * Router object |
||
120 | * @var AbstractRouter |
||
121 | */ |
||
122 | private $router; |
||
123 | |||
124 | /** |
||
125 | * Get application instance |
||
126 | * |
||
127 | * @return \Nkey\Caribu\Mvc\Application |
||
128 | */ |
||
129 | 29 | public static function getInstance() |
|
136 | |||
137 | /** |
||
138 | * Singleton constructor |
||
139 | */ |
||
140 | 1 | private function __construct() |
|
144 | |||
145 | /** |
||
146 | * Set up the default values |
||
147 | * |
||
148 | * @return Application Current application instance |
||
149 | */ |
||
150 | 29 | public function setUp() |
|
161 | |||
162 | /** |
||
163 | * Singleton instance |
||
164 | */ |
||
165 | 1 | public function __clone() |
|
169 | |||
170 | /** |
||
171 | * Init the application |
||
172 | * |
||
173 | * Register internally needed controller and view |
||
174 | */ |
||
175 | 29 | public function init() |
|
180 | |||
181 | /** |
||
182 | * Set the default controller and action |
||
183 | * |
||
184 | * @param string $defaultController |
||
185 | * The default controller name if nothing is provided by request |
||
186 | * @param string $defaultAction |
||
187 | * The default action name if nothing is provided by request |
||
188 | * @return Application Current application instance |
||
189 | */ |
||
190 | 29 | public function setDefaults($defaultController = 'Index', $defaultAction = 'index') |
|
197 | |||
198 | /** |
||
199 | * Register a new view |
||
200 | * |
||
201 | * @param string $view |
||
202 | * The view class |
||
203 | * @param int $order |
||
204 | * Override the default order given by view class |
||
205 | * @param string $applicationName |
||
206 | * The application name where the view will be available in |
||
207 | * |
||
208 | * @throws ViewException |
||
209 | * |
||
210 | * @return Application Current application instance |
||
211 | */ |
||
212 | 29 | public function registerView($view, $order = null, $applicationName = 'default') |
|
236 | |||
237 | /** |
||
238 | * Register a view control |
||
239 | * |
||
240 | * @param string $controlIdentifier |
||
241 | * The identifier under which the control will be registered |
||
242 | * @param string $controlClass |
||
243 | * The class of control |
||
244 | * |
||
245 | * @return Application Current application instance |
||
246 | */ |
||
247 | 4 | public function registerViewControl($controlIdentifier, $controlClass) |
|
252 | |||
253 | /** |
||
254 | * Unregister a given view |
||
255 | * |
||
256 | * @param string $view |
||
257 | * The view to unregister |
||
258 | * @param string $applicationName |
||
259 | * Optional application name where the view is registered |
||
260 | * |
||
261 | * @return Application Current application instance |
||
262 | */ |
||
263 | 1 | public function unregisterView($view, $order, $applicationName = 'default') |
|
270 | |||
271 | /** |
||
272 | * Get the best view for request |
||
273 | * |
||
274 | * @param Request $request |
||
275 | * The request to get best view for |
||
276 | * |
||
277 | * @return View The view best matched for the request |
||
278 | * |
||
279 | * @throws ViewException |
||
280 | */ |
||
281 | 21 | private function getViewBestMatch(Request $request, $applicationName) |
|
306 | |||
307 | /** |
||
308 | * Register a new controller class |
||
309 | * |
||
310 | * @param string $controller |
||
311 | * The full qualified name of controller class to register |
||
312 | * @param string $applicationName |
||
313 | * Optional name of application where controller will be registered in |
||
314 | * |
||
315 | * @return Application Current application instance |
||
316 | * |
||
317 | * @throws ControllerException |
||
318 | */ |
||
319 | 29 | public function registerController($controller, $applicationName = 'default') |
|
342 | |||
343 | /** |
||
344 | * Start the application |
||
345 | * |
||
346 | * @param string $applicationName |
||
347 | * Optional application name to service the request for |
||
348 | * @param array $serverVars |
||
349 | * The server variables provided by sapi |
||
350 | * @param Request $request |
||
351 | * Optional previous generated request object |
||
352 | * @param boolean $send |
||
353 | * Optional whether to send the output directly to client |
||
354 | * |
||
355 | * @throws ControllerException |
||
356 | * @throws InvalidUrlException |
||
357 | */ |
||
358 | 21 | public function serve($applicationName = 'default', $serverVars = array(), Request $request = null, $send = true) |
|
461 | |||
462 | /** |
||
463 | * Register a new Router |
||
464 | * |
||
465 | * @param AbstractRouter $router |
||
466 | * @return Application the current application instance |
||
467 | */ |
||
468 | 3 | public function registerRouter(AbstractRouter $router) |
|
474 | |||
475 | /** |
||
476 | * Enable session handling |
||
477 | * |
||
478 | * @return Application The current application instance |
||
479 | */ |
||
480 | public function enableSession() |
||
486 | |||
487 | /** |
||
488 | * Retrieve the default controller name |
||
489 | * |
||
490 | * @return string The name of default controller |
||
491 | */ |
||
492 | public function getDefaultController() |
||
496 | |||
497 | /** |
||
498 | * Retrieve the default action name |
||
499 | * |
||
500 | * @return string The name of default action |
||
501 | */ |
||
502 | public function getDefaultAction() |
||
506 | |||
507 | /** |
||
508 | * Add a new header to specific value. |
||
509 | * |
||
510 | * Existing header will be overriden. |
||
511 | * |
||
512 | * @param string $name |
||
513 | * The header identifier |
||
514 | * @param string $value |
||
515 | * The value to set |
||
516 | * |
||
517 | * @return Application The current application instance |
||
518 | */ |
||
519 | public function addHeader($name, $value) |
||
524 | |||
525 | /** |
||
526 | * Add a header to overide a client request header |
||
527 | * |
||
528 | * @param string $name |
||
529 | * The header name to override |
||
530 | * @param string $value |
||
531 | * The value to override |
||
532 | * |
||
533 | * @return Application The current application instance |
||
534 | */ |
||
535 | public function addOverridenClientHeader($name, $value) |
||
540 | |||
541 | /** |
||
542 | * Add an uri for an additional javascript file |
||
543 | * |
||
544 | * @param string $file |
||
545 | * |
||
546 | * @return Application the current application instance |
||
547 | */ |
||
548 | public function addJsFile($file) |
||
553 | |||
554 | /** |
||
555 | * Add an uri for an additional css file |
||
556 | * |
||
557 | * @param string $file |
||
558 | * |
||
559 | * @return Application the current application instance |
||
560 | */ |
||
561 | public function addCssFile($file) |
||
566 | } |
||
567 |
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.