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 |
||
| 65 | class OC_App { |
||
|
|
|||
| 66 | static private $adminForms = []; |
||
| 67 | static private $personalForms = []; |
||
| 68 | static private $appTypes = []; |
||
| 69 | static private $loadedApps = []; |
||
| 70 | static private $altLogin = []; |
||
| 71 | static private $alreadyRegistered = []; |
||
| 72 | const officialApp = 200; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * clean the appId |
||
| 76 | * |
||
| 77 | * @param string $app AppId that needs to be cleaned |
||
| 78 | * @return string |
||
| 79 | */ |
||
| 80 | public static function cleanAppId(string $app): string { |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Check if an app is loaded |
||
| 86 | * |
||
| 87 | * @param string $app |
||
| 88 | * @return bool |
||
| 89 | */ |
||
| 90 | public static function isAppLoaded(string $app): bool { |
||
| 93 | |||
| 94 | /** |
||
| 95 | * loads all apps |
||
| 96 | * |
||
| 97 | * @param string[] $types |
||
| 98 | * @return bool |
||
| 99 | * |
||
| 100 | * This function walks through the ownCloud directory and loads all apps |
||
| 101 | * it can find. A directory contains an app if the file /appinfo/info.xml |
||
| 102 | * exists. |
||
| 103 | * |
||
| 104 | * if $types is set to non-empty array, only apps of those types will be loaded |
||
| 105 | */ |
||
| 106 | public static function loadApps(array $types = []): bool { |
||
| 132 | |||
| 133 | /** |
||
| 134 | * load a single app |
||
| 135 | * |
||
| 136 | * @param string $app |
||
| 137 | * @throws Exception |
||
| 138 | */ |
||
| 139 | public static function loadApp(string $app) { |
||
| 140 | self::$loadedApps[] = $app; |
||
| 141 | $appPath = self::getAppPath($app); |
||
| 142 | if($appPath === false) { |
||
| 143 | return; |
||
| 144 | } |
||
| 145 | |||
| 146 | // in case someone calls loadApp() directly |
||
| 147 | self::registerAutoloading($app, $appPath); |
||
| 148 | |||
| 149 | if (is_file($appPath . '/appinfo/app.php')) { |
||
| 150 | \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app); |
||
| 151 | try { |
||
| 152 | self::requireAppFile($app); |
||
| 153 | } catch (Error $ex) { |
||
| 154 | \OC::$server->getLogger()->logException($ex); |
||
| 155 | if (!\OC::$server->getAppManager()->isShipped($app)) { |
||
| 156 | // Only disable apps which are not shipped |
||
| 157 | \OC::$server->getAppManager()->disableApp($app); |
||
| 158 | } |
||
| 159 | } |
||
| 160 | \OC::$server->getEventLogger()->end('load_app_' . $app); |
||
| 161 | } |
||
| 162 | |||
| 163 | $info = self::getAppInfo($app); |
||
| 164 | View Code Duplication | if (!empty($info['activity']['filters'])) { |
|
| 165 | foreach ($info['activity']['filters'] as $filter) { |
||
| 166 | \OC::$server->getActivityManager()->registerFilter($filter); |
||
| 167 | } |
||
| 168 | } |
||
| 169 | View Code Duplication | if (!empty($info['activity']['settings'])) { |
|
| 170 | foreach ($info['activity']['settings'] as $setting) { |
||
| 171 | \OC::$server->getActivityManager()->registerSetting($setting); |
||
| 172 | } |
||
| 173 | } |
||
| 174 | View Code Duplication | if (!empty($info['activity']['providers'])) { |
|
| 175 | foreach ($info['activity']['providers'] as $provider) { |
||
| 176 | \OC::$server->getActivityManager()->registerProvider($provider); |
||
| 177 | } |
||
| 178 | } |
||
| 179 | |||
| 180 | View Code Duplication | if (!empty($info['settings']['admin'])) { |
|
| 181 | foreach ($info['settings']['admin'] as $setting) { |
||
| 182 | \OC::$server->getSettingsManager()->registerSetting('admin', $setting); |
||
| 183 | } |
||
| 184 | } |
||
| 185 | if (!empty($info['settings']['admin-section'])) { |
||
| 186 | foreach ($info['settings']['admin-section'] as $section) { |
||
| 187 | \OC::$server->getSettingsManager()->registerSection('admin', $section); |
||
| 188 | } |
||
| 189 | } |
||
| 190 | if (!empty($info['settings']['personal'])) { |
||
| 191 | foreach ($info['settings']['personal'] as $setting) { |
||
| 192 | \OC::$server->getSettingsManager()->registerSetting('personal', $setting); |
||
| 193 | } |
||
| 194 | } |
||
| 195 | if (!empty($info['settings']['personal-section'])) { |
||
| 196 | foreach ($info['settings']['personal-section'] as $section) { |
||
| 197 | \OC::$server->getSettingsManager()->registerSection('personal', $section); |
||
| 198 | } |
||
| 199 | } |
||
| 200 | |||
| 201 | if (!empty($info['collaboration']['plugins'])) { |
||
| 202 | // deal with one or many plugin entries |
||
| 203 | $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ? |
||
| 204 | [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin']; |
||
| 205 | foreach ($plugins as $plugin) { |
||
| 206 | if($plugin['@attributes']['type'] === 'collaborator-search') { |
||
| 207 | $pluginInfo = [ |
||
| 208 | 'shareType' => $plugin['@attributes']['share-type'], |
||
| 209 | 'class' => $plugin['@value'], |
||
| 210 | ]; |
||
| 211 | \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo); |
||
| 212 | } else if ($plugin['@attributes']['type'] === 'autocomplete-sort') { |
||
| 213 | \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']); |
||
| 214 | } |
||
| 215 | } |
||
| 216 | } |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * @internal |
||
| 221 | * @param string $app |
||
| 222 | * @param string $path |
||
| 223 | */ |
||
| 224 | public static function registerAutoloading(string $app, string $path) { |
||
| 249 | |||
| 250 | /** |
||
| 251 | * Load app.php from the given app |
||
| 252 | * |
||
| 253 | * @param string $app app name |
||
| 254 | * @throws Error |
||
| 255 | */ |
||
| 256 | private static function requireAppFile(string $app) { |
||
| 260 | |||
| 261 | /** |
||
| 262 | * check if an app is of a specific type |
||
| 263 | * |
||
| 264 | * @param string $app |
||
| 265 | * @param array $types |
||
| 266 | * @return bool |
||
| 267 | */ |
||
| 268 | public static function isType(string $app, array $types): bool { |
||
| 277 | |||
| 278 | /** |
||
| 279 | * get the types of an app |
||
| 280 | * |
||
| 281 | * @param string $app |
||
| 282 | * @return array |
||
| 283 | */ |
||
| 284 | private static function getAppTypes(string $app): array { |
||
| 296 | |||
| 297 | /** |
||
| 298 | * read app types from info.xml and cache them in the database |
||
| 299 | */ |
||
| 300 | public static function setAppTypes(string $app) { |
||
| 324 | |||
| 325 | /** |
||
| 326 | * Returns apps enabled for the current user. |
||
| 327 | * |
||
| 328 | * @param bool $forceRefresh whether to refresh the cache |
||
| 329 | * @param bool $all whether to return apps for all users, not only the |
||
| 330 | * currently logged in one |
||
| 331 | * @return string[] |
||
| 332 | */ |
||
| 333 | public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array { |
||
| 358 | |||
| 359 | /** |
||
| 360 | * checks whether or not an app is enabled |
||
| 361 | * |
||
| 362 | * @param string $app app |
||
| 363 | * @return bool |
||
| 364 | * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId) |
||
| 365 | * |
||
| 366 | * This function checks whether or not an app is enabled. |
||
| 367 | */ |
||
| 368 | public static function isEnabled(string $app): bool { |
||
| 371 | |||
| 372 | /** |
||
| 373 | * enables an app |
||
| 374 | * |
||
| 375 | * @param string $appId |
||
| 376 | * @param array $groups (optional) when set, only these groups will have access to the app |
||
| 377 | * @throws \Exception |
||
| 378 | * @return void |
||
| 379 | * |
||
| 380 | * This function set an app as enabled in appconfig. |
||
| 381 | */ |
||
| 382 | public function enable(string $appId, |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Get the path where to install apps |
||
| 413 | * |
||
| 414 | * @return string|false |
||
| 415 | */ |
||
| 416 | public static function getInstallPath() { |
||
| 430 | |||
| 431 | |||
| 432 | /** |
||
| 433 | * search for an app in all app-directories |
||
| 434 | * |
||
| 435 | * @param string $appId |
||
| 436 | * @return false|string |
||
| 437 | */ |
||
| 438 | public static function findAppInDirectories(string $appId) { |
||
| 478 | |||
| 479 | /** |
||
| 480 | * Get the directory for the given app. |
||
| 481 | * If the app is defined in multiple directories, the first one is taken. (false if not found) |
||
| 482 | * |
||
| 483 | * @param string $appId |
||
| 484 | * @return string|false |
||
| 485 | */ |
||
| 486 | public static function getAppPath(string $appId) { |
||
| 496 | |||
| 497 | /** |
||
| 498 | * Get the path for the given app on the access |
||
| 499 | * If the app is defined in multiple directories, the first one is taken. (false if not found) |
||
| 500 | * |
||
| 501 | * @param string $appId |
||
| 502 | * @return string|false |
||
| 503 | */ |
||
| 504 | public static function getAppWebPath(string $appId) { |
||
| 510 | |||
| 511 | /** |
||
| 512 | * get the last version of the app from appinfo/info.xml |
||
| 513 | * |
||
| 514 | * @param string $appId |
||
| 515 | * @param bool $useCache |
||
| 516 | * @return string |
||
| 517 | * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion() |
||
| 518 | */ |
||
| 519 | public static function getAppVersion(string $appId, bool $useCache = true): string { |
||
| 522 | |||
| 523 | /** |
||
| 524 | * get app's version based on it's path |
||
| 525 | * |
||
| 526 | * @param string $path |
||
| 527 | * @return string |
||
| 528 | */ |
||
| 529 | public static function getAppVersionByPath(string $path): string { |
||
| 534 | |||
| 535 | |||
| 536 | /** |
||
| 537 | * Read all app metadata from the info.xml file |
||
| 538 | * |
||
| 539 | * @param string $appId id of the app or the path of the info.xml file |
||
| 540 | * @param bool $path |
||
| 541 | * @param string $lang |
||
| 542 | * @return array|null |
||
| 543 | * @note all data is read from info.xml, not just pre-defined fields |
||
| 544 | * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo() |
||
| 545 | */ |
||
| 546 | public static function getAppInfo(string $appId, bool $path = false, string $lang = null) { |
||
| 549 | |||
| 550 | /** |
||
| 551 | * Returns the navigation |
||
| 552 | * |
||
| 553 | * @return array |
||
| 554 | * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll() |
||
| 555 | * |
||
| 556 | * This function returns an array containing all entries added. The |
||
| 557 | * entries are sorted by the key 'order' ascending. Additional to the keys |
||
| 558 | * given for each app the following keys exist: |
||
| 559 | * - active: boolean, signals if the user is on this navigation entry |
||
| 560 | */ |
||
| 561 | public static function getNavigation(): array { |
||
| 564 | |||
| 565 | /** |
||
| 566 | * Returns the Settings Navigation |
||
| 567 | * |
||
| 568 | * @return string[] |
||
| 569 | * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings') |
||
| 570 | * |
||
| 571 | * This function returns an array containing all settings pages added. The |
||
| 572 | * entries are sorted by the key 'order' ascending. |
||
| 573 | */ |
||
| 574 | public static function getSettingsNavigation(): array { |
||
| 577 | |||
| 578 | /** |
||
| 579 | * get the id of loaded app |
||
| 580 | * |
||
| 581 | * @return string |
||
| 582 | */ |
||
| 583 | public static function getCurrentApp(): string { |
||
| 600 | |||
| 601 | /** |
||
| 602 | * @param string $type |
||
| 603 | * @return array |
||
| 604 | */ |
||
| 605 | public static function getForms(string $type): array { |
||
| 622 | |||
| 623 | /** |
||
| 624 | * register an admin form to be shown |
||
| 625 | * |
||
| 626 | * @param string $app |
||
| 627 | * @param string $page |
||
| 628 | */ |
||
| 629 | public static function registerAdmin(string $app, string $page) { |
||
| 632 | |||
| 633 | /** |
||
| 634 | * register a personal form to be shown |
||
| 635 | * @param string $app |
||
| 636 | * @param string $page |
||
| 637 | */ |
||
| 638 | public static function registerPersonal(string $app, string $page) { |
||
| 641 | |||
| 642 | /** |
||
| 643 | * @param array $entry |
||
| 644 | */ |
||
| 645 | public static function registerLogIn(array $entry) { |
||
| 648 | |||
| 649 | /** |
||
| 650 | * @return array |
||
| 651 | */ |
||
| 652 | public static function getAlternativeLogIns(): array { |
||
| 655 | |||
| 656 | /** |
||
| 657 | * get a list of all apps in the apps folder |
||
| 658 | * |
||
| 659 | * @return array an array of app names (string IDs) |
||
| 660 | * @todo: change the name of this method to getInstalledApps, which is more accurate |
||
| 661 | */ |
||
| 662 | public static function getAllApps(): array { |
||
| 688 | |||
| 689 | /** |
||
| 690 | * List all apps, this is used in apps.php |
||
| 691 | * |
||
| 692 | * @return array |
||
| 693 | */ |
||
| 694 | public function listAllApps(): array { |
||
| 774 | |||
| 775 | public static function shouldUpgrade(string $app): bool { |
||
| 786 | |||
| 787 | /** |
||
| 788 | * Adjust the number of version parts of $version1 to match |
||
| 789 | * the number of version parts of $version2. |
||
| 790 | * |
||
| 791 | * @param string $version1 version to adjust |
||
| 792 | * @param string $version2 version to take the number of parts from |
||
| 793 | * @return string shortened $version1 |
||
| 794 | */ |
||
| 795 | private static function adjustVersionParts(string $version1, string $version2): string { |
||
| 808 | |||
| 809 | /** |
||
| 810 | * Check whether the current ownCloud version matches the given |
||
| 811 | * application's version requirements. |
||
| 812 | * |
||
| 813 | * The comparison is made based on the number of parts that the |
||
| 814 | * app info version has. For example for ownCloud 6.0.3 if the |
||
| 815 | * app info version is expecting version 6.0, the comparison is |
||
| 816 | * made on the first two parts of the ownCloud version. |
||
| 817 | * This means that it's possible to specify "requiremin" => 6 |
||
| 818 | * and "requiremax" => 6 and it will still match ownCloud 6.0.3. |
||
| 819 | * |
||
| 820 | * @param string $ocVersion ownCloud version to check against |
||
| 821 | * @param array $appInfo app info (from xml) |
||
| 822 | * |
||
| 823 | * @return boolean true if compatible, otherwise false |
||
| 824 | */ |
||
| 825 | public static function isAppCompatible(string $ocVersion, array $appInfo): bool { |
||
| 861 | |||
| 862 | /** |
||
| 863 | * get the installed version of all apps |
||
| 864 | */ |
||
| 865 | public static function getAppVersions() { |
||
| 874 | |||
| 875 | /** |
||
| 876 | * update the database for the app and call the update script |
||
| 877 | * |
||
| 878 | * @param string $appId |
||
| 879 | * @return bool |
||
| 880 | */ |
||
| 881 | public static function updateApp(string $appId): bool { |
||
| 934 | |||
| 935 | /** |
||
| 936 | * @param string $appId |
||
| 937 | * @param string[] $steps |
||
| 938 | * @throws \OC\NeedsUpdateException |
||
| 939 | */ |
||
| 940 | public static function executeRepairSteps(string $appId, array $steps) { |
||
| 962 | |||
| 963 | public static function setupBackgroundJobs(array $jobs) { |
||
| 969 | |||
| 970 | /** |
||
| 971 | * @param string $appId |
||
| 972 | * @param string[] $steps |
||
| 973 | */ |
||
| 974 | private static function setupLiveMigrations(string $appId, array $steps) { |
||
| 982 | |||
| 983 | /** |
||
| 984 | * @param string $appId |
||
| 985 | * @return \OC\Files\View|false |
||
| 986 | */ |
||
| 987 | public static function getStorage(string $appId) { |
||
| 1004 | |||
| 1005 | protected static function findBestL10NOption(array $options, string $lang): string { |
||
| 1049 | |||
| 1050 | /** |
||
| 1051 | * parses the app data array and enhanced the 'description' value |
||
| 1052 | * |
||
| 1053 | * @param array $data the app data |
||
| 1054 | * @param string $lang |
||
| 1055 | * @return array improved app data |
||
| 1056 | */ |
||
| 1057 | public static function parseAppInfo(array $data, $lang = null): array { |
||
| 1075 | |||
| 1076 | /** |
||
| 1077 | * @param \OCP\IConfig $config |
||
| 1078 | * @param \OCP\IL10N $l |
||
| 1079 | * @param array $info |
||
| 1080 | * @throws \Exception |
||
| 1081 | */ |
||
| 1082 | public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info) { |
||
| 1094 | } |
||
| 1095 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.