Complex classes like helper_plugin_extension_extension 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 helper_plugin_extension_extension, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class helper_plugin_extension_extension extends DokuWiki_Plugin { |
||
17 | private $id; |
||
18 | private $base; |
||
19 | private $is_template = false; |
||
20 | private $localInfo; |
||
21 | private $remoteInfo; |
||
22 | private $managerData; |
||
23 | /** @var helper_plugin_extension_repository $repository */ |
||
24 | private $repository = null; |
||
25 | |||
26 | /** @var array list of temporary directories */ |
||
27 | private $temporary = array(); |
||
28 | |||
29 | /** |
||
30 | * Destructor |
||
31 | * |
||
32 | * deletes any dangling temporary directories |
||
33 | */ |
||
34 | public function __destruct() { |
||
39 | |||
40 | /** |
||
41 | * @return bool false, this component is not a singleton |
||
42 | */ |
||
43 | public function isSingleton() { |
||
46 | |||
47 | /** |
||
48 | * Set the name of the extension this instance shall represents, triggers loading the local and remote data |
||
49 | * |
||
50 | * @param string $id The id of the extension (prefixed with template: for templates) |
||
51 | * @return bool If some (local or remote) data was found |
||
52 | */ |
||
53 | public function setExtension($id) { |
||
81 | |||
82 | /** |
||
83 | * If the extension is installed locally |
||
84 | * |
||
85 | * @return bool If the extension is installed locally |
||
86 | */ |
||
87 | public function isInstalled() { |
||
90 | |||
91 | /** |
||
92 | * If the extension is under git control |
||
93 | * |
||
94 | * @return bool |
||
95 | */ |
||
96 | public function isGitControlled() { |
||
100 | |||
101 | /** |
||
102 | * If the extension is bundled |
||
103 | * |
||
104 | * @return bool If the extension is bundled |
||
105 | */ |
||
106 | public function isBundled() { |
||
115 | |||
116 | /** |
||
117 | * If the extension is protected against any modification (disable/uninstall) |
||
118 | * |
||
119 | * @return bool if the extension is protected |
||
120 | */ |
||
121 | public function isProtected() { |
||
131 | |||
132 | /** |
||
133 | * If the extension is installed in the correct directory |
||
134 | * |
||
135 | * @return bool If the extension is installed in the correct directory |
||
136 | */ |
||
137 | public function isInWrongFolder() { |
||
140 | |||
141 | /** |
||
142 | * If the extension is enabled |
||
143 | * |
||
144 | * @return bool If the extension is enabled |
||
145 | */ |
||
146 | public function isEnabled() { |
||
156 | |||
157 | /** |
||
158 | * If the extension should be updated, i.e. if an updated version is available |
||
159 | * |
||
160 | * @return bool If an update is available |
||
161 | */ |
||
162 | public function updateAvailable() { |
||
171 | |||
172 | /** |
||
173 | * If the extension is a template |
||
174 | * |
||
175 | * @return bool If this extension is a template |
||
176 | */ |
||
177 | public function isTemplate() { |
||
180 | |||
181 | /** |
||
182 | * Get the ID of the extension |
||
183 | * |
||
184 | * This is the same as getName() for plugins, for templates it's getName() prefixed with 'template:' |
||
185 | * |
||
186 | * @return string |
||
187 | */ |
||
188 | public function getID() { |
||
191 | |||
192 | /** |
||
193 | * Get the name of the installation directory |
||
194 | * |
||
195 | * @return string The name of the installation directory |
||
196 | */ |
||
197 | public function getInstallName() { |
||
200 | |||
201 | // Data from plugin.info.txt/template.info.txt or the repo when not available locally |
||
202 | /** |
||
203 | * Get the basename of the extension |
||
204 | * |
||
205 | * @return string The basename |
||
206 | */ |
||
207 | public function getBase() { |
||
211 | |||
212 | /** |
||
213 | * Get the display name of the extension |
||
214 | * |
||
215 | * @return string The display name |
||
216 | */ |
||
217 | public function getDisplayName() { |
||
222 | |||
223 | /** |
||
224 | * Get the author name of the extension |
||
225 | * |
||
226 | * @return string|bool The name of the author or false if there is none |
||
227 | */ |
||
228 | public function getAuthor() { |
||
233 | |||
234 | /** |
||
235 | * Get the email of the author of the extension if there is any |
||
236 | * |
||
237 | * @return string|bool The email address or false if there is none |
||
238 | */ |
||
239 | public function getEmail() { |
||
244 | |||
245 | /** |
||
246 | * Get the email id, i.e. the md5sum of the email |
||
247 | * |
||
248 | * @return string|bool The md5sum of the email if there is any, false otherwise |
||
249 | */ |
||
250 | public function getEmailID() { |
||
255 | |||
256 | /** |
||
257 | * Get the description of the extension |
||
258 | * |
||
259 | * @return string The description |
||
260 | */ |
||
261 | public function getDescription() { |
||
266 | |||
267 | /** |
||
268 | * Get the URL of the extension, usually a page on dokuwiki.org |
||
269 | * |
||
270 | * @return string The URL |
||
271 | */ |
||
272 | public function getURL() { |
||
276 | |||
277 | /** |
||
278 | * Get the installed version of the extension |
||
279 | * |
||
280 | * @return string|bool The version, usually in the form yyyy-mm-dd if there is any |
||
281 | */ |
||
282 | public function getInstalledVersion() { |
||
287 | |||
288 | /** |
||
289 | * Get the install date of the current version |
||
290 | * |
||
291 | * @return string|bool The date of the last update or false if not available |
||
292 | */ |
||
293 | public function getUpdateDate() { |
||
297 | |||
298 | /** |
||
299 | * Get the date of the installation of the plugin |
||
300 | * |
||
301 | * @return string|bool The date of the installation or false if not available |
||
302 | */ |
||
303 | public function getInstallDate() { |
||
307 | |||
308 | /** |
||
309 | * Get the names of the dependencies of this extension |
||
310 | * |
||
311 | * @return array The base names of the dependencies |
||
312 | */ |
||
313 | public function getDependencies() { |
||
317 | |||
318 | /** |
||
319 | * Get the names of the missing dependencies |
||
320 | * |
||
321 | * @return array The base names of the missing dependencies |
||
322 | */ |
||
323 | public function getMissingDependencies() { |
||
335 | |||
336 | /** |
||
337 | * Get the names of all conflicting extensions |
||
338 | * |
||
339 | * @return array The names of the conflicting extensions |
||
340 | */ |
||
341 | public function getConflicts() { |
||
345 | |||
346 | /** |
||
347 | * Get the names of similar extensions |
||
348 | * |
||
349 | * @return array The names of similar extensions |
||
350 | */ |
||
351 | public function getSimilarExtensions() { |
||
355 | |||
356 | /** |
||
357 | * Get the names of the tags of the extension |
||
358 | * |
||
359 | * @return array The names of the tags of the extension |
||
360 | */ |
||
361 | public function getTags() { |
||
365 | |||
366 | /** |
||
367 | * Get the popularity information as floating point number [0,1] |
||
368 | * |
||
369 | * @return float|bool The popularity information or false if it isn't available |
||
370 | */ |
||
371 | public function getPopularity() { |
||
375 | |||
376 | |||
377 | /** |
||
378 | * Get the text of the security warning if there is any |
||
379 | * |
||
380 | * @return string|bool The security warning if there is any, false otherwise |
||
381 | */ |
||
382 | public function getSecurityWarning() { |
||
386 | |||
387 | /** |
||
388 | * Get the text of the security issue if there is any |
||
389 | * |
||
390 | * @return string|bool The security issue if there is any, false otherwise |
||
391 | */ |
||
392 | public function getSecurityIssue() { |
||
396 | |||
397 | /** |
||
398 | * Get the URL of the screenshot of the extension if there is any |
||
399 | * |
||
400 | * @return string|bool The screenshot URL if there is any, false otherwise |
||
401 | */ |
||
402 | public function getScreenshotURL() { |
||
406 | |||
407 | /** |
||
408 | * Get the URL of the thumbnail of the extension if there is any |
||
409 | * |
||
410 | * @return string|bool The thumbnail URL if there is any, false otherwise |
||
411 | */ |
||
412 | public function getThumbnailURL() { |
||
416 | /** |
||
417 | * Get the last used download URL of the extension if there is any |
||
418 | * |
||
419 | * @return string|bool The previously used download URL, false if the extension has been installed manually |
||
420 | */ |
||
421 | public function getLastDownloadURL() { |
||
425 | |||
426 | /** |
||
427 | * Get the download URL of the extension if there is any |
||
428 | * |
||
429 | * @return string|bool The download URL if there is any, false otherwise |
||
430 | */ |
||
431 | public function getDownloadURL() { |
||
435 | |||
436 | /** |
||
437 | * If the download URL has changed since the last download |
||
438 | * |
||
439 | * @return bool If the download URL has changed |
||
440 | */ |
||
441 | public function hasDownloadURLChanged() { |
||
446 | |||
447 | /** |
||
448 | * Get the bug tracker URL of the extension if there is any |
||
449 | * |
||
450 | * @return string|bool The bug tracker URL if there is any, false otherwise |
||
451 | */ |
||
452 | public function getBugtrackerURL() { |
||
456 | |||
457 | /** |
||
458 | * Get the URL of the source repository if there is any |
||
459 | * |
||
460 | * @return string|bool The URL of the source repository if there is any, false otherwise |
||
461 | */ |
||
462 | public function getSourcerepoURL() { |
||
466 | |||
467 | /** |
||
468 | * Get the donation URL of the extension if there is any |
||
469 | * |
||
470 | * @return string|bool The donation URL if there is any, false otherwise |
||
471 | */ |
||
472 | public function getDonationURL() { |
||
476 | |||
477 | /** |
||
478 | * Get the extension type(s) |
||
479 | * |
||
480 | * @return array The type(s) as array of strings |
||
481 | */ |
||
482 | public function getTypes() { |
||
487 | |||
488 | /** |
||
489 | * Get a list of all DokuWiki versions this extension is compatible with |
||
490 | * |
||
491 | * @return array The versions in the form yyyy-mm-dd => ('label' => label, 'implicit' => implicit) |
||
492 | */ |
||
493 | public function getCompatibleVersions() { |
||
497 | |||
498 | /** |
||
499 | * Get the date of the last available update |
||
500 | * |
||
501 | * @return string|bool The last available update in the form yyyy-mm-dd if there is any, false otherwise |
||
502 | */ |
||
503 | public function getLastUpdate() { |
||
507 | |||
508 | /** |
||
509 | * Get the base path of the extension |
||
510 | * |
||
511 | * @return string The base path of the extension |
||
512 | */ |
||
513 | public function getInstallDir() { |
||
520 | |||
521 | /** |
||
522 | * The type of extension installation |
||
523 | * |
||
524 | * @return string One of "none", "manual", "git" or "automatic" |
||
525 | */ |
||
526 | public function getInstallType() { |
||
532 | |||
533 | /** |
||
534 | * If the extension can probably be installed/updated or uninstalled |
||
535 | * |
||
536 | * @return bool|string True or error string |
||
537 | */ |
||
538 | public function canModify() { |
||
553 | |||
554 | /** |
||
555 | * Install an extension from a user upload |
||
556 | * |
||
557 | * @param string $field name of the upload file |
||
558 | * @throws Exception when something goes wrong |
||
559 | * @return array The list of installed extensions |
||
560 | */ |
||
561 | public function installFromUpload($field){ |
||
589 | |||
590 | /** |
||
591 | * Install an extension from a remote URL |
||
592 | * |
||
593 | * @param string $url |
||
594 | * @throws Exception when something goes wrong |
||
595 | * @return array The list of installed extensions |
||
596 | */ |
||
597 | public function installFromURL($url){ |
||
611 | |||
612 | /** |
||
613 | * Install or update the extension |
||
614 | * |
||
615 | * @throws \Exception when something goes wrong |
||
616 | * @return array The list of installed extensions |
||
617 | */ |
||
618 | public function installOrUpdate() { |
||
633 | |||
634 | /** |
||
635 | * Uninstall the extension |
||
636 | * |
||
637 | * @return bool If the plugin was sucessfully uninstalled |
||
638 | */ |
||
639 | public function uninstall() { |
||
658 | |||
659 | /** |
||
660 | * Enable the extension |
||
661 | * |
||
662 | * @return bool|string True or an error message |
||
663 | */ |
||
664 | public function enable() { |
||
689 | |||
690 | /** |
||
691 | * Disable the extension |
||
692 | * |
||
693 | * @return bool|string True or an error message |
||
694 | */ |
||
695 | public function disable() { |
||
720 | |||
721 | /** |
||
722 | * Purge the cache by touching the main configuration file |
||
723 | */ |
||
724 | protected function purgeCache() { |
||
731 | |||
732 | /** |
||
733 | * Read local extension data either from info.txt or getInfo() |
||
734 | */ |
||
735 | protected function readLocalData() { |
||
773 | |||
774 | /** |
||
775 | * Save the given URL and current datetime in the manager.dat file of all installed extensions |
||
776 | * |
||
777 | * @param string $url Where the extension was downloaded from. (empty for manual installs via upload) |
||
778 | * @param array $installed Optional list of installed plugins |
||
779 | */ |
||
780 | protected function updateManagerData($url = '', $installed = null) { |
||
804 | |||
805 | /** |
||
806 | * Read the manager.dat file |
||
807 | */ |
||
808 | protected function readManagerData() { |
||
824 | |||
825 | /** |
||
826 | * Write the manager.data file |
||
827 | */ |
||
828 | protected function writeManagerData() { |
||
836 | |||
837 | /** |
||
838 | * Returns a temporary directory |
||
839 | * |
||
840 | * The directory is registered for cleanup when the class is destroyed |
||
841 | * |
||
842 | * @return false|string |
||
843 | */ |
||
844 | protected function mkTmpDir(){ |
||
850 | |||
851 | /** |
||
852 | * Download an archive to a protected path |
||
853 | * |
||
854 | * @param string $url The url to get the archive from |
||
855 | * @throws Exception when something goes wrong |
||
856 | * @return string The path where the archive was saved |
||
857 | */ |
||
858 | public function download($url) { |
||
885 | |||
886 | /** |
||
887 | * @param string $file The path to the archive that shall be installed |
||
888 | * @param bool $overwrite If an already installed plugin should be overwritten |
||
889 | * @param string $base The basename of the plugin if it's known |
||
890 | * @throws Exception when something went wrong |
||
891 | * @return array list of installed extensions |
||
892 | */ |
||
893 | public function installArchive($file, $overwrite=false, $base = '') { |
||
994 | |||
995 | /** |
||
996 | * Find out what was in the extracted directory |
||
997 | * |
||
998 | * Correct folders are searched recursively using the "*.info.txt" configs |
||
999 | * as indicator for a root folder. When such a file is found, it's base |
||
1000 | * setting is used (when set). All folders found by this method are stored |
||
1001 | * in the 'new' key of the $result array. |
||
1002 | * |
||
1003 | * For backwards compatibility all found top level folders are stored as |
||
1004 | * in the 'old' key of the $result array. |
||
1005 | * |
||
1006 | * When no items are found in 'new' the copy mechanism should fall back |
||
1007 | * the 'old' list. |
||
1008 | * |
||
1009 | * @author Andreas Gohr <[email protected]> |
||
1010 | * @param array $result - results are stored here |
||
1011 | * @param string $directory - the temp directory where the package was unpacked to |
||
1012 | * @param string $default_type - type used if no info.txt available |
||
1013 | * @param string $subdir - a subdirectory. do not set. used by recursion |
||
1014 | * @return bool - false on error |
||
1015 | */ |
||
1016 | protected function find_folders(&$result, $directory, $default_type='plugin', $subdir='') { |
||
1078 | |||
1079 | /** |
||
1080 | * Decompress a given file to the given target directory |
||
1081 | * |
||
1082 | * Determines the compression type from the file extension |
||
1083 | * |
||
1084 | * @param string $file archive to extract |
||
1085 | * @param string $target directory to extract to |
||
1086 | * @throws Exception |
||
1087 | * @return bool |
||
1088 | */ |
||
1089 | private function decompress($file, $target) { |
||
1121 | |||
1122 | /** |
||
1123 | * Determine the archive type of the given file |
||
1124 | * |
||
1125 | * Reads the first magic bytes of the given file for content type guessing, |
||
1126 | * if neither bz, gz or zip are recognized, tar is assumed. |
||
1127 | * |
||
1128 | * @author Andreas Gohr <[email protected]> |
||
1129 | * @param string $file The file to analyze |
||
1130 | * @return string|false false if the file can't be read, otherwise an "extension" |
||
1131 | */ |
||
1132 | private function guess_archive($file) { |
||
1143 | |||
1144 | /** |
||
1145 | * Copy with recursive sub-directory support |
||
1146 | * |
||
1147 | * @param string $src filename path to file |
||
1148 | * @param string $dst filename path to file |
||
1149 | * @return bool|int|string |
||
1150 | */ |
||
1151 | private function dircopy($src, $dst) { |
||
1177 | |||
1178 | /** |
||
1179 | * Delete outdated files from updated plugins |
||
1180 | * |
||
1181 | * @param array $installed |
||
1182 | */ |
||
1183 | private function removeDeletedfiles($installed) { |
||
1211 | |||
1212 | } |
||
1213 | |||
1215 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.