diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php index e15e4a797e..5a7bc8fad4 100644 --- a/lib/private/AppFramework/App.php +++ b/lib/private/AppFramework/App.php @@ -61,11 +61,12 @@ class App { $appInfo = \OC_App::getAppInfo($appId); if (isset($appInfo['namespace'])) { - return $topNamespace . trim($appInfo['namespace']); + self::$nameSpaceCache[$appId] = trim($appInfo['namespace']); + } else { + // if the tag is not found, fall back to uppercasing the first letter + self::$nameSpaceCache[$appId] = ucfirst($appId); } - // if the tag is not found, fall back to uppercasing the first letter - self::$nameSpaceCache[$appId] = ucfirst($appId); return $topNamespace . self::$nameSpaceCache[$appId]; } diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index 06825d2dd5..4fb13b09ae 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -49,6 +49,7 @@ use OC\ServerContainer; use OCP\AppFramework\Http\IOutput; use OCP\AppFramework\IApi; use OCP\AppFramework\IAppContainer; +use OCP\AppFramework\QueryException; use OCP\Files\Folder; use OCP\Files\IAppData; use OCP\IL10N; @@ -373,24 +374,40 @@ class DIContainer extends SimpleContainer implements IAppContainer { }); } + /** + * @param string $name + * @return mixed + * @throws QueryException if the query could not be resolved + */ public function query($name) { + try { + return $this->queryNoFallback($name); + } catch (QueryException $e) { + return $this->getServer()->query($name); + } + } + + /** + * @param string $name + * @return mixed + * @throws QueryException if the query could not be resolved + */ + public function queryNoFallback($name) { $name = $this->sanitizeName($name); if ($this->offsetExists($name)) { return parent::query($name); } else { - if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) { - $segments = explode('\\', $name); - if (strtolower($segments[1]) === strtolower($this['AppName'])) { - return parent::query($name); - } - } else if ($this['AppName'] === 'settings' && strpos($name, 'OC\\Settings\\') === 0) { + if ($this['AppName'] === 'settings' && strpos($name, 'OC\\Settings\\') === 0) { return parent::query($name); } else if ($this['AppName'] === 'core' && strpos($name, 'OC\\Core\\') === 0) { return parent::query($name); + } else if (strpos($name, \OC\AppFramework\App::buildAppNamespace($this['AppName']) . '\\') === 0) { + return parent::query($name); } } - return $this->getServer()->query($name); + throw new QueryException('Could not resolve ' . $name . '!' . + ' Class can not be instantiated'); } } diff --git a/lib/private/ServerContainer.php b/lib/private/ServerContainer.php index df0293addf..e7b1ed2dad 100644 --- a/lib/private/ServerContainer.php +++ b/lib/private/ServerContainer.php @@ -37,12 +37,26 @@ class ServerContainer extends SimpleContainer { /** @var DIContainer[] */ protected $appContainers; + /** @var string[] */ + protected $namespaces; + /** * ServerContainer constructor. */ public function __construct() { parent::__construct(); $this->appContainers = []; + $this->namespaces = []; + } + + /** + * @param string $appName + * @param string $appNamespace + */ + public function registerNamespace($appName, $appNamespace) { + // Cut of OCA\ and lowercase + $appNamespace = strtolower(substr($appNamespace, strrpos($appNamespace, '\\') + 1)); + $this->namespaces[$appNamespace] = $appName; } /** @@ -54,15 +68,19 @@ class ServerContainer extends SimpleContainer { } /** - * @param string $appName + * @param string $namespace * @return DIContainer + * @throws QueryException */ - public function getAppContainer($appName) { - if (isset($this->appContainers[$appName])) { - return $this->appContainers[$appName]; + protected function getAppContainer($namespace) { + if (isset($this->appContainers[$namespace])) { + return $this->appContainers[$namespace]; } - return new DIContainer($appName); + if (isset($this->namespaces[$namespace])) { + return new DIContainer($this->namespaces[$namespace]); + } + throw new QueryException(); } /** @@ -77,11 +95,11 @@ class ServerContainer extends SimpleContainer { // the apps container first. if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) { $segments = explode('\\', $name); - $appContainer = $this->getAppContainer(strtolower($segments[1])); try { - return $appContainer->query($name); + $appContainer = $this->getAppContainer(strtolower($segments[1])); + return $appContainer->queryNoFallback($name); } catch (QueryException $e) { - // Didn't find the service in the respective app container, + // Didn't find the service or the respective app container, // ignore it and fall back to the core container. } } diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php index c82d620882..5343e7ad17 100644 --- a/lib/private/legacy/app.php +++ b/lib/private/legacy/app.php @@ -189,6 +189,7 @@ class OC_App { self::$alreadyRegistered[$key] = true; // Register on PSR-4 composer autoloader $appNamespace = \OC\AppFramework\App::buildAppNamespace($app); + \OC::$server->registerNamespace($app, $appNamespace); \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true); if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) { \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true); diff --git a/lib/public/IContainer.php b/lib/public/IContainer.php index 9dc7f9f941..f7ca069767 100644 --- a/lib/public/IContainer.php +++ b/lib/public/IContainer.php @@ -62,6 +62,7 @@ interface IContainer { * * @param string $name * @return mixed + * @throws QueryException if the query could not be resolved * @since 6.0.0 */ public function query($name); diff --git a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php index 1ea17f5d30..c031c39b5f 100644 --- a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php +++ b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php @@ -68,7 +68,7 @@ class ManagerTest extends TestCase { parent::setUp(); $this->user = $this->createMock(IUser::class); - $this->appManager = $this->createMock('\OC\App\AppManager'); + $this->appManager = $this->createMock(AppManager::class); $this->session = $this->createMock(ISession::class); $this->config = $this->createMock(IConfig::class); $this->activityManager = $this->createMock(IManager::class); diff --git a/tests/lib/InfoXmlTest.php b/tests/lib/InfoXmlTest.php index 4e75ca7820..18391a20c0 100644 --- a/tests/lib/InfoXmlTest.php +++ b/tests/lib/InfoXmlTest.php @@ -63,6 +63,14 @@ class InfoXmlTest extends TestCase { $appPath = \OC_App::getAppPath($app); \OC_App::registerAutoloading($app, $appPath); + //Add the appcontainer + $applicationClassName = \OCP\AppFramework\App::buildAppNamespace($app) . '\\AppInfo\\Application'; + if (class_exists($applicationClassName)) { + $application = new $applicationClassName(); + } else { + $application = new \OCP\AppFramework\App($app); + } + if (isset($appInfo['background-jobs'])) { foreach ($appInfo['background-jobs'] as $job) { $this->assertTrue(class_exists($job), 'Asserting background job "' . $job . '" exists');