Total Complexity | 73 |
Total Lines | 554 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Installer 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.
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 Installer, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
54 | class Installer { |
||
55 | /** @var AppFetcher */ |
||
56 | private $appFetcher; |
||
57 | /** @var IClientService */ |
||
58 | private $clientService; |
||
59 | /** @var ITempManager */ |
||
60 | private $tempManager; |
||
61 | /** @var ILogger */ |
||
62 | private $logger; |
||
63 | /** @var IConfig */ |
||
64 | private $config; |
||
65 | /** @var array - for caching the result of app fetcher */ |
||
66 | private $apps = null; |
||
67 | /** @var bool|null - for caching the result of the ready status */ |
||
68 | private $isInstanceReadyForUpdates = null; |
||
69 | |||
70 | /** |
||
71 | * @param AppFetcher $appFetcher |
||
72 | * @param IClientService $clientService |
||
73 | * @param ITempManager $tempManager |
||
74 | * @param ILogger $logger |
||
75 | * @param IConfig $config |
||
76 | */ |
||
77 | public function __construct(AppFetcher $appFetcher, |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * Installs an app that is located in one of the app folders already |
||
91 | * |
||
92 | * @param string $appId App to install |
||
93 | * @throws \Exception |
||
94 | * @return string app ID |
||
95 | */ |
||
96 | public function installApp($appId) { |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Updates the specified app from the appstore |
||
171 | * |
||
172 | * @param string $appId |
||
173 | * @return bool |
||
174 | */ |
||
175 | public function updateAppstoreApp($appId) { |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Downloads an app and puts it into the app directory |
||
194 | * |
||
195 | * @param string $appId |
||
196 | * |
||
197 | * @throws \Exception If the installation was not successful |
||
198 | */ |
||
199 | public function downloadApp($appId) { |
||
359 | ) |
||
360 | ); |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * Check if an update for the app is available |
||
365 | * |
||
366 | * @param string $appId |
||
367 | * @return string|false false or the version number of the update |
||
368 | */ |
||
369 | public function isUpdateAvailable($appId) { |
||
370 | if ($this->isInstanceReadyForUpdates === null) { |
||
371 | $installPath = OC_App::getInstallPath(); |
||
372 | if ($installPath === false || $installPath === null) { |
||
373 | $this->isInstanceReadyForUpdates = false; |
||
374 | } else { |
||
375 | $this->isInstanceReadyForUpdates = true; |
||
376 | } |
||
377 | } |
||
378 | |||
379 | if ($this->isInstanceReadyForUpdates === false) { |
||
380 | return false; |
||
381 | } |
||
382 | |||
383 | if ($this->isInstalledFromGit($appId) === true) { |
||
384 | return false; |
||
385 | } |
||
386 | |||
387 | if ($this->apps === null) { |
||
388 | $this->apps = $this->appFetcher->get(); |
||
389 | } |
||
390 | |||
391 | foreach($this->apps as $app) { |
||
392 | if($app['id'] === $appId) { |
||
393 | $currentVersion = OC_App::getAppVersion($appId); |
||
394 | |||
395 | if (!isset($app['releases'][0]['version'])) { |
||
396 | return false; |
||
397 | } |
||
398 | $newestVersion = $app['releases'][0]['version']; |
||
399 | if ($currentVersion !== '0' && version_compare($newestVersion, $currentVersion, '>')) { |
||
400 | return $newestVersion; |
||
401 | } else { |
||
402 | return false; |
||
403 | } |
||
404 | } |
||
405 | } |
||
406 | |||
407 | return false; |
||
408 | } |
||
409 | |||
410 | /** |
||
411 | * Check if app has been installed from git |
||
412 | * @param string $name name of the application to remove |
||
413 | * @return boolean |
||
414 | * |
||
415 | * The function will check if the path contains a .git folder |
||
416 | */ |
||
417 | private function isInstalledFromGit($appId) { |
||
418 | $app = \OC_App::findAppInDirectories($appId); |
||
419 | if($app === false) { |
||
420 | return false; |
||
421 | } |
||
422 | $basedir = $app['path'].'/'.$appId; |
||
423 | return file_exists($basedir.'/.git/'); |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * Check if app is already downloaded |
||
428 | * @param string $name name of the application to remove |
||
429 | * @return boolean |
||
430 | * |
||
431 | * The function will check if the app is already downloaded in the apps repository |
||
432 | */ |
||
433 | public function isDownloaded($name) { |
||
446 | } |
||
447 | |||
448 | /** |
||
449 | * Removes an app |
||
450 | * @param string $appId ID of the application to remove |
||
451 | * @return boolean |
||
452 | * |
||
453 | * |
||
454 | * This function works as follows |
||
455 | * -# call uninstall repair steps |
||
456 | * -# removing the files |
||
457 | * |
||
458 | * The function will not delete preferences, tables and the configuration, |
||
459 | * this has to be done by the function oc_app_uninstall(). |
||
460 | */ |
||
461 | public function removeApp($appId) { |
||
462 | if($this->isDownloaded( $appId )) { |
||
463 | if (\OC::$server->getAppManager()->isShipped($appId)) { |
||
464 | return false; |
||
465 | } |
||
466 | $appDir = OC_App::getInstallPath() . '/' . $appId; |
||
467 | OC_Helper::rmdirr($appDir); |
||
468 | return true; |
||
469 | }else{ |
||
470 | \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', ILogger::ERROR); |
||
471 | |||
472 | return false; |
||
473 | } |
||
474 | |||
475 | } |
||
476 | |||
477 | /** |
||
478 | * Installs the app within the bundle and marks the bundle as installed |
||
479 | * |
||
480 | * @param Bundle $bundle |
||
481 | * @throws \Exception If app could not get installed |
||
482 | */ |
||
483 | public function installAppBundle(Bundle $bundle) { |
||
484 | $appIds = $bundle->getAppIdentifiers(); |
||
485 | foreach($appIds as $appId) { |
||
486 | if(!$this->isDownloaded($appId)) { |
||
487 | $this->downloadApp($appId); |
||
488 | } |
||
489 | $this->installApp($appId); |
||
490 | $app = new OC_App(); |
||
491 | $app->enable($appId); |
||
492 | } |
||
493 | $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true); |
||
494 | $bundles[] = $bundle->getIdentifier(); |
||
495 | $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles)); |
||
496 | } |
||
497 | |||
498 | /** |
||
499 | * Installs shipped apps |
||
500 | * |
||
501 | * This function installs all apps found in the 'apps' directory that should be enabled by default; |
||
502 | * @param bool $softErrors When updating we ignore errors and simply log them, better to have a |
||
503 | * working ownCloud at the end instead of an aborted update. |
||
504 | * @return array Array of error messages (appid => Exception) |
||
505 | */ |
||
506 | public static function installShippedApps($softErrors = false) { |
||
507 | $appManager = \OC::$server->getAppManager(); |
||
508 | $config = \OC::$server->getConfig(); |
||
509 | $errors = []; |
||
510 | foreach(\OC::$APPSROOTS as $app_dir) { |
||
511 | if($dir = opendir( $app_dir['path'] )) { |
||
512 | while( false !== ( $filename = readdir( $dir ))) { |
||
513 | if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) { |
||
514 | if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) { |
||
515 | if($config->getAppValue($filename, "installed_version", null) === null) { |
||
516 | $info=OC_App::getAppInfo($filename); |
||
517 | $enabled = isset($info['default_enable']); |
||
518 | if (($enabled || in_array($filename, $appManager->getAlwaysEnabledApps())) |
||
519 | && $config->getAppValue($filename, 'enabled') !== 'no') { |
||
520 | if ($softErrors) { |
||
521 | try { |
||
522 | Installer::installShippedApp($filename); |
||
523 | } catch (HintException $e) { |
||
524 | if ($e->getPrevious() instanceof TableExistsException) { |
||
525 | $errors[$filename] = $e; |
||
526 | continue; |
||
527 | } |
||
528 | throw $e; |
||
529 | } |
||
530 | } else { |
||
531 | Installer::installShippedApp($filename); |
||
532 | } |
||
533 | $config->setAppValue($filename, 'enabled', 'yes'); |
||
534 | } |
||
535 | } |
||
536 | } |
||
537 | } |
||
538 | } |
||
539 | closedir( $dir ); |
||
540 | } |
||
541 | } |
||
542 | |||
543 | return $errors; |
||
544 | } |
||
545 | |||
546 | /** |
||
547 | * install an app already placed in the app folder |
||
548 | * @param string $app id of the app to install |
||
549 | * @return integer |
||
550 | */ |
||
551 | public static function installShippedApp($app) { |
||
552 | //install the database |
||
553 | $appPath = OC_App::getAppPath($app); |
||
554 | \OC_App::registerAutoloading($app, $appPath); |
||
555 | |||
556 | if(is_file("$appPath/appinfo/database.xml")) { |
||
557 | try { |
||
558 | OC_DB::createDbFromStructure("$appPath/appinfo/database.xml"); |
||
559 | } catch (TableExistsException $e) { |
||
560 | throw new HintException( |
||
561 | 'Failed to enable app ' . $app, |
||
562 | 'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.', |
||
563 | 0, $e |
||
564 | ); |
||
565 | } |
||
566 | } else { |
||
567 | $ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection()); |
||
568 | $ms->migrate(); |
||
569 | } |
||
570 | |||
571 | //run appinfo/install.php |
||
572 | self::includeAppScript("$appPath/appinfo/install.php"); |
||
573 | |||
574 | $info = OC_App::getAppInfo($app); |
||
575 | if (is_null($info)) { |
||
576 | return false; |
||
577 | } |
||
578 | \OC_App::setupBackgroundJobs($info['background-jobs']); |
||
579 | |||
580 | OC_App::executeRepairSteps($app, $info['repair-steps']['install']); |
||
581 | |||
582 | $config = \OC::$server->getConfig(); |
||
583 | |||
584 | $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app)); |
||
585 | if (array_key_exists('ocsid', $info)) { |
||
586 | $config->setAppValue($app, 'ocsid', $info['ocsid']); |
||
587 | } |
||
588 | |||
589 | //set remote/public handlers |
||
590 | foreach($info['remote'] as $name=>$path) { |
||
591 | $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path); |
||
592 | } |
||
593 | foreach($info['public'] as $name=>$path) { |
||
594 | $config->setAppValue('core', 'public_'.$name, $app.'/'.$path); |
||
595 | } |
||
596 | |||
597 | OC_App::setAppTypes($info['id']); |
||
598 | |||
599 | return $info['id']; |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * @param string $script |
||
604 | */ |
||
605 | private static function includeAppScript($script) { |
||
608 | } |
||
609 | } |
||
610 | } |
||
611 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.