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 PluginPackage 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 PluginPackage, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
35 | class PluginPackage extends BasePackage |
||
36 | { |
||
37 | |||
38 | /** |
||
39 | * Plugin information. |
||
40 | * |
||
41 | * @var array |
||
42 | */ |
||
43 | protected $_info = []; |
||
44 | |||
45 | /** |
||
46 | * Permissions tree for this plugin. |
||
47 | * |
||
48 | * @var null|array |
||
49 | */ |
||
50 | protected $_permissions = null; |
||
51 | |||
52 | /** |
||
53 | * {@inheritDoc} |
||
54 | * |
||
55 | * @return string CamelizedName plugin name |
||
56 | */ |
||
57 | public function name() |
||
61 | |||
62 | /** |
||
63 | * Gets plugin's permissions tree. |
||
64 | * |
||
65 | * ### Output example: |
||
66 | * |
||
67 | * ```php |
||
68 | * [ |
||
69 | * 'administrator' => [ |
||
70 | * 'Plugin/Controller/action', |
||
71 | * 'Plugin/Controller/action2', |
||
72 | * ... |
||
73 | * ], |
||
74 | * 'role-machine-name' => [ |
||
75 | * 'Plugin/Controller/anotherAction', |
||
76 | * 'Plugin/Controller/anotherAction2', |
||
77 | * ], |
||
78 | * ... |
||
79 | * ] |
||
80 | * ``` |
||
81 | * |
||
82 | * @return array Permissions index by role's machine-name |
||
83 | */ |
||
84 | public function permissions() |
||
116 | |||
117 | /** |
||
118 | * Magic getter to access properties that exists on info(). |
||
119 | * |
||
120 | * @param string $property Name of the property to access |
||
121 | * @return mixed |
||
122 | */ |
||
123 | public function &__get($property) |
||
127 | |||
128 | /** |
||
129 | * Gets information for this plugin. |
||
130 | * |
||
131 | * When `$full` is set to true some additional keys will be repent in the |
||
132 | * resulting array: |
||
133 | * |
||
134 | * - `settings`: Plugin's settings info fetched from DB. |
||
135 | * - `composer`: Composer JSON information, converted to an array. |
||
136 | * - `permissions`: Permissions tree for this plugin, see `PluginPackage::permissions()` |
||
137 | * |
||
138 | * ### Example: |
||
139 | * |
||
140 | * Reading full information: |
||
141 | * |
||
142 | * ```php |
||
143 | * $plugin->info(); |
||
144 | * |
||
145 | * // returns an array as follow: |
||
146 | * [ |
||
147 | * 'name' => 'User, |
||
148 | * 'isTheme' => false, |
||
149 | * 'hasHelp' => true, |
||
150 | * 'hasSettings' => false, |
||
151 | * 'eventListeners' => [ ... ], |
||
152 | * 'status' => 1, |
||
153 | * 'path' => '/path/to/plugin', |
||
154 | * 'settings' => [ ... ], // only when $full = true |
||
155 | * 'composer' => [ ... ], // only when $full = true |
||
156 | * 'permissions' => [ ... ], // only when $full = true |
||
157 | * ] |
||
158 | * ``` |
||
159 | * |
||
160 | * Additionally the first argument, $key, can be used to get an specific value |
||
161 | * using a dot syntax path: |
||
162 | * |
||
163 | * ```php |
||
164 | * $plugin->info('isTheme'); |
||
165 | * $plugin->info('settings.some_key'); |
||
166 | * ``` |
||
167 | * |
||
168 | * If the given path is not found NULL will be returned |
||
169 | * |
||
170 | * @param string $key Optional path to read from the resulting array |
||
171 | * @return mixed Plugin information as an array if no key is given, or the |
||
172 | * requested value if a valid $key was provided, or NULL if $key path is not |
||
173 | * found |
||
174 | */ |
||
175 | public function &info($key = null) |
||
205 | |||
206 | /** |
||
207 | * Gets info value for the given key. |
||
208 | * |
||
209 | * @param string|array $key The path to read. String using a dot-syntax, or an |
||
210 | * array result of exploding by `.` symbol |
||
211 | * @return mixed |
||
212 | */ |
||
213 | protected function &_getKey($key) |
||
256 | |||
257 | /** |
||
258 | * {@inheritDoc} |
||
259 | */ |
||
260 | public function composer($full = false) |
||
272 | |||
273 | /** |
||
274 | * Gets settings from DB for this plugin. Or reads a single settings key value. |
||
275 | * |
||
276 | * @param string $key Which setting to read, the entire settings will be |
||
277 | * returned if no key is provided |
||
278 | * @return mixed Array of settings if $key was not provided, or the requested |
||
279 | * value for the given $key (null of key does not exists) |
||
280 | */ |
||
281 | public function settings($key = null) |
||
316 | |||
317 | /** |
||
318 | * Gets a collection list of plugin that depends on this plugin. |
||
319 | * |
||
320 | * @return \Cake\Collection\Collection List of plugins |
||
321 | */ |
||
322 | public function requiredBy() |
||
352 | |||
353 | /** |
||
354 | * {@inheritDoc} |
||
355 | * |
||
356 | * It will look for plugin's version in the following places: |
||
357 | * |
||
358 | * - Plugin's "composer.json" file. |
||
359 | * - Plugin's "VERSION.txt" file (or any file matching "/version?(\.\w+)/i"). |
||
360 | * - Composer's "installed.json" file. |
||
361 | * |
||
362 | * If not found `dev-master` is returned by default. If plugin is not registered |
||
363 | * on QuickAppsCMS (not installed) an empty string will be returned instead. |
||
364 | * |
||
365 | * @return string Plugin's version, for instance `1.2.x-dev` |
||
366 | */ |
||
367 | public function version() |
||
418 | |||
419 | /** |
||
420 | * Returns an array that can be used to describe the internal state of this |
||
421 | * object. |
||
422 | * |
||
423 | * @return array |
||
424 | */ |
||
425 | public function __debugInfo() |
||
429 | } |
||
430 |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: