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 AbstractProxyHelper 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 AbstractProxyHelper, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | class AbstractProxyHelper extends AbstractHelper |
||
26 | { |
||
27 | /** |
||
28 | * View helper namespace |
||
29 | * |
||
30 | * @var string |
||
31 | */ |
||
32 | const NS = 'UIComponents\View\Helper\Components'; |
||
33 | |||
34 | /** |
||
35 | * Default proxy to use in {@link render()} |
||
36 | * |
||
37 | * @var string |
||
38 | */ |
||
39 | protected $defaultProxy = 'element'; |
||
40 | |||
41 | /** |
||
42 | * Indicates whether or not a given helper has been injected |
||
43 | * |
||
44 | * @var array |
||
45 | */ |
||
46 | protected $injected = []; |
||
47 | |||
48 | /** |
||
49 | * Whether ACL should be injected when proxying |
||
50 | * |
||
51 | * @var bool |
||
52 | */ |
||
53 | protected $injectAcl = true; |
||
54 | |||
55 | /** |
||
56 | * Whether container should be injected when proxying |
||
57 | * |
||
58 | * @var bool |
||
59 | */ |
||
60 | protected $injectContainer = true; |
||
61 | |||
62 | /** |
||
63 | * Whether translator should be injected when proxying |
||
64 | * |
||
65 | * @var bool |
||
66 | */ |
||
67 | protected $injectTranslator = true; |
||
68 | |||
69 | /** |
||
70 | * @var Navigation\PluginManager |
||
71 | */ |
||
72 | protected $plugins; |
||
73 | |||
74 | /** |
||
75 | * AbstractContainer to operate on by default |
||
76 | * |
||
77 | * @var Navigation\AbstractContainer|Navigation\Navigation|\Zend\Navigation\AbstractContainer |
||
78 | */ |
||
79 | protected $container; |
||
80 | |||
81 | /** |
||
82 | * Helper entry point |
||
83 | * |
||
84 | * @param array $options option to operate on |
||
85 | * @return Components |
||
86 | */ |
||
87 | View Code Duplication | public function __invoke($options = array()) |
|
95 | |||
96 | /** |
||
97 | * Magic overload: Proxy to other navigation helpers or the container |
||
98 | * |
||
99 | * Examples of usage from a view script or layout: |
||
100 | * <code> |
||
101 | * echo $this->Components()->Widget(...); |
||
102 | * </code> |
||
103 | * |
||
104 | * @param string $method helper name or method name in container |
||
105 | * @param array $arguments [optional] arguments to pass |
||
106 | * @throws \Zend\View\Exception\ExceptionInterface if proxying to a helper, and the |
||
107 | * helper is not an instance of the |
||
108 | * interface specified in |
||
109 | * {@link findHelper()} |
||
110 | * @throws \Zend\View\Exception\ExceptionInterface if method does not exist in container |
||
111 | * @return mixed returns what the proxied call returns |
||
112 | */ |
||
113 | public function __call($method, array $arguments = []) |
||
133 | |||
134 | /** |
||
135 | * Sets navigation container the helper operates on by default |
||
136 | * |
||
137 | * Implements {@link HelperInterface::setContainer()}. |
||
138 | * |
||
139 | * @param string|Navigation\AbstractContainer $container Default is null, meaning container will be reset. |
||
140 | * @return AbstractHelper |
||
141 | */ |
||
142 | public function setContainer($container = null) |
||
149 | |||
150 | /** |
||
151 | * Returns the navigation container helper operates on by default |
||
152 | * |
||
153 | * Implements {@link HelperInterface::getContainer()}. |
||
154 | * |
||
155 | * If no container is set, a new container will be instantiated and |
||
156 | * stored in the helper. |
||
157 | * |
||
158 | * @return Navigation\AbstractContainer|\Zend\Navigation\AbstractContainer navigation container |
||
159 | */ |
||
160 | public function getContainer() |
||
168 | |||
169 | /** |
||
170 | * Renders helper |
||
171 | * |
||
172 | * @param AbstractContainer $container |
||
173 | * @return string |
||
174 | * @throws Exception\RuntimeException |
||
175 | */ |
||
176 | public function render($container = null) |
||
181 | |||
182 | /** |
||
183 | * Returns the helper matching $proxy |
||
184 | * |
||
185 | * The helper must implement the interface |
||
186 | * {@link UIComponents\View\Helper\Components\HelperInterface}. |
||
187 | * |
||
188 | * @param string $proxy helper name |
||
189 | * @param bool $strict [optional] whether exceptions should be |
||
190 | * thrown if something goes |
||
191 | * wrong. Default is true. |
||
192 | * @throws Exception\RuntimeException if $strict is true and helper cannot be found |
||
193 | * @return boolean|\UIComponents\View\Helper\Components\HelperInterface helper instance |
||
194 | */ |
||
195 | public function findHelper($proxy, $strict = true) |
||
228 | |||
229 | /** |
||
230 | * Injects container, ACL, and translator to the given $helper if this |
||
231 | * helper is configured to do so |
||
232 | * |
||
233 | * @param \Zend\View\Helper\AbstractHelper $helper helper instance |
||
234 | * @return void |
||
235 | */ |
||
236 | protected function inject(\Zend\View\Helper\AbstractHelper $helper) |
||
262 | |||
263 | /** |
||
264 | * Sets the default proxy to use in {@link render()} |
||
265 | * |
||
266 | * @param string $proxy default proxy |
||
267 | * @return Bootstrap |
||
268 | */ |
||
269 | public function setDefaultProxy($proxy) |
||
274 | |||
275 | /** |
||
276 | * Returns the default proxy to use in {@link render()} |
||
277 | * |
||
278 | * @return string |
||
279 | */ |
||
280 | public function getDefaultProxy() |
||
284 | |||
285 | /** |
||
286 | * Sets whether container should be injected when proxying |
||
287 | * |
||
288 | * @param bool $injectContainer |
||
289 | * @return Bootstrap |
||
290 | */ |
||
291 | public function setInjectContainer($injectContainer = true) |
||
296 | |||
297 | /** |
||
298 | * Returns whether container should be injected when proxying |
||
299 | * |
||
300 | * @return bool |
||
301 | */ |
||
302 | public function getInjectContainer() |
||
306 | |||
307 | /** |
||
308 | * Sets whether ACL should be injected when proxying |
||
309 | * |
||
310 | * @param bool $injectAcl |
||
311 | * @return NavigBootstrapation |
||
312 | */ |
||
313 | public function setInjectAcl($injectAcl = true) |
||
318 | |||
319 | /** |
||
320 | * Returns whether ACL should be injected when proxying |
||
321 | * |
||
322 | * @return bool |
||
323 | */ |
||
324 | public function getInjectAcl() |
||
328 | |||
329 | /** |
||
330 | * Sets whether translator should be injected when proxying |
||
331 | * |
||
332 | * @param bool $injectTranslator |
||
333 | * @return Bootstrap |
||
334 | */ |
||
335 | public function setInjectTranslator($injectTranslator = true) |
||
340 | |||
341 | /** |
||
342 | * Returns whether translator should be injected when proxying |
||
343 | * |
||
344 | * @return bool |
||
345 | */ |
||
346 | public function getInjectTranslator() |
||
350 | |||
351 | /** |
||
352 | * Set manager for retrieving navigation helpers |
||
353 | * |
||
354 | * @param Components\PluginManager $plugins |
||
355 | * @return Components |
||
356 | */ |
||
357 | public function setPluginManager(AbstractPluginManager $plugins) |
||
367 | |||
368 | /** |
||
369 | * Retrieve plugin loader for navigation helpers |
||
370 | * |
||
371 | * Lazy-loads an instance of Navigation\HelperLoader if none currently |
||
372 | * registered. |
||
373 | * |
||
374 | * @return Components\PluginManager |
||
375 | */ |
||
376 | public function getPluginManager() |
||
384 | |||
385 | /** |
||
386 | * Set the View object |
||
387 | * |
||
388 | * @param Renderer $view |
||
389 | * @return self |
||
390 | */ |
||
391 | public function setView(Renderer $view) |
||
399 | } |
||
400 |
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.