diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 398e2015e20b4..5f2cc5d11045b 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -2965,7 +2965,6 @@ - @@ -2988,26 +2987,11 @@ - - - - - - - - - - - - - - - diff --git a/core/Command/App/Disable.php b/core/Command/App/Disable.php index 7f25959bacd91..b61585f80a3f2 100644 --- a/core/Command/App/Disable.php +++ b/core/Command/App/Disable.php @@ -80,7 +80,9 @@ public function completeOptionValues($optionName, CompletionContext $context): a #[\Override] public function completeArgumentValues($argumentName, CompletionContext $context): array { if ($argumentName === 'app-id') { - return array_diff(\OC_App::getEnabledApps(true, true), $this->appManager->getAlwaysEnabledApps()); + $enabledApps = $this->appManager->getEnabledApps(); + $coreApps = $this->appManager->getAlwaysEnabledApps(); + return array_diff($enabledApps, $coreApps); } return []; } diff --git a/core/Command/App/Enable.php b/core/Command/App/Enable.php index 8c6c11e7b9c04..d7b81bc4b5b6d 100644 --- a/core/Command/App/Enable.php +++ b/core/Command/App/Enable.php @@ -148,7 +148,8 @@ public function completeOptionValues($optionName, CompletionContext $context): a public function completeArgumentValues($argumentName, CompletionContext $context): array { if ($argumentName === 'app-id') { $allApps = $this->appManager->getAllAppsInAppsFolders(); - return array_diff($allApps, \OC_App::getEnabledApps(true, true)); + $enabledApps = $this->appManager->getEnabledApps(); + return array_diff($allApps, $enabledApps); } return []; } diff --git a/core/Command/Config/ListConfigs.php b/core/Command/Config/ListConfigs.php index 4c683974908bd..3ce18f91ef9ca 100644 --- a/core/Command/Config/ListConfigs.php +++ b/core/Command/Config/ListConfigs.php @@ -10,6 +10,7 @@ use OC\Config\ConfigManager; use OC\Core\Command\Base; use OC\SystemConfig; +use OCP\App\IAppManager; use OCP\IAppConfig; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Input\InputArgument; @@ -24,6 +25,7 @@ public function __construct( protected SystemConfig $systemConfig, protected IAppConfig $appConfig, protected ConfigManager $configManager, + protected IAppManager $appManager, ) { parent::__construct(); } @@ -141,7 +143,7 @@ protected function getAppConfigs(string $app, bool $noSensitiveValues) { #[\Override] public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { - return array_merge(['all', 'system'], \OC_App::getAllApps()); + return array_merge(['all', 'system'], $this->appManager->getAllAppsInAppsFolders()); } return []; } diff --git a/core/Command/Db/ExpectedSchema.php b/core/Command/Db/ExpectedSchema.php index 8c942a023a748..75e2124a31060 100644 --- a/core/Command/Db/ExpectedSchema.php +++ b/core/Command/Db/ExpectedSchema.php @@ -14,6 +14,7 @@ use OC\DB\MigrationService; use OC\DB\SchemaWrapper; use OC\Migration\NullOutput; +use OCP\App\IAppManager; use Override; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -23,6 +24,7 @@ class ExpectedSchema extends Base { public function __construct( protected readonly Connection $connection, + protected readonly IAppManager $appManager, ) { parent::__construct(); } @@ -45,7 +47,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->applyMigrations('core', $schema); - $apps = \OC_App::getEnabledApps(); + $apps = $this->appManager->getEnabledApps(); foreach ($apps as $app) { $this->applyMigrations($app, $schema); } diff --git a/core/Command/Db/Migrations/ExecuteCommand.php b/core/Command/Db/Migrations/ExecuteCommand.php index 9a813a45c8e86..0d5655095109c 100644 --- a/core/Command/Db/Migrations/ExecuteCommand.php +++ b/core/Command/Db/Migrations/ExecuteCommand.php @@ -10,6 +10,7 @@ use OC\DB\Connection; use OC\DB\MigrationService; use OC\Migration\ConsoleOutput; +use OCP\App\IAppManager; use OCP\IConfig; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; @@ -22,6 +23,7 @@ class ExecuteCommand extends Command implements CompletionAwareInterface { public function __construct( private Connection $connection, private IConfig $config, + private IAppManager $appManager, ) { parent::__construct(); } @@ -81,8 +83,8 @@ public function completeOptionValues($optionName, CompletionContext $context) { #[\Override] public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { - $allApps = \OC_App::getAllApps(); - return array_diff($allApps, \OC_App::getEnabledApps(true, true)); + $allApps = $this->appManager->getAllAppsInAppsFolders(); + return array_diff($allApps, $this->appManager->getEnabledApps()); } if ($argumentName === 'version') { diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php index 86ff22cffde83..4c2be062634bc 100644 --- a/core/Command/Db/Migrations/GenerateCommand.php +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -164,7 +164,8 @@ public function completeOptionValues($optionName, CompletionContext $context) { public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { $allApps = $this->appManager->getAllAppsInAppsFolders(); - return array_diff($allApps, \OC_App::getEnabledApps(true, true)); + $enabledApps = $this->appManager->getEnabledApps(); + return array_diff($allApps, $enabledApps); } if ($argumentName === 'version') { diff --git a/core/Command/Db/Migrations/MigrateCommand.php b/core/Command/Db/Migrations/MigrateCommand.php index 23b9204db005e..0949334a90f60 100644 --- a/core/Command/Db/Migrations/MigrateCommand.php +++ b/core/Command/Db/Migrations/MigrateCommand.php @@ -10,6 +10,7 @@ use OC\DB\Connection; use OC\DB\MigrationService; use OC\Migration\ConsoleOutput; +use OCP\App\IAppManager; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; @@ -20,6 +21,7 @@ class MigrateCommand extends Command implements CompletionAwareInterface { public function __construct( private Connection $connection, + private IAppManager $appManager, ) { parent::__construct(); } @@ -63,8 +65,8 @@ public function completeOptionValues($optionName, CompletionContext $context) { #[\Override] public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { - $allApps = \OC_App::getAllApps(); - return array_diff($allApps, \OC_App::getEnabledApps(true, true)); + $allApps = $this->appManager->getAllAppsInAppsFolders(); + return array_diff($allApps, $this->appManager->getEnabledApps()); } if ($argumentName === 'version') { diff --git a/core/Command/Db/Migrations/StatusCommand.php b/core/Command/Db/Migrations/StatusCommand.php index abbfd10ed90ba..f7de52bab4c3c 100644 --- a/core/Command/Db/Migrations/StatusCommand.php +++ b/core/Command/Db/Migrations/StatusCommand.php @@ -10,6 +10,7 @@ use OC\DB\Connection; use OC\DB\MigrationService; use OC\Migration\ConsoleOutput; +use OCP\App\IAppManager; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; @@ -20,6 +21,7 @@ class StatusCommand extends Command implements CompletionAwareInterface { public function __construct( private Connection $connection, + private IAppManager $appManager, ) { parent::__construct(); } @@ -69,8 +71,8 @@ public function completeOptionValues($optionName, CompletionContext $context) { #[\Override] public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { - $allApps = \OC_App::getAllApps(); - return array_diff($allApps, \OC_App::getEnabledApps(true, true)); + $allApps = $this->appManager->getAllAppsInAppsFolders(); + return array_diff($allApps, $this->appManager->getEnabledApps()); } return []; } diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 0c3519b99d30a..21df5de22dbff 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -12,6 +12,9 @@ use OC\Config\ConfigManager; use OC\DB\MigrationService; use OC\Migration\BackgroundRepair; +use OC\NeedsUpdateException; +use OC\Repair; +use OC\Repair\Events\RepairErrorEvent; use OCP\Activity\IManager as IActivityManager; use OCP\App\AppPathNotFoundException; use OCP\App\Events\AppDisableEvent; @@ -147,6 +150,10 @@ private function getUrlGenerator(): IURLGenerator { * @return array appId => enabled (may be 'yes', or a json encoded list of group ids) */ private function getEnabledAppsValues(): array { + if ($this->config->getSystemValueBool('installed', false) === false) { + return []; + } + if (!$this->enabledAppsCache) { /** @var array */ $values = $this->getAppConfig()->searchValues('enabled', false, IAppConfig::VALUE_STRING); @@ -240,25 +247,18 @@ public function getEnabledAppsForGroup(IGroup $group): array { return array_keys($appsForGroups); } - /** - * Loads all apps - * - * @param string[] $types - * @return bool - * - * This function walks through the Nextcloud directory and loads all apps - * it can find. A directory contains an app if the file /appinfo/info.xml - * exists. - * - * if $types is set to non-empty array, only apps of those types will be loaded - */ #[\Override] public function loadApps(array $types = []): bool { if ($this->config->getSystemValueBool('maintenance', false)) { return false; } + if ($this->config->getSystemValueBool('installed', false) === false) { + // can only access the apps folder after installation, so we can't load any apps before that + return false; + } + // Load the enabled apps here - $apps = \OC_App::getEnabledApps(); + $apps = $this->getEnabledApps(); // Add each apps' folder as allowed class path foreach ($apps as $app) { @@ -708,7 +708,7 @@ public function disableApp($appId, $automaticDisabled = false): void { // run uninstall steps $appData = $this->getAppInfo($appId); if (!is_null($appData)) { - \OC_App::executeRepairSteps($appId, $appData['repair-steps']['uninstall']); + $this->executeRepairSteps($appId, $appData['repair-steps']['uninstall']); } $this->dispatcher->dispatchTyped(new AppDisableEvent($appId)); @@ -1109,30 +1109,24 @@ public function upgradeApp(string $appId): bool { $appPath = $this->getAppPath($appId, true); $this->clearAppsCache(); - $l = \OC::$server->getL10N('core'); - $appData = $this->getAppInfo($appId, false, $l->getLanguageCode()); - if ($appData === null) { + $appInfo = $this->getAppInfo($appId); + if ($appInfo === null) { throw new AppPathNotFoundException('Could not find ' . $appId); } $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []); $ignoreMax = in_array($appId, $ignoreMaxApps, true); - \OC_App::checkAppDependencies( - $this->config, - $l, - $appData, - $ignoreMax - ); + $this->checkAppDependencies($appId, $ignoreMax); \OC_App::registerAutoloading($appId, $appPath, true); - \OC_App::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']); + $this->executeRepairSteps($appId, $appInfo['repair-steps']['pre-migration']); $ms = new MigrationService($appId, Server::get(\OC\DB\Connection::class)); $ms->migrate(); - \OC_App::executeRepairSteps($appId, $appData['repair-steps']['post-migration']); + $this->executeRepairSteps($appId, $appInfo['repair-steps']['post-migration']); $queue = Server::get(IJobList::class); - foreach ($appData['repair-steps']['live-migration'] as $step) { + foreach ($appInfo['repair-steps']['live-migration'] as $step) { $queue->add(BackgroundRepair::class, [ 'app' => $appId, 'step' => $step]); @@ -1143,19 +1137,19 @@ public function upgradeApp(string $appId): bool { $this->getAppVersion($appId, false); // Setup background jobs - foreach ($appData['background-jobs'] as $job) { + foreach ($appInfo['background-jobs'] as $job) { $queue->add($job); } //set remote/public handlers - foreach ($appData['remote'] as $name => $path) { + foreach ($appInfo['remote'] as $name => $path) { $this->config->setAppValue('core', 'remote_' . $name, $appId . '/' . $path); } - foreach ($appData['public'] as $name => $path) { + foreach ($appInfo['public'] as $name => $path) { $this->config->setAppValue('core', 'public_' . $name, $appId . '/' . $path); } - $this->setAppTypes($appId, $appData); + $this->setAppTypes($appId, $appInfo); $version = $this->getAppVersion($appId); $this->config->setAppValue($appId, 'installed_version', $version); @@ -1197,4 +1191,53 @@ public function isUpgradeRequired(string $appId): bool { public function isAppCompatible(string $serverVersion, array $appInfo, bool $ignoreMax = false): bool { return count($this->dependencyAnalyzer->analyzeServerVersion($serverVersion, $appInfo, $ignoreMax)) === 0; } + + /** + * Check if all dependencies of an app are satisfied. + * + * @param string $appId - The app to check + * @param bool $ignoreMax - Whether to ignore the Nextcloud max version requirement + * @throws \Exception - If there are missing dependencies + */ + public function checkAppDependencies(string $appId, bool $ignoreMax = false): void { + $info = $this->getAppInfo($appId); + $missing = $this->dependencyAnalyzer->analyze($info, $ignoreMax); + if (!empty($missing)) { + $l = \OCP\Server::get(\OCP\L10N\IFactory::class)->get('core'); + $missingMsg = implode(PHP_EOL, $missing); + throw new \Exception( + $l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s', + [$info['name'], $missingMsg] + ) + ); + } + } + + /** + * Run repair steps for an app. + * + * @param string $appId - The app to run the repair steps for + * @param string[] $steps - The repair steps to run + * @throws NeedsUpdateException + */ + public function executeRepairSteps(string $appId, array $steps): void { + if (empty($steps)) { + return; + } + + $this->loadApp($appId); + + // load the steps + $r = Server::get(Repair::class); + foreach ($steps as $step) { + try { + $r->addStep($step); + } catch (\Exception $ex) { + $this->dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage())); + $this->logger->error('Failed to add app migration step ' . $step, ['exception' => $ex]); + } + } + // run the steps + $r->run(); + } } diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php index a31dd6a05e194..a07fba2c2c823 100644 --- a/lib/private/AppFramework/Bootstrap/Coordinator.php +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -46,9 +46,8 @@ public function __construct( } public function runInitialRegistration(): void { - $apps = OC_App::getEnabledApps(); - if (!empty($apps)) { - // make sure to also register the core app + $apps = $this->appManager->getEnabledApps(); + if ($apps !== []) { $apps = ['core', ...$apps]; } diff --git a/lib/private/Installer.php b/lib/private/Installer.php index dc114cc70fb03..f853a7a1eedcf 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -87,7 +87,7 @@ public function installApp(string $appId, bool $forceEnable = false): string { } // check for required dependencies - \OC_App::checkAppDependencies($this->config, $l, $info, $ignoreMax); + $this->appManager->checkAppDependencies($appId, $ignoreMax); $coordinator = Server::get(Coordinator::class); $coordinator->runLazyRegistration($appId); @@ -541,13 +541,13 @@ private function installAppLastSteps(string $appPath, array $info, ?IOutput $out $ms->setOutput($output); } if ($previousVersion !== '') { - \OC_App::executeRepairSteps($info['id'], $info['repair-steps']['pre-migration']); + $this->appManager->executeRepairSteps($info['id'], $info['repair-steps']['pre-migration']); } $ms->migrate('latest', $previousVersion === ''); if ($previousVersion !== '') { - \OC_App::executeRepairSteps($info['id'], $info['repair-steps']['post-migration']); + $this->appManager->executeRepairSteps($info['id'], $info['repair-steps']['post-migration']); } if ($output instanceof IOutput) { @@ -569,7 +569,7 @@ private function installAppLastSteps(string $appPath, array $info, ?IOutput $out self::includeAppScript($appInstallScriptPath); } - \OC_App::executeRepairSteps($info['id'], $info['repair-steps']['install']); + $this->appManager->executeRepairSteps($info['id'], $info['repair-steps']['install']); // Set the installed version $this->config->setAppValue($info['id'], 'installed_version', $this->appManager->getAppVersion($info['id'], false)); diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index 4dd5673ec4583..12bdaf35840a8 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -8,20 +8,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ use OC\App\AppManager; -use OC\App\DependencyAnalyzer; use OC\AppFramework\App; use OC\AppFramework\Bootstrap\Coordinator; use OC\Installer; use OC\NeedsUpdateException; -use OC\Repair; -use OC\Repair\Events\RepairErrorEvent; use OC\SystemConfig; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\Authentication\IAlternativeLogin; use OCP\Authentication\IAlternativeLoginProvider; use OCP\BackgroundJob\IJobList; -use OCP\EventDispatcher\IEventDispatcher; use OCP\IAppConfig; use OCP\IConfig; use OCP\IGroup; @@ -34,7 +30,6 @@ use OCP\Support\Subscription\IRegistry; use Psr\Container\ContainerExceptionInterface; use Psr\Log\LoggerInterface; -use function OCP\Log\logger; /** * This class manages the apps. It allows them to register and integrate in the @@ -146,6 +141,7 @@ public static function isType(string $app, array $types): bool { * @param bool $all whether to return apps for all users, not only the * currently logged in one * @return list + * @deprecated 32.0.0 - use {@see \OCP\App\IAppManager::getEnabledAppsForUser} or {@see \OC\OCP\AppIAppManager::getEnabledApps} instead */ public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array { if (!Server::get(SystemConfig::class)->getValue('installed', false)) { @@ -532,28 +528,10 @@ public static function updateApp(string $appId): bool { * @param string $appId * @param string[] $steps * @throws NeedsUpdateException + * @deprecated 34.0.0 Use {@see \OC\App\AppManager::upgradeApp} */ public static function executeRepairSteps(string $appId, array $steps) { - if (empty($steps)) { - return; - } - // load the app - self::loadApp($appId); - - $dispatcher = Server::get(IEventDispatcher::class); - - // load the steps - $r = Server::get(Repair::class); - foreach ($steps as $step) { - try { - $r->addStep($step); - } catch (Exception $ex) { - $dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage())); - logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]); - } - } - // run the steps - $r->run(); + Server::get(AppManager::class)->executeRepairSteps($appId, $steps); } /** @@ -568,17 +546,9 @@ public static function setupBackgroundJobs(array $jobs): void { /** * @throws \Exception + * @deprecated 34.0.0 Use {@see \OC\App\AppManager::checkAppDependencies} instead */ public static function checkAppDependencies(IConfig $config, IL10N $l, array $info, bool $ignoreMax): void { - $dependencyAnalyzer = Server::get(DependencyAnalyzer::class); - $missing = $dependencyAnalyzer->analyze($info, $ignoreMax); - if (!empty($missing)) { - $missingMsg = implode(PHP_EOL, $missing); - throw new \Exception( - $l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s', - [$info['name'], $missingMsg] - ) - ); - } + Server::get(AppManager::class)->checkAppDependencies($info['id'], $ignoreMax); } } diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php index ddd426da942e4..02fe760599274 100644 --- a/lib/private/legacy/OC_User.php +++ b/lib/private/legacy/OC_User.php @@ -10,6 +10,7 @@ use OC\User\Database; use OC\User\DisabledUserException; use OC\User\Session; +use OCP\App\IAppManager; use OCP\Authentication\Exceptions\InvalidTokenException; use OCP\Authentication\Exceptions\WipeTokenException; use OCP\Authentication\IApacheBackend; @@ -108,7 +109,8 @@ public static function clearBackends() { * @suppress PhanDeprecatedFunction */ public static function setupBackends() { - OC_App::loadApps(['prelogin']); + Server::get(IAppManager::class)->loadApps(['prelogin']); + $backends = Server::get(SystemConfig::class)->getValue('user_backends', []); if (isset($backends['default']) && !$backends['default']) { // clear default backends @@ -231,7 +233,7 @@ public static function loginWithApache(IApacheBackend $backend): bool { public static function handleApacheAuth(): ?bool { $backend = self::findFirstActiveUsedBackend(); if ($backend) { - OC_App::loadApps(); + Server::get(IAppManager::class)->loadApps(); //setup extra user backends self::setupBackends(); diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index 97acd9af7b1e3..9b732a1f3871b 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -200,7 +200,9 @@ public function getEnabledAppsForUser(IUser $user); public function getInstalledApps(); /** - * List all apps enabled, either for everyone or for specific groups only + * List all apps enabled + * + * Including apps enabled for everyone and also including apps only enabled for specific groups. * * @return list * @since 32.0.0 @@ -223,14 +225,12 @@ public function isShipped($appId); /** * Loads all apps * - * @param string[] $types - * @return bool - * * This function walks through the Nextcloud directory and loads all apps * it can find. A directory contains an app if the file `/appinfo/info.xml` * exists. * - * if $types is set to non-empty array, only apps of those types will be loaded + * @param string[] $types - If set, only apps of these types will be loaded + * @return bool * @since 27.0.0 */ public function loadApps(array $types = []): bool; diff --git a/tests/Core/Command/Config/ListConfigsTest.php b/tests/Core/Command/Config/ListConfigsTest.php index e5b14dc0643dd..555710132f0b8 100644 --- a/tests/Core/Command/Config/ListConfigsTest.php +++ b/tests/Core/Command/Config/ListConfigsTest.php @@ -11,49 +11,49 @@ use OC\Config\ConfigManager; use OC\Core\Command\Config\ListConfigs; use OC\SystemConfig; +use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\IConfig; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Test\TestCase; class ListConfigsTest extends TestCase { - /** @var \PHPUnit\Framework\MockObject\MockObject */ - protected $appConfig; - /** @var \PHPUnit\Framework\MockObject\MockObject */ - protected $systemConfig; - /** @var \PHPUnit\Framework\MockObject\MockObject */ - protected $configManager; + protected IAppConfig&MockObject $appConfig; + protected SystemConfig&MockObject $systemConfig; + protected ConfigManager&MockObject $configManager; + protected InputInterface&MockObject $consoleInput; + protected OutputInterface&MockObject $consoleOutput; + protected IAppManager&MockObject $appManager; - /** @var \PHPUnit\Framework\MockObject\MockObject */ - protected $consoleInput; - /** @var \PHPUnit\Framework\MockObject\MockObject */ - protected $consoleOutput; - - /** @var \Symfony\Component\Console\Command\Command */ - protected $command; + protected Command $command; #[\Override] protected function setUp(): void { parent::setUp(); - $systemConfig = $this->systemConfig = $this->getMockBuilder(SystemConfig::class) + $this->systemConfig = $this->getMockBuilder(SystemConfig::class) ->disableOriginalConstructor() ->getMock(); - $appConfig = $this->appConfig = $this->getMockBuilder(IAppConfig::class) + $this->appConfig = $this->getMockBuilder(IAppConfig::class) ->disableOriginalConstructor() ->getMock(); - $configManager = $this->configManager = $this->getMockBuilder(ConfigManager::class) + $this->configManager = $this->getMockBuilder(ConfigManager::class) ->disableOriginalConstructor() ->getMock(); + $this->appManager = $this->createMock(IAppManager::class); - $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock(); - $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock(); + $this->consoleInput = $this->createMock(InputInterface::class); + $this->consoleOutput = $this->createMock(OutputInterface::class); - /** @var \OC\SystemConfig $systemConfig */ - /** @var \OCP\IAppConfig $appConfig */ - /** @var ConfigManager $configManager */ - $this->command = new ListConfigs($systemConfig, $appConfig, $configManager); + $this->command = new ListConfigs( + $this->systemConfig, + $this->appConfig, + $this->configManager, + $this->appManager, + ); } public static function listData(): array { @@ -316,8 +316,7 @@ public function testList($app, $systemConfigs, $systemConfigMap, $appConfig, $pr $output = ''; $this->consoleOutput->expects($this->any()) ->method('writeln') - ->willReturnCallback(function ($value) { - global $output; + ->willReturnCallback(function ($value) use (&$output) { $output .= $value . "\n"; return $output; });