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:
1 | <?php |
||
13 | abstract class AbstractPicoPlugin implements PicoPluginInterface |
||
14 | { |
||
15 | /** |
||
16 | * Current instance of Pico |
||
17 | * |
||
18 | * @see PicoPluginInterface::getPico() |
||
19 | * @var Pico |
||
20 | */ |
||
21 | private $pico; |
||
22 | |||
23 | /** |
||
24 | * Boolean indicating if this plugin is enabled (true) or disabled (false) |
||
25 | * |
||
26 | * @see PicoPluginInterface::isEnabled() |
||
27 | * @see PicoPluginInterface::setEnabled() |
||
28 | * @var boolean |
||
29 | */ |
||
30 | protected $enabled = true; |
||
31 | |||
32 | /** |
||
33 | * Boolean indicating if this plugin was ever enabled/disabled manually |
||
34 | * |
||
35 | * @see PicoPluginInterface::isStatusChanged() |
||
36 | * @var boolean |
||
37 | */ |
||
38 | protected $statusChanged = false; |
||
39 | |||
40 | /** |
||
41 | * List of plugins which this plugin depends on |
||
42 | * |
||
43 | * @see AbstractPicoPlugin::checkDependencies() |
||
44 | * @see PicoPluginInterface::getDependencies() |
||
45 | * @var string[] |
||
46 | */ |
||
47 | protected $dependsOn = array(); |
||
48 | |||
49 | /** |
||
50 | * List of plugin which depend on this plugin |
||
51 | * |
||
52 | * @see AbstractPicoPlugin::checkDependants() |
||
53 | * @see PicoPluginInterface::getDependants() |
||
54 | * @var object[] |
||
55 | */ |
||
56 | private $dependants; |
||
57 | |||
58 | /** |
||
59 | * @see PicoPluginInterface::__construct() |
||
60 | */ |
||
61 | public function __construct(Pico $pico) |
||
65 | |||
66 | /** |
||
67 | * @see PicoPluginInterface::handleEvent() |
||
68 | */ |
||
69 | public function handleEvent($eventName, array $params) |
||
70 | { |
||
71 | // plugins can be enabled/disabled using the config |
||
72 | if ($eventName === 'onConfigLoaded') { |
||
73 | $pluginEnabled = $this->getConfig(get_called_class() . '.enabled'); |
||
74 | if ($pluginEnabled !== null) { |
||
75 | $this->setEnabled($pluginEnabled); |
||
76 | } else { |
||
77 | $pluginConfig = $this->getConfig(get_called_class()); |
||
78 | if (is_array($pluginConfig) && isset($pluginConfig['enabled'])) { |
||
79 | $this->setEnabled($pluginConfig['enabled']); |
||
80 | } |
||
81 | } |
||
82 | } |
||
83 | |||
84 | if ($this->isEnabled() || ($eventName === 'onPluginsLoaded')) { |
||
85 | if (method_exists($this, $eventName)) { |
||
86 | call_user_func_array(array($this, $eventName), $params); |
||
87 | } |
||
88 | } |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * @see PicoPluginInterface::setEnabled() |
||
93 | */ |
||
94 | public function setEnabled($enabled, $recursive = true, $auto = false) |
||
95 | { |
||
96 | $this->statusChanged = (!$this->statusChanged) ? !$auto : true; |
||
97 | $this->enabled = (bool) $enabled; |
||
98 | |||
99 | if ($enabled) { |
||
100 | $this->checkDependencies($recursive); |
||
101 | } else { |
||
102 | $this->checkDependants($recursive); |
||
103 | } |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * @see PicoPluginInterface::isEnabled() |
||
108 | */ |
||
109 | public function isEnabled() |
||
113 | |||
114 | /** |
||
115 | * @see PicoPluginInterface::isStatusChanged() |
||
116 | */ |
||
117 | public function isStatusChanged() |
||
121 | |||
122 | /** |
||
123 | * @see PicoPluginInterface::getPico() |
||
124 | */ |
||
125 | public function getPico() |
||
129 | |||
130 | /** |
||
131 | * Passes all not satisfiable method calls to Pico |
||
132 | * |
||
133 | * @see Pico |
||
134 | * @param string $methodName name of the method to call |
||
135 | * @param array $params parameters to pass |
||
136 | * @return mixed return value of the called method |
||
137 | */ |
||
138 | public function __call($methodName, array $params) |
||
139 | { |
||
140 | if (method_exists($this->getPico(), $methodName)) { |
||
141 | return call_user_func_array(array($this->getPico(), $methodName), $params); |
||
142 | } |
||
143 | |||
144 | throw new BadMethodCallException( |
||
145 | 'Call to undefined method ' . get_class($this->getPico()) . '::' . $methodName . '() ' |
||
146 | . 'through ' . get_called_class() . '::__call()' |
||
147 | ); |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Enables all plugins which this plugin depends on |
||
152 | * |
||
153 | * @see PicoPluginInterface::getDependencies() |
||
154 | * @param boolean $recursive enable required plugins automatically |
||
155 | * @return void |
||
156 | * @throws RuntimeException thrown when a dependency fails |
||
157 | */ |
||
158 | protected function checkDependencies($recursive) |
||
159 | { |
||
160 | foreach ($this->getDependencies() as $pluginName) { |
||
161 | try { |
||
162 | $plugin = $this->getPlugin($pluginName); |
||
163 | } catch (RuntimeException $e) { |
||
164 | throw new RuntimeException( |
||
165 | "Unable to enable plugin '" . get_called_class() . "':" |
||
166 | . "Required plugin '" . $pluginName . "' not found" |
||
167 | ); |
||
168 | } |
||
169 | |||
170 | // plugins which don't implement PicoPluginInterface are always enabled |
||
171 | if (is_a($plugin, 'PicoPluginInterface') && !$plugin->isEnabled()) { |
||
172 | if ($recursive) { |
||
173 | View Code Duplication | if (!$plugin->isStatusChanged()) { |
|
|
|||
174 | $plugin->setEnabled(true, true, true); |
||
175 | } else { |
||
176 | throw new RuntimeException( |
||
177 | "Unable to enable plugin '" . get_called_class() . "':" |
||
178 | . "Required plugin '" . $pluginName . "' was disabled manually" |
||
179 | ); |
||
180 | } |
||
181 | } else { |
||
182 | throw new RuntimeException( |
||
183 | "Unable to enable plugin '" . get_called_class() . "':" |
||
184 | . "Required plugin '" . $pluginName . "' is disabled" |
||
185 | ); |
||
186 | } |
||
187 | } |
||
188 | } |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * @see PicoPluginInterface::getDependencies() |
||
193 | */ |
||
194 | public function getDependencies() |
||
198 | |||
199 | /** |
||
200 | * Disables all plugins which depend on this plugin |
||
201 | * |
||
202 | * @see PicoPluginInterface::getDependants() |
||
203 | * @param boolean $recursive disabled dependant plugins automatically |
||
204 | * @return void |
||
205 | * @throws RuntimeException thrown when a dependency fails |
||
206 | */ |
||
207 | protected function checkDependants($recursive) |
||
234 | |||
235 | /** |
||
236 | * @see PicoPluginInterface::getDependants() |
||
237 | */ |
||
238 | public function getDependants() |
||
255 | } |
||
256 |
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.