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 OC_App 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 OC_App, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
56 | class OC_App { |
||
57 | static private $appVersion = []; |
||
58 | static private $adminForms = array(); |
||
59 | static private $personalForms = array(); |
||
60 | static private $appInfo = array(); |
||
61 | static private $appTypes = array(); |
||
62 | static private $loadedApps = array(); |
||
63 | static private $altLogin = array(); |
||
64 | const officialApp = 200; |
||
65 | |||
66 | /** |
||
67 | * clean the appId |
||
68 | * |
||
69 | * @param string|boolean $app AppId that needs to be cleaned |
||
70 | * @return string |
||
71 | */ |
||
72 | 1253 | public static function cleanAppId($app) { |
|
75 | |||
76 | /** |
||
77 | * Check if an app is loaded |
||
78 | * |
||
79 | * @param string $app |
||
80 | * @return bool |
||
81 | */ |
||
82 | 1 | public static function isAppLoaded($app) { |
|
85 | |||
86 | /** |
||
87 | * loads all apps |
||
88 | * |
||
89 | * @param array $types |
||
90 | * @return bool |
||
91 | * |
||
92 | * This function walks through the ownCloud directory and loads all apps |
||
93 | * it can find. A directory contains an app if the file /appinfo/info.xml |
||
94 | * exists. |
||
95 | * |
||
96 | * if $types is set, only apps of those types will be loaded |
||
97 | */ |
||
98 | 1077 | public static function loadApps($types = null) { |
|
124 | |||
125 | /** |
||
126 | * load a single app |
||
127 | * |
||
128 | * @param string $app |
||
129 | * @param bool $checkUpgrade whether an upgrade check should be done |
||
130 | * @throws \OC\NeedsUpdateException |
||
131 | */ |
||
132 | 9 | public static function loadApp($app, $checkUpgrade = true) { |
|
151 | |||
152 | /** |
||
153 | * Load app.php from the given app |
||
154 | * |
||
155 | * @param string $app app name |
||
156 | */ |
||
157 | 9 | private static function requireAppFile($app) { |
|
161 | |||
162 | /** |
||
163 | * check if an app is of a specific type |
||
164 | * |
||
165 | * @param string $app |
||
166 | * @param string|array $types |
||
167 | * @return bool |
||
168 | */ |
||
169 | 1077 | public static function isType($app, $types) { |
|
181 | |||
182 | /** |
||
183 | * get the types of an app |
||
184 | * |
||
185 | * @param string $app |
||
186 | * @return array |
||
187 | */ |
||
188 | 1077 | private static function getAppTypes($app) { |
|
200 | |||
201 | /** |
||
202 | * read app types from info.xml and cache them in the database |
||
203 | */ |
||
204 | 2 | public static function setAppTypes($app) { |
|
215 | |||
216 | /** |
||
217 | * check if app is shipped |
||
218 | * |
||
219 | * @param string $appId the id of the app to check |
||
220 | * @return bool |
||
221 | * |
||
222 | * Check if an app that is installed is a shipped app or installed from the appstore. |
||
223 | */ |
||
224 | 4 | public static function isShipped($appId) { |
|
227 | |||
228 | /** |
||
229 | * get all enabled apps |
||
230 | */ |
||
231 | protected static $enabledAppsCache = array(); |
||
232 | |||
233 | /** |
||
234 | * Returns apps enabled for the current user. |
||
235 | * |
||
236 | * @param bool $forceRefresh whether to refresh the cache |
||
237 | * @param bool $all whether to return apps for all users, not only the |
||
238 | * currently logged in one |
||
239 | * @return string[] |
||
240 | */ |
||
241 | 1091 | public static function getEnabledApps($forceRefresh = false, $all = false) { |
|
266 | |||
267 | /** |
||
268 | * checks whether or not an app is enabled |
||
269 | * |
||
270 | * @param string $app app |
||
271 | * @return bool |
||
272 | * |
||
273 | * This function checks whether or not an app is enabled. |
||
274 | */ |
||
275 | 144 | public static function isEnabled($app) { |
|
278 | |||
279 | /** |
||
280 | * enables an app |
||
281 | * |
||
282 | * @param mixed $app app |
||
283 | * @param array $groups (optional) when set, only these groups will have access to the app |
||
284 | * @throws \Exception |
||
285 | * @return void |
||
286 | * |
||
287 | * This function set an app as enabled in appconfig. |
||
288 | */ |
||
289 | 1 | public static function enable($app, $groups = null) { |
|
310 | |||
311 | /** |
||
312 | * @param string $app |
||
313 | * @return int |
||
314 | */ |
||
315 | public static function downloadApp($app) { |
||
331 | |||
332 | /** |
||
333 | * @param string $app |
||
334 | * @return bool |
||
335 | */ |
||
336 | public static function removeApp($app) { |
||
343 | |||
344 | /** |
||
345 | * This function set an app as disabled in appconfig. |
||
346 | * |
||
347 | * @param string $app app |
||
348 | * @throws Exception |
||
349 | */ |
||
350 | public static function disable($app) { |
||
362 | |||
363 | /** |
||
364 | * Returns the Settings Navigation |
||
365 | * |
||
366 | * @return string[] |
||
367 | * |
||
368 | * This function returns an array containing all settings pages added. The |
||
369 | * entries are sorted by the key 'order' ascending. |
||
370 | */ |
||
371 | public static function getSettingsNavigation() { |
||
372 | $l = \OC::$server->getL10N('lib'); |
||
373 | |||
374 | $settings = array(); |
||
375 | // by default, settings only contain the help menu |
||
376 | if (OC_Util::getEditionString() === '' && |
||
377 | \OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true |
||
378 | ) { |
||
379 | $settings = array( |
||
380 | array( |
||
381 | "id" => "help", |
||
382 | "order" => 1000, |
||
383 | "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_help'), |
||
384 | "name" => $l->t("Help"), |
||
385 | "icon" => OC_Helper::imagePath("settings", "help.svg") |
||
386 | ) |
||
387 | ); |
||
388 | } |
||
389 | |||
390 | // if the user is logged-in |
||
391 | if (OC_User::isLoggedIn()) { |
||
392 | // personal menu |
||
393 | $settings[] = array( |
||
394 | "id" => "personal", |
||
395 | "order" => 1, |
||
396 | "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_personal'), |
||
397 | "name" => $l->t("Personal"), |
||
398 | "icon" => OC_Helper::imagePath("settings", "personal.svg") |
||
399 | ); |
||
400 | |||
401 | //SubAdmins are also allowed to access user management |
||
402 | $userObject = \OC::$server->getUserSession()->getUser(); |
||
403 | $isSubAdmin = false; |
||
404 | if($userObject !== null) { |
||
405 | $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject); |
||
406 | } |
||
407 | View Code Duplication | if ($isSubAdmin) { |
|
408 | // admin users menu |
||
409 | $settings[] = array( |
||
410 | "id" => "core_users", |
||
411 | "order" => 2, |
||
412 | "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_users'), |
||
413 | "name" => $l->t("Users"), |
||
414 | "icon" => OC_Helper::imagePath("settings", "users.svg") |
||
415 | ); |
||
416 | } |
||
417 | |||
418 | // if the user is an admin |
||
419 | View Code Duplication | if (OC_User::isAdminUser(OC_User::getUser())) { |
|
420 | // admin settings |
||
421 | $settings[] = array( |
||
422 | "id" => "admin", |
||
423 | "order" => 1000, |
||
424 | "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_admin'), |
||
425 | "name" => $l->t("Admin"), |
||
426 | "icon" => OC_Helper::imagePath("settings", "admin.svg") |
||
427 | ); |
||
428 | } |
||
429 | } |
||
430 | |||
431 | $navigation = self::proceedNavigation($settings); |
||
432 | return $navigation; |
||
433 | } |
||
434 | |||
435 | // This is private as well. It simply works, so don't ask for more details |
||
436 | private static function proceedNavigation($list) { |
||
451 | |||
452 | /** |
||
453 | * Get the path where to install apps |
||
454 | * |
||
455 | * @return string|false |
||
456 | */ |
||
457 | 3 | public static function getInstallPath() { |
|
471 | |||
472 | |||
473 | /** |
||
474 | * search for an app in all app-directories |
||
475 | * |
||
476 | * @param string $appId |
||
477 | * @return false|string |
||
478 | */ |
||
479 | 1174 | protected static function findAppInDirectories($appId) { |
|
519 | |||
520 | /** |
||
521 | * Get the directory for the given app. |
||
522 | * If the app is defined in multiple directories, the first one is taken. (false if not found) |
||
523 | * |
||
524 | * @param string $appId |
||
525 | * @return string|false |
||
526 | */ |
||
527 | 1174 | public static function getAppPath($appId) { |
|
537 | |||
538 | |||
539 | /** |
||
540 | * check if an app's directory is writable |
||
541 | * |
||
542 | * @param string $appId |
||
543 | * @return bool |
||
544 | */ |
||
545 | public static function isAppDirWritable($appId) { |
||
549 | |||
550 | /** |
||
551 | * Get the path for the given app on the access |
||
552 | * If the app is defined in multiple directories, the first one is taken. (false if not found) |
||
553 | * |
||
554 | * @param string $appId |
||
555 | * @return string|false |
||
556 | */ |
||
557 | 4 | public static function getAppWebPath($appId) { |
|
563 | |||
564 | /** |
||
565 | * get the last version of the app, either from appinfo/version or from appinfo/info.xml |
||
566 | * |
||
567 | * @param string $appId |
||
568 | * @return string |
||
569 | */ |
||
570 | 19 | public static function getAppVersion($appId) { |
|
577 | |||
578 | /** |
||
579 | * get app's version based on it's path |
||
580 | * |
||
581 | * @param string $path |
||
582 | * @return string |
||
583 | */ |
||
584 | 3 | public static function getAppVersionByPath($path) { |
|
594 | |||
595 | |||
596 | /** |
||
597 | * Read all app metadata from the info.xml file |
||
598 | * |
||
599 | * @param string $appId id of the app or the path of the info.xml file |
||
600 | * @param boolean $path (optional) |
||
601 | * @return array|null |
||
602 | * @note all data is read from info.xml, not just pre-defined fields |
||
603 | */ |
||
604 | 8 | public static function getAppInfo($appId, $path = false) { |
|
631 | |||
632 | /** |
||
633 | * Returns the navigation |
||
634 | * |
||
635 | * @return array |
||
636 | * |
||
637 | * This function returns an array containing all entries added. The |
||
638 | * entries are sorted by the key 'order' ascending. Additional to the keys |
||
639 | * given for each app the following keys exist: |
||
640 | * - active: boolean, signals if the user is on this navigation entry |
||
641 | */ |
||
642 | public static function getNavigation() { |
||
647 | |||
648 | /** |
||
649 | * get the id of loaded app |
||
650 | * |
||
651 | * @return string |
||
652 | */ |
||
653 | public static function getCurrentApp() { |
||
670 | |||
671 | /** |
||
672 | * @param string $type |
||
673 | * @return array |
||
674 | */ |
||
675 | public static function getForms($type) { |
||
692 | |||
693 | /** |
||
694 | * register an admin form to be shown |
||
695 | * |
||
696 | * @param string $app |
||
697 | * @param string $page |
||
698 | */ |
||
699 | public static function registerAdmin($app, $page) { |
||
702 | |||
703 | /** |
||
704 | * register a personal form to be shown |
||
705 | * @param string $app |
||
706 | * @param string $page |
||
707 | */ |
||
708 | public static function registerPersonal($app, $page) { |
||
711 | |||
712 | /** |
||
713 | * @param array $entry |
||
714 | */ |
||
715 | public static function registerLogIn(array $entry) { |
||
718 | |||
719 | /** |
||
720 | * @return array |
||
721 | */ |
||
722 | public static function getAlternativeLogIns() { |
||
725 | |||
726 | /** |
||
727 | * get a list of all apps in the apps folder |
||
728 | * |
||
729 | * @return array an array of app names (string IDs) |
||
730 | * @todo: change the name of this method to getInstalledApps, which is more accurate |
||
731 | */ |
||
732 | 5 | public static function getAllApps() { |
|
756 | |||
757 | /** |
||
758 | * List all apps, this is used in apps.php |
||
759 | * |
||
760 | * @param bool $onlyLocal |
||
761 | * @param bool $includeUpdateInfo Should we check whether there is an update |
||
762 | * in the app store? |
||
763 | * @param OCSClient $ocsClient |
||
764 | * @return array |
||
765 | */ |
||
766 | 4 | public static function listAllApps($onlyLocal = false, |
|
852 | |||
853 | /** |
||
854 | * Returns the internal app ID or false |
||
855 | * @param string $ocsID |
||
856 | * @return string|false |
||
857 | */ |
||
858 | protected static function getInternalAppIdByOcs($ocsID) { |
||
867 | |||
868 | /** |
||
869 | * Get a list of all apps on the appstore |
||
870 | * @param string $filter |
||
871 | * @param string|null $category |
||
872 | * @param OCSClient $ocsClient |
||
873 | * @return array|bool multi-dimensional array of apps. |
||
874 | * Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description |
||
875 | */ |
||
876 | 4 | public static function getAppstoreApps($filter = 'approved', |
|
926 | |||
927 | 13 | public static function shouldUpgrade($app) { |
|
938 | |||
939 | /** |
||
940 | * Adjust the number of version parts of $version1 to match |
||
941 | * the number of version parts of $version2. |
||
942 | * |
||
943 | * @param string $version1 version to adjust |
||
944 | * @param string $version2 version to take the number of parts from |
||
945 | * @return string shortened $version1 |
||
946 | */ |
||
947 | 31 | private static function adjustVersionParts($version1, $version2) { |
|
960 | |||
961 | /** |
||
962 | * Check whether the current ownCloud version matches the given |
||
963 | * application's version requirements. |
||
964 | * |
||
965 | * The comparison is made based on the number of parts that the |
||
966 | * app info version has. For example for ownCloud 6.0.3 if the |
||
967 | * app info version is expecting version 6.0, the comparison is |
||
968 | * made on the first two parts of the ownCloud version. |
||
969 | * This means that it's possible to specify "requiremin" => 6 |
||
970 | * and "requiremax" => 6 and it will still match ownCloud 6.0.3. |
||
971 | * |
||
972 | * @param string $ocVersion ownCloud version to check against |
||
973 | * @param array $appInfo app info (from xml) |
||
974 | * |
||
975 | * @return boolean true if compatible, otherwise false |
||
976 | */ |
||
977 | 31 | public static function isAppCompatible($ocVersion, $appInfo) { |
|
1014 | |||
1015 | /** |
||
1016 | * get the installed version of all apps |
||
1017 | */ |
||
1018 | 13 | public static function getAppVersions() { |
|
1036 | |||
1037 | |||
1038 | /** |
||
1039 | * @param mixed $app |
||
1040 | * @return bool |
||
1041 | * @throws Exception if app is not compatible with this version of ownCloud |
||
1042 | * @throws Exception if no app-name was specified |
||
1043 | */ |
||
1044 | public static function installApp($app) { |
||
1114 | |||
1115 | /** |
||
1116 | * update the database for the app and call the update script |
||
1117 | * |
||
1118 | * @param string $appId |
||
1119 | * @return bool |
||
1120 | */ |
||
1121 | 1 | public static function updateApp($appId) { |
|
1153 | |||
1154 | /** |
||
1155 | * @param string $appId |
||
1156 | * @return \OC\Files\View|false |
||
1157 | */ |
||
1158 | public static function getStorage($appId) { |
||
1175 | |||
1176 | /** |
||
1177 | * parses the app data array and enhanced the 'description' value |
||
1178 | * |
||
1179 | * @param array $data the app data |
||
1180 | * @return array improved app data |
||
1181 | */ |
||
1182 | 9 | public static function parseAppInfo(array $data) { |
|
1212 | } |
||
1213 |