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 | self::disable($app); |
||
| 158 | } |
||
| 159 | } |
||
| 160 | if (self::isType($app, array('authentication'))) { |
||
| 161 | // since authentication apps affect the "is app enabled for group" check, |
||
| 162 | // the enabled apps cache needs to be cleared to make sure that the |
||
| 163 | // next time getEnableApps() is called it will also include apps that were |
||
| 164 | // enabled for groups |
||
| 165 | self::$enabledAppsCache = []; |
||
| 166 | } |
||
| 167 | \OC::$server->getEventLogger()->end('load_app_' . $app); |
||
| 168 | } |
||
| 169 | |||
| 170 | $info = self::getAppInfo($app); |
||
| 171 | View Code Duplication | if (!empty($info['activity']['filters'])) { |
|
| 172 | foreach ($info['activity']['filters'] as $filter) { |
||
| 173 | \OC::$server->getActivityManager()->registerFilter($filter); |
||
| 174 | } |
||
| 175 | } |
||
| 176 | View Code Duplication | if (!empty($info['activity']['settings'])) { |
|
| 177 | foreach ($info['activity']['settings'] as $setting) { |
||
| 178 | \OC::$server->getActivityManager()->registerSetting($setting); |
||
| 179 | } |
||
| 180 | } |
||
| 181 | View Code Duplication | if (!empty($info['activity']['providers'])) { |
|
| 182 | foreach ($info['activity']['providers'] as $provider) { |
||
| 183 | \OC::$server->getActivityManager()->registerProvider($provider); |
||
| 184 | } |
||
| 185 | } |
||
| 186 | |||
| 187 | View Code Duplication | if (!empty($info['settings']['admin'])) { |
|
| 188 | foreach ($info['settings']['admin'] as $setting) { |
||
| 189 | \OC::$server->getSettingsManager()->registerSetting('admin', $setting); |
||
| 190 | } |
||
| 191 | } |
||
| 192 | if (!empty($info['settings']['admin-section'])) { |
||
| 193 | foreach ($info['settings']['admin-section'] as $section) { |
||
| 194 | \OC::$server->getSettingsManager()->registerSection('admin', $section); |
||
| 195 | } |
||
| 196 | } |
||
| 197 | if (!empty($info['settings']['personal'])) { |
||
| 198 | foreach ($info['settings']['personal'] as $setting) { |
||
| 199 | \OC::$server->getSettingsManager()->registerSetting('personal', $setting); |
||
| 200 | } |
||
| 201 | } |
||
| 202 | if (!empty($info['settings']['personal-section'])) { |
||
| 203 | foreach ($info['settings']['personal-section'] as $section) { |
||
| 204 | \OC::$server->getSettingsManager()->registerSection('personal', $section); |
||
| 205 | } |
||
| 206 | } |
||
| 207 | |||
| 208 | if (!empty($info['collaboration']['plugins'])) { |
||
| 209 | // deal with one or many plugin entries |
||
| 210 | $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ? |
||
| 211 | [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin']; |
||
| 212 | foreach ($plugins as $plugin) { |
||
| 213 | if($plugin['@attributes']['type'] === 'collaborator-search') { |
||
| 214 | $pluginInfo = [ |
||
| 215 | 'shareType' => $plugin['@attributes']['share-type'], |
||
| 216 | 'class' => $plugin['@value'], |
||
| 217 | ]; |
||
| 218 | \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo); |
||
| 219 | } else if ($plugin['@attributes']['type'] === 'autocomplete-sort') { |
||
| 220 | \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']); |
||
| 221 | } |
||
| 222 | } |
||
| 223 | } |
||
| 224 | } |
||
| 225 | |||
| 226 | /** |
||
| 227 | * @internal |
||
| 228 | * @param string $app |
||
| 229 | * @param string $path |
||
| 230 | */ |
||
| 231 | public static function registerAutoloading(string $app, string $path) { |
||
| 232 | $key = $app . '-' . $path; |
||
| 233 | if(isset(self::$alreadyRegistered[$key])) { |
||
| 234 | return; |
||
| 235 | } |
||
| 236 | |||
| 237 | self::$alreadyRegistered[$key] = true; |
||
| 238 | |||
| 239 | // Register on PSR-4 composer autoloader |
||
| 240 | $appNamespace = \OC\AppFramework\App::buildAppNamespace($app); |
||
| 241 | \OC::$server->registerNamespace($app, $appNamespace); |
||
| 242 | |||
| 243 | if (file_exists($path . '/composer/autoload.php')) { |
||
| 244 | require_once $path . '/composer/autoload.php'; |
||
| 245 | } else { |
||
| 246 | \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true); |
||
| 247 | // Register on legacy autoloader |
||
| 248 | \OC::$loader->addValidRoot($path); |
||
| 249 | } |
||
| 250 | |||
| 251 | // Register Test namespace only when testing |
||
| 252 | if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) { |
||
| 253 | \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true); |
||
| 254 | } |
||
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Load app.php from the given app |
||
| 259 | * |
||
| 260 | * @param string $app app name |
||
| 261 | * @throws Error |
||
| 262 | */ |
||
| 263 | private static function requireAppFile(string $app) { |
||
| 264 | // encapsulated here to avoid variable scope conflicts |
||
| 265 | require_once $app . '/appinfo/app.php'; |
||
| 266 | } |
||
| 267 | |||
| 268 | /** |
||
| 269 | * check if an app is of a specific type |
||
| 270 | * |
||
| 271 | * @param string $app |
||
| 272 | * @param array $types |
||
| 273 | * @return bool |
||
| 274 | */ |
||
| 275 | public static function isType(string $app, array $types): bool { |
||
| 276 | $appTypes = self::getAppTypes($app); |
||
| 277 | foreach ($types as $type) { |
||
| 278 | if (array_search($type, $appTypes) !== false) { |
||
| 279 | return true; |
||
| 280 | } |
||
| 281 | } |
||
| 282 | return false; |
||
| 283 | } |
||
| 284 | |||
| 285 | /** |
||
| 286 | * get the types of an app |
||
| 287 | * |
||
| 288 | * @param string $app |
||
| 289 | * @return array |
||
| 290 | */ |
||
| 291 | private static function getAppTypes(string $app): array { |
||
| 292 | //load the cache |
||
| 293 | if (count(self::$appTypes) == 0) { |
||
| 294 | self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types'); |
||
| 295 | } |
||
| 296 | |||
| 297 | if (isset(self::$appTypes[$app])) { |
||
| 298 | return explode(',', self::$appTypes[$app]); |
||
| 299 | } |
||
| 300 | |||
| 301 | return []; |
||
| 302 | } |
||
| 303 | |||
| 304 | /** |
||
| 305 | * read app types from info.xml and cache them in the database |
||
| 306 | */ |
||
| 307 | public static function setAppTypes(string $app) { |
||
| 308 | $appManager = \OC::$server->getAppManager(); |
||
| 309 | $appData = $appManager->getAppInfo($app); |
||
| 310 | if(!is_array($appData)) { |
||
| 311 | return; |
||
| 312 | } |
||
| 313 | |||
| 314 | if (isset($appData['types'])) { |
||
| 315 | $appTypes = implode(',', $appData['types']); |
||
| 316 | } else { |
||
| 317 | $appTypes = ''; |
||
| 318 | $appData['types'] = []; |
||
| 319 | } |
||
| 320 | |||
| 321 | $config = \OC::$server->getConfig(); |
||
| 322 | $config->setAppValue($app, 'types', $appTypes); |
||
| 323 | |||
| 324 | if ($appManager->hasProtectedAppType($appData['types'])) { |
||
| 325 | $enabled = $config->getAppValue($app, 'enabled', 'yes'); |
||
| 326 | if ($enabled !== 'yes' && $enabled !== 'no') { |
||
| 327 | $config->setAppValue($app, 'enabled', 'yes'); |
||
| 328 | } |
||
| 329 | } |
||
| 330 | } |
||
| 331 | |||
| 332 | /** |
||
| 333 | * get all enabled apps |
||
| 334 | */ |
||
| 335 | protected static $enabledAppsCache = []; |
||
| 336 | |||
| 337 | /** |
||
| 338 | * Returns apps enabled for the current user. |
||
| 339 | * |
||
| 340 | * @param bool $forceRefresh whether to refresh the cache |
||
| 341 | * @param bool $all whether to return apps for all users, not only the |
||
| 342 | * currently logged in one |
||
| 343 | * @return string[] |
||
| 344 | */ |
||
| 345 | public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array { |
||
| 346 | if (!\OC::$server->getSystemConfig()->getValue('installed', false)) { |
||
| 347 | return []; |
||
| 348 | } |
||
| 349 | // in incognito mode or when logged out, $user will be false, |
||
| 350 | // which is also the case during an upgrade |
||
| 351 | $appManager = \OC::$server->getAppManager(); |
||
| 352 | if ($all) { |
||
| 353 | $user = null; |
||
| 354 | } else { |
||
| 355 | $user = \OC::$server->getUserSession()->getUser(); |
||
| 356 | } |
||
| 357 | |||
| 358 | if (is_null($user)) { |
||
| 359 | $apps = $appManager->getInstalledApps(); |
||
| 360 | } else { |
||
| 361 | $apps = $appManager->getEnabledAppsForUser($user); |
||
| 362 | } |
||
| 363 | $apps = array_filter($apps, function ($app) { |
||
| 364 | return $app !== 'files';//we add this manually |
||
| 365 | }); |
||
| 366 | sort($apps); |
||
| 367 | array_unshift($apps, 'files'); |
||
| 368 | return $apps; |
||
| 369 | } |
||
| 370 | |||
| 371 | /** |
||
| 372 | * checks whether or not an app is enabled |
||
| 373 | * |
||
| 374 | * @param string $app app |
||
| 375 | * @return bool |
||
| 376 | * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId) |
||
| 377 | * |
||
| 378 | * This function checks whether or not an app is enabled. |
||
| 379 | */ |
||
| 380 | public static function isEnabled(string $app): bool { |
||
| 381 | return \OC::$server->getAppManager()->isEnabledForUser($app); |
||
| 382 | } |
||
| 383 | |||
| 384 | /** |
||
| 385 | * enables an app |
||
| 386 | * |
||
| 387 | * @param string $appId |
||
| 388 | * @param array $groups (optional) when set, only these groups will have access to the app |
||
| 389 | * @throws \Exception |
||
| 390 | * @return void |
||
| 391 | * |
||
| 392 | * This function set an app as enabled in appconfig. |
||
| 393 | */ |
||
| 394 | public function enable(string $appId, |
||
| 395 | array $groups = []) { |
||
| 396 | self::$enabledAppsCache = []; // flush |
||
| 397 | |||
| 398 | // Check if app is already downloaded |
||
| 399 | $installer = \OC::$server->query(Installer::class); |
||
| 400 | $isDownloaded = $installer->isDownloaded($appId); |
||
| 401 | |||
| 402 | if(!$isDownloaded) { |
||
| 403 | $installer->downloadApp($appId); |
||
| 404 | } |
||
| 405 | |||
| 406 | $installer->installApp($appId); |
||
| 407 | |||
| 408 | $appManager = \OC::$server->getAppManager(); |
||
| 409 | if ($groups !== []) { |
||
| 410 | $groupManager = \OC::$server->getGroupManager(); |
||
| 411 | $groupsList = []; |
||
| 412 | foreach ($groups as $group) { |
||
| 413 | $groupItem = $groupManager->get($group); |
||
| 414 | if ($groupItem instanceof \OCP\IGroup) { |
||
| 415 | $groupsList[] = $groupManager->get($group); |
||
| 416 | } |
||
| 417 | } |
||
| 418 | $appManager->enableAppForGroups($appId, $groupsList); |
||
| 419 | } else { |
||
| 420 | $appManager->enableApp($appId); |
||
| 421 | } |
||
| 422 | } |
||
| 423 | |||
| 424 | /** |
||
| 425 | * This function set an app as disabled in appconfig. |
||
| 426 | * |
||
| 427 | * @param string $app app |
||
| 428 | * @throws Exception |
||
| 429 | */ |
||
| 430 | public static function disable(string $app) { |
||
| 447 | |||
| 448 | /** |
||
| 449 | * Get the path where to install apps |
||
| 450 | * |
||
| 451 | * @return string|false |
||
| 452 | */ |
||
| 453 | public static function getInstallPath() { |
||
| 454 | if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) { |
||
| 455 | return false; |
||
| 456 | } |
||
| 457 | |||
| 458 | foreach (OC::$APPSROOTS as $dir) { |
||
| 459 | if (isset($dir['writable']) && $dir['writable'] === true) { |
||
| 460 | return $dir['path']; |
||
| 461 | } |
||
| 462 | } |
||
| 463 | |||
| 464 | \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR); |
||
| 465 | return null; |
||
| 466 | } |
||
| 467 | |||
| 468 | |||
| 469 | /** |
||
| 470 | * search for an app in all app-directories |
||
| 471 | * |
||
| 472 | * @param string $appId |
||
| 473 | * @return false|string |
||
| 474 | */ |
||
| 475 | public static function findAppInDirectories(string $appId) { |
||
| 476 | $sanitizedAppId = self::cleanAppId($appId); |
||
| 477 | if($sanitizedAppId !== $appId) { |
||
| 478 | return false; |
||
| 479 | } |
||
| 480 | static $app_dir = []; |
||
| 481 | |||
| 482 | if (isset($app_dir[$appId])) { |
||
| 483 | return $app_dir[$appId]; |
||
| 484 | } |
||
| 485 | |||
| 486 | $possibleApps = []; |
||
| 487 | foreach (OC::$APPSROOTS as $dir) { |
||
| 488 | if (file_exists($dir['path'] . '/' . $appId)) { |
||
| 489 | $possibleApps[] = $dir; |
||
| 490 | } |
||
| 491 | } |
||
| 492 | |||
| 493 | if (empty($possibleApps)) { |
||
| 494 | return false; |
||
| 495 | } elseif (count($possibleApps) === 1) { |
||
| 496 | $dir = array_shift($possibleApps); |
||
| 497 | $app_dir[$appId] = $dir; |
||
| 498 | return $dir; |
||
| 499 | } else { |
||
| 500 | $versionToLoad = []; |
||
| 501 | foreach ($possibleApps as $possibleApp) { |
||
| 502 | $version = self::getAppVersionByPath($possibleApp['path']); |
||
| 503 | if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) { |
||
| 504 | $versionToLoad = array( |
||
| 505 | 'dir' => $possibleApp, |
||
| 506 | 'version' => $version, |
||
| 507 | ); |
||
| 508 | } |
||
| 509 | } |
||
| 510 | $app_dir[$appId] = $versionToLoad['dir']; |
||
| 511 | return $versionToLoad['dir']; |
||
| 512 | //TODO - write test |
||
| 513 | } |
||
| 514 | } |
||
| 515 | |||
| 516 | /** |
||
| 517 | * Get the directory for the given app. |
||
| 518 | * If the app is defined in multiple directories, the first one is taken. (false if not found) |
||
| 519 | * |
||
| 520 | * @param string $appId |
||
| 521 | * @return string|false |
||
| 522 | */ |
||
| 523 | public static function getAppPath(string $appId) { |
||
| 524 | if ($appId === null || trim($appId) === '') { |
||
| 525 | return false; |
||
| 526 | } |
||
| 527 | |||
| 528 | if (($dir = self::findAppInDirectories($appId)) != false) { |
||
| 529 | return $dir['path'] . '/' . $appId; |
||
| 530 | } |
||
| 531 | return false; |
||
| 532 | } |
||
| 533 | |||
| 534 | /** |
||
| 535 | * Get the path for the given app on the access |
||
| 536 | * If the app is defined in multiple directories, the first one is taken. (false if not found) |
||
| 537 | * |
||
| 538 | * @param string $appId |
||
| 539 | * @return string|false |
||
| 540 | */ |
||
| 541 | public static function getAppWebPath(string $appId) { |
||
| 542 | if (($dir = self::findAppInDirectories($appId)) != false) { |
||
| 543 | return OC::$WEBROOT . $dir['url'] . '/' . $appId; |
||
| 544 | } |
||
| 545 | return false; |
||
| 546 | } |
||
| 547 | |||
| 548 | /** |
||
| 549 | * get the last version of the app from appinfo/info.xml |
||
| 550 | * |
||
| 551 | * @param string $appId |
||
| 552 | * @param bool $useCache |
||
| 553 | * @return string |
||
| 554 | * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion() |
||
| 555 | */ |
||
| 556 | public static function getAppVersion(string $appId, bool $useCache = true): string { |
||
| 557 | return \OC::$server->getAppManager()->getAppVersion($appId, $useCache); |
||
| 558 | } |
||
| 559 | |||
| 560 | /** |
||
| 561 | * get app's version based on it's path |
||
| 562 | * |
||
| 563 | * @param string $path |
||
| 564 | * @return string |
||
| 565 | */ |
||
| 566 | public static function getAppVersionByPath(string $path): string { |
||
| 567 | $infoFile = $path . '/appinfo/info.xml'; |
||
| 568 | $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true); |
||
| 569 | return isset($appData['version']) ? $appData['version'] : ''; |
||
| 570 | } |
||
| 571 | |||
| 572 | |||
| 573 | /** |
||
| 574 | * Read all app metadata from the info.xml file |
||
| 575 | * |
||
| 576 | * @param string $appId id of the app or the path of the info.xml file |
||
| 577 | * @param bool $path |
||
| 578 | * @param string $lang |
||
| 579 | * @return array|null |
||
| 580 | * @note all data is read from info.xml, not just pre-defined fields |
||
| 581 | * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo() |
||
| 582 | */ |
||
| 583 | public static function getAppInfo(string $appId, bool $path = false, string $lang = null) { |
||
| 584 | return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang); |
||
| 585 | } |
||
| 586 | |||
| 587 | /** |
||
| 588 | * Returns the navigation |
||
| 589 | * |
||
| 590 | * @return array |
||
| 591 | * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll() |
||
| 592 | * |
||
| 593 | * This function returns an array containing all entries added. The |
||
| 594 | * entries are sorted by the key 'order' ascending. Additional to the keys |
||
| 595 | * given for each app the following keys exist: |
||
| 596 | * - active: boolean, signals if the user is on this navigation entry |
||
| 597 | */ |
||
| 598 | public static function getNavigation(): array { |
||
| 599 | return OC::$server->getNavigationManager()->getAll(); |
||
| 600 | } |
||
| 601 | |||
| 602 | /** |
||
| 603 | * Returns the Settings Navigation |
||
| 604 | * |
||
| 605 | * @return string[] |
||
| 606 | * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings') |
||
| 607 | * |
||
| 608 | * This function returns an array containing all settings pages added. The |
||
| 609 | * entries are sorted by the key 'order' ascending. |
||
| 610 | */ |
||
| 611 | public static function getSettingsNavigation(): array { |
||
| 612 | return OC::$server->getNavigationManager()->getAll('settings'); |
||
| 613 | } |
||
| 614 | |||
| 615 | /** |
||
| 616 | * get the id of loaded app |
||
| 617 | * |
||
| 618 | * @return string |
||
| 619 | */ |
||
| 620 | public static function getCurrentApp(): string { |
||
| 621 | $request = \OC::$server->getRequest(); |
||
| 622 | $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1); |
||
| 623 | $topFolder = substr($script, 0, strpos($script, '/') ?: 0); |
||
| 624 | if (empty($topFolder)) { |
||
| 625 | $path_info = $request->getPathInfo(); |
||
| 626 | if ($path_info) { |
||
| 627 | $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1); |
||
| 628 | } |
||
| 629 | } |
||
| 630 | if ($topFolder == 'apps') { |
||
| 631 | $length = strlen($topFolder); |
||
| 632 | return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: ''; |
||
| 633 | } else { |
||
| 634 | return $topFolder; |
||
| 635 | } |
||
| 636 | } |
||
| 637 | |||
| 638 | /** |
||
| 639 | * @param string $type |
||
| 640 | * @return array |
||
| 641 | */ |
||
| 642 | public static function getForms(string $type): array { |
||
| 643 | $forms = []; |
||
| 644 | switch ($type) { |
||
| 645 | case 'admin': |
||
| 646 | $source = self::$adminForms; |
||
| 647 | break; |
||
| 648 | case 'personal': |
||
| 649 | $source = self::$personalForms; |
||
| 650 | break; |
||
| 651 | default: |
||
| 652 | return []; |
||
| 653 | } |
||
| 654 | foreach ($source as $form) { |
||
| 655 | $forms[] = include $form; |
||
| 656 | } |
||
| 657 | return $forms; |
||
| 658 | } |
||
| 659 | |||
| 660 | /** |
||
| 661 | * register an admin form to be shown |
||
| 662 | * |
||
| 663 | * @param string $app |
||
| 664 | * @param string $page |
||
| 665 | */ |
||
| 666 | public static function registerAdmin(string $app, string $page) { |
||
| 667 | self::$adminForms[] = $app . '/' . $page . '.php'; |
||
| 668 | } |
||
| 669 | |||
| 670 | /** |
||
| 671 | * register a personal form to be shown |
||
| 672 | * @param string $app |
||
| 673 | * @param string $page |
||
| 674 | */ |
||
| 675 | public static function registerPersonal(string $app, string $page) { |
||
| 676 | self::$personalForms[] = $app . '/' . $page . '.php'; |
||
| 677 | } |
||
| 678 | |||
| 679 | /** |
||
| 680 | * @param array $entry |
||
| 681 | */ |
||
| 682 | public static function registerLogIn(array $entry) { |
||
| 683 | self::$altLogin[] = $entry; |
||
| 684 | } |
||
| 685 | |||
| 686 | /** |
||
| 687 | * @return array |
||
| 688 | */ |
||
| 689 | public static function getAlternativeLogIns(): array { |
||
| 690 | return self::$altLogin; |
||
| 691 | } |
||
| 692 | |||
| 693 | /** |
||
| 694 | * get a list of all apps in the apps folder |
||
| 695 | * |
||
| 696 | * @return array an array of app names (string IDs) |
||
| 697 | * @todo: change the name of this method to getInstalledApps, which is more accurate |
||
| 698 | */ |
||
| 699 | public static function getAllApps(): array { |
||
| 700 | |||
| 701 | $apps = []; |
||
| 702 | |||
| 703 | foreach (OC::$APPSROOTS as $apps_dir) { |
||
| 704 | if (!is_readable($apps_dir['path'])) { |
||
| 705 | \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN); |
||
| 706 | continue; |
||
| 707 | } |
||
| 708 | $dh = opendir($apps_dir['path']); |
||
| 709 | |||
| 710 | if (is_resource($dh)) { |
||
| 711 | while (($file = readdir($dh)) !== false) { |
||
| 712 | |||
| 713 | if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) { |
||
| 714 | |||
| 715 | $apps[] = $file; |
||
| 716 | } |
||
| 717 | } |
||
| 718 | } |
||
| 719 | } |
||
| 720 | |||
| 721 | $apps = array_unique($apps); |
||
| 722 | |||
| 723 | return $apps; |
||
| 724 | } |
||
| 725 | |||
| 726 | /** |
||
| 727 | * List all apps, this is used in apps.php |
||
| 728 | * |
||
| 729 | * @return array |
||
| 730 | */ |
||
| 731 | public function listAllApps(): array { |
||
| 732 | $installedApps = OC_App::getAllApps(); |
||
| 733 | |||
| 734 | $appManager = \OC::$server->getAppManager(); |
||
| 735 | //we don't want to show configuration for these |
||
| 736 | $blacklist = $appManager->getAlwaysEnabledApps(); |
||
| 737 | $appList = []; |
||
| 738 | $langCode = \OC::$server->getL10N('core')->getLanguageCode(); |
||
| 739 | $urlGenerator = \OC::$server->getURLGenerator(); |
||
| 740 | |||
| 741 | foreach ($installedApps as $app) { |
||
| 742 | if (array_search($app, $blacklist) === false) { |
||
| 743 | |||
| 744 | $info = OC_App::getAppInfo($app, false, $langCode); |
||
| 745 | if (!is_array($info)) { |
||
| 746 | \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR); |
||
| 747 | continue; |
||
| 748 | } |
||
| 749 | |||
| 750 | if (!isset($info['name'])) { |
||
| 751 | \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR); |
||
| 752 | continue; |
||
| 753 | } |
||
| 754 | |||
| 755 | $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no'); |
||
| 756 | $info['groups'] = null; |
||
| 757 | if ($enabled === 'yes') { |
||
| 758 | $active = true; |
||
| 759 | } else if ($enabled === 'no') { |
||
| 760 | $active = false; |
||
| 761 | } else { |
||
| 762 | $active = true; |
||
| 763 | $info['groups'] = $enabled; |
||
| 764 | } |
||
| 765 | |||
| 766 | $info['active'] = $active; |
||
| 767 | |||
| 768 | if ($appManager->isShipped($app)) { |
||
| 769 | $info['internal'] = true; |
||
| 770 | $info['level'] = self::officialApp; |
||
| 771 | $info['removable'] = false; |
||
| 772 | } else { |
||
| 773 | $info['internal'] = false; |
||
| 774 | $info['removable'] = true; |
||
| 775 | } |
||
| 776 | |||
| 777 | $appPath = self::getAppPath($app); |
||
| 778 | if($appPath !== false) { |
||
| 779 | $appIcon = $appPath . '/img/' . $app . '.svg'; |
||
| 780 | if (file_exists($appIcon)) { |
||
| 781 | $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg'); |
||
| 782 | $info['previewAsIcon'] = true; |
||
| 783 | } else { |
||
| 784 | $appIcon = $appPath . '/img/app.svg'; |
||
| 785 | if (file_exists($appIcon)) { |
||
| 786 | $info['preview'] = $urlGenerator->imagePath($app, 'app.svg'); |
||
| 787 | $info['previewAsIcon'] = true; |
||
| 788 | } |
||
| 789 | } |
||
| 790 | } |
||
| 791 | // fix documentation |
||
| 792 | if (isset($info['documentation']) && is_array($info['documentation'])) { |
||
| 793 | foreach ($info['documentation'] as $key => $url) { |
||
| 794 | // If it is not an absolute URL we assume it is a key |
||
| 795 | // i.e. admin-ldap will get converted to go.php?to=admin-ldap |
||
| 796 | if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) { |
||
| 797 | $url = $urlGenerator->linkToDocs($url); |
||
| 798 | } |
||
| 799 | |||
| 800 | $info['documentation'][$key] = $url; |
||
| 801 | } |
||
| 802 | } |
||
| 803 | |||
| 804 | $info['version'] = OC_App::getAppVersion($app); |
||
| 805 | $appList[] = $info; |
||
| 806 | } |
||
| 807 | } |
||
| 808 | |||
| 809 | return $appList; |
||
| 810 | } |
||
| 811 | |||
| 812 | public static function shouldUpgrade(string $app): bool { |
||
| 813 | $versions = self::getAppVersions(); |
||
| 814 | $currentVersion = OC_App::getAppVersion($app); |
||
| 815 | if ($currentVersion && isset($versions[$app])) { |
||
| 816 | $installedVersion = $versions[$app]; |
||
| 817 | if (!version_compare($currentVersion, $installedVersion, '=')) { |
||
| 818 | return true; |
||
| 819 | } |
||
| 820 | } |
||
| 821 | return false; |
||
| 822 | } |
||
| 823 | |||
| 824 | /** |
||
| 825 | * Adjust the number of version parts of $version1 to match |
||
| 826 | * the number of version parts of $version2. |
||
| 827 | * |
||
| 828 | * @param string $version1 version to adjust |
||
| 829 | * @param string $version2 version to take the number of parts from |
||
| 830 | * @return string shortened $version1 |
||
| 831 | */ |
||
| 832 | private static function adjustVersionParts(string $version1, string $version2): string { |
||
| 833 | $version1 = explode('.', $version1); |
||
| 834 | $version2 = explode('.', $version2); |
||
| 835 | // reduce $version1 to match the number of parts in $version2 |
||
| 836 | while (count($version1) > count($version2)) { |
||
| 837 | array_pop($version1); |
||
| 838 | } |
||
| 839 | // if $version1 does not have enough parts, add some |
||
| 840 | while (count($version1) < count($version2)) { |
||
| 841 | $version1[] = '0'; |
||
| 842 | } |
||
| 843 | return implode('.', $version1); |
||
| 844 | } |
||
| 845 | |||
| 846 | /** |
||
| 847 | * Check whether the current ownCloud version matches the given |
||
| 848 | * application's version requirements. |
||
| 849 | * |
||
| 850 | * The comparison is made based on the number of parts that the |
||
| 851 | * app info version has. For example for ownCloud 6.0.3 if the |
||
| 852 | * app info version is expecting version 6.0, the comparison is |
||
| 853 | * made on the first two parts of the ownCloud version. |
||
| 854 | * This means that it's possible to specify "requiremin" => 6 |
||
| 855 | * and "requiremax" => 6 and it will still match ownCloud 6.0.3. |
||
| 856 | * |
||
| 857 | * @param string $ocVersion ownCloud version to check against |
||
| 858 | * @param array $appInfo app info (from xml) |
||
| 859 | * |
||
| 860 | * @return boolean true if compatible, otherwise false |
||
| 861 | */ |
||
| 862 | public static function isAppCompatible(string $ocVersion, array $appInfo): bool { |
||
| 863 | $requireMin = ''; |
||
| 864 | $requireMax = ''; |
||
| 865 | if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) { |
||
| 866 | $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version']; |
||
| 867 | View Code Duplication | } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) { |
|
| 868 | $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version']; |
||
| 869 | } else if (isset($appInfo['requiremin'])) { |
||
| 870 | $requireMin = $appInfo['requiremin']; |
||
| 871 | } else if (isset($appInfo['require'])) { |
||
| 872 | $requireMin = $appInfo['require']; |
||
| 873 | } |
||
| 874 | |||
| 875 | if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) { |
||
| 876 | $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version']; |
||
| 877 | View Code Duplication | } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) { |
|
| 878 | $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version']; |
||
| 879 | } else if (isset($appInfo['requiremax'])) { |
||
| 880 | $requireMax = $appInfo['requiremax']; |
||
| 881 | } |
||
| 882 | |||
| 883 | View Code Duplication | if (!empty($requireMin) |
|
| 884 | && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<') |
||
| 885 | ) { |
||
| 886 | |||
| 887 | return false; |
||
| 888 | } |
||
| 889 | |||
| 890 | View Code Duplication | if (!empty($requireMax) |
|
| 891 | && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>') |
||
| 892 | ) { |
||
| 893 | return false; |
||
| 894 | } |
||
| 895 | |||
| 896 | return true; |
||
| 897 | } |
||
| 898 | |||
| 899 | /** |
||
| 900 | * get the installed version of all apps |
||
| 901 | */ |
||
| 902 | public static function getAppVersions() { |
||
| 911 | |||
| 912 | /** |
||
| 913 | * update the database for the app and call the update script |
||
| 914 | * |
||
| 915 | * @param string $appId |
||
| 916 | * @return bool |
||
| 917 | */ |
||
| 918 | public static function updateApp(sstring $appId): bool { |
||
| 971 | |||
| 972 | /** |
||
| 973 | * @param string $appId |
||
| 974 | * @param string[] $steps |
||
| 975 | * @throws \OC\NeedsUpdateException |
||
| 976 | */ |
||
| 977 | public static function executeRepairSteps(string $appId, array $steps) { |
||
| 999 | |||
| 1000 | public static function setupBackgroundJobs(array $jobs) { |
||
| 1006 | |||
| 1007 | /** |
||
| 1008 | * @param string $appId |
||
| 1009 | * @param string[] $steps |
||
| 1010 | */ |
||
| 1011 | private static function setupLiveMigrations(string $appId, array $steps) { |
||
| 1019 | |||
| 1020 | /** |
||
| 1021 | * @param string $appId |
||
| 1022 | * @return \OC\Files\View|false |
||
| 1023 | */ |
||
| 1024 | public static function getStorage(string $appId) { |
||
| 1041 | |||
| 1042 | protected static function findBestL10NOption(array $options, string $lang): string { |
||
| 1086 | |||
| 1087 | /** |
||
| 1088 | * parses the app data array and enhanced the 'description' value |
||
| 1089 | * |
||
| 1090 | * @param array $data the app data |
||
| 1091 | * @param string $lang |
||
| 1092 | * @return array improved app data |
||
| 1093 | */ |
||
| 1094 | public static function parseAppInfo(array $data, $lang = null): array { |
||
| 1112 | |||
| 1113 | /** |
||
| 1114 | * @param \OCP\IConfig $config |
||
| 1115 | * @param \OCP\IL10N $l |
||
| 1116 | * @param array $info |
||
| 1117 | * @throws \Exception |
||
| 1118 | */ |
||
| 1119 | public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info) { |
||
| 1131 | } |
||
| 1132 |
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.