diff options
Diffstat (limited to 'lib/private/AppFramework')
4 files changed, 10 insertions, 288 deletions
diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php index 2b04d291730..4e613703dec 100644 --- a/lib/private/AppFramework/Bootstrap/Coordinator.php +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -83,11 +83,12 @@ class Coordinator { $appNameSpace = App::buildAppNamespace($appId); $applicationClassName = $appNameSpace . '\\AppInfo\\Application'; try { - if (class_exists($applicationClassName) && in_array(IBootstrap::class, class_implements($applicationClassName), true)) { + if (class_exists($applicationClassName) && is_a($applicationClassName, IBootstrap::class, true)) { $this->eventLogger->start("bootstrap:register_app:$appId:application", "Load `Application` instance for $appId"); try { - /** @var IBootstrap|App $application */ - $apps[$appId] = $application = $this->serverContainer->query($applicationClassName); + /** @var IBootstrap&App $application */ + $application = $this->serverContainer->query($applicationClassName); + $apps[$appId] = $application; } catch (QueryException $e) { // Weird, but ok $this->eventLogger->end("bootstrap:register_app:$appId"); diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php deleted file mode 100644 index 2b7f21a8ba5..00000000000 --- a/lib/private/AppFramework/Routing/RouteConfig.php +++ /dev/null @@ -1,279 +0,0 @@ -<?php - -declare(strict_types=1); -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace OC\AppFramework\Routing; - -use OC\AppFramework\DependencyInjection\DIContainer; -use OC\Route\Router; - -/** - * Class RouteConfig - * @package OC\AppFramework\routing - */ -class RouteConfig { - /** @var DIContainer */ - private $container; - - /** @var Router */ - private $router; - - /** @var array */ - private $routes; - - /** @var string */ - private $appName; - - /** @var string[] */ - private $controllerNameCache = []; - - protected $rootUrlApps = [ - 'cloud_federation_api', - 'core', - 'files_sharing', - 'files', - 'profile', - 'settings', - 'spreed', - ]; - - /** - * @param \OC\AppFramework\DependencyInjection\DIContainer $container - * @param \OC\Route\Router $router - * @param array $routes - * @internal param $appName - */ - public function __construct(DIContainer $container, Router $router, $routes) { - $this->routes = $routes; - $this->container = $container; - $this->router = $router; - $this->appName = $container['AppName']; - } - - /** - * The routes and resource will be registered to the \OCP\Route\IRouter - */ - public function register() { - // parse simple - $this->processIndexRoutes($this->routes); - - // parse resources - $this->processIndexResources($this->routes); - - /* - * OCS routes go into a different collection - */ - $oldCollection = $this->router->getCurrentCollection(); - $this->router->useCollection($oldCollection . '.ocs'); - - // parse ocs simple routes - $this->processOCS($this->routes); - - // parse ocs simple routes - $this->processOCSResources($this->routes); - - $this->router->useCollection($oldCollection); - } - - private function processOCS(array $routes): void { - $ocsRoutes = $routes['ocs'] ?? []; - foreach ($ocsRoutes as $ocsRoute) { - $this->processRoute($ocsRoute, 'ocs.'); - } - } - - /** - * Creates one route base on the give configuration - * @param array $routes - * @throws \UnexpectedValueException - */ - private function processIndexRoutes(array $routes): void { - $simpleRoutes = $routes['routes'] ?? []; - foreach ($simpleRoutes as $simpleRoute) { - $this->processRoute($simpleRoute); - } - } - - protected function processRoute(array $route, string $routeNamePrefix = ''): void { - $name = $route['name']; - $postfix = $route['postfix'] ?? ''; - $root = $this->buildRootPrefix($route, $routeNamePrefix); - - $url = $root . '/' . ltrim($route['url'], '/'); - $verb = strtoupper($route['verb'] ?? 'GET'); - - $split = explode('#', $name, 2); - if (count($split) !== 2) { - throw new \UnexpectedValueException('Invalid route name: use the format foo#bar to reference FooController::bar'); - } - [$controller, $action] = $split; - - $controllerName = $this->buildControllerName($controller); - $actionName = $this->buildActionName($action); - - /* - * The route name has to be lowercase, for symfony to match it correctly. - * This is required because smyfony allows mixed casing for controller names in the routes. - * To avoid breaking all the existing route names, registering and matching will only use the lowercase names. - * This is also safe on the PHP side because class and method names collide regardless of the casing. - */ - $routeName = strtolower($routeNamePrefix . $this->appName . '.' . $controller . '.' . $action . $postfix); - - $router = $this->router->create($routeName, $url) - ->method($verb); - - // optionally register requirements for route. This is used to - // tell the route parser how url parameters should be matched - if (array_key_exists('requirements', $route)) { - $router->requirements($route['requirements']); - } - - // optionally register defaults for route. This is used to - // tell the route parser how url parameters should be default valued - $defaults = []; - if (array_key_exists('defaults', $route)) { - $defaults = $route['defaults']; - } - - $defaults['caller'] = [$this->appName, $controllerName, $actionName]; - $router->defaults($defaults); - } - - /** - * For a given name and url restful OCS routes are created: - * - index - * - show - * - create - * - update - * - destroy - * - * @param array $routes - */ - private function processOCSResources(array $routes): void { - $this->processResources($routes['ocs-resources'] ?? [], 'ocs.'); - } - - /** - * For a given name and url restful routes are created: - * - index - * - show - * - create - * - update - * - destroy - * - * @param array $routes - */ - private function processIndexResources(array $routes): void { - $this->processResources($routes['resources'] ?? []); - } - - /** - * For a given name and url restful routes are created: - * - index - * - show - * - create - * - update - * - destroy - * - * @param array $resources - * @param string $routeNamePrefix - */ - protected function processResources(array $resources, string $routeNamePrefix = ''): void { - // declaration of all restful actions - $actions = [ - ['name' => 'index', 'verb' => 'GET', 'on-collection' => true], - ['name' => 'show', 'verb' => 'GET'], - ['name' => 'create', 'verb' => 'POST', 'on-collection' => true], - ['name' => 'update', 'verb' => 'PUT'], - ['name' => 'destroy', 'verb' => 'DELETE'], - ]; - - foreach ($resources as $resource => $config) { - $root = $this->buildRootPrefix($config, $routeNamePrefix); - - // the url parameter used as id to the resource - foreach ($actions as $action) { - $url = $root . '/' . ltrim($config['url'], '/'); - $method = $action['name']; - - $verb = strtoupper($action['verb'] ?? 'GET'); - $collectionAction = $action['on-collection'] ?? false; - if (!$collectionAction) { - $url .= '/{id}'; - } - if (isset($action['url-postfix'])) { - $url .= '/' . $action['url-postfix']; - } - - $controller = $resource; - - $controllerName = $this->buildControllerName($controller); - $actionName = $this->buildActionName($method); - - $routeName = $routeNamePrefix . $this->appName . '.' . strtolower($resource) . '.' . $method; - - $route = $this->router->create($routeName, $url) - ->method($verb); - - $route->defaults(['caller' => [$this->appName, $controllerName, $actionName]]); - } - } - } - - private function buildRootPrefix(array $route, string $routeNamePrefix): string { - $defaultRoot = $this->appName === 'core' ? '' : '/apps/' . $this->appName; - $root = $route['root'] ?? $defaultRoot; - - if ($routeNamePrefix !== '') { - // In OCS all apps are whitelisted - return $root; - } - - if (!\in_array($this->appName, $this->rootUrlApps, true)) { - // Only allow root URLS for some apps - return $defaultRoot; - } - - return $root; - } - - /** - * Based on a given route name the controller name is generated - * @param string $controller - * @return string - */ - private function buildControllerName(string $controller): string { - if (!isset($this->controllerNameCache[$controller])) { - $this->controllerNameCache[$controller] = $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller'; - } - return $this->controllerNameCache[$controller]; - } - - /** - * Based on the action part of the route name the controller method name is generated - * @param string $action - * @return string - */ - private function buildActionName(string $action): string { - return $this->underScoreToCamelCase($action); - } - - /** - * Underscored strings are converted to camel case strings - * @param string $str - * @return string - */ - private function underScoreToCamelCase(string $str): string { - $pattern = '/_[a-z]?/'; - return preg_replace_callback( - $pattern, - function ($matches) { - return strtoupper(ltrim($matches[0], '_')); - }, - $str); - } -} diff --git a/lib/private/AppFramework/Routing/RouteParser.php b/lib/private/AppFramework/Routing/RouteParser.php index 894a74c727b..55e58234673 100644 --- a/lib/private/AppFramework/Routing/RouteParser.php +++ b/lib/private/AppFramework/Routing/RouteParser.php @@ -76,7 +76,7 @@ class RouteParser { $url = $root . '/' . ltrim($route['url'], '/'); $verb = strtoupper($route['verb'] ?? 'GET'); - $split = explode('#', $name, 2); + $split = explode('#', $name, 3); if (count($split) !== 2) { throw new \UnexpectedValueException('Invalid route name: use the format foo#bar to reference FooController::bar'); } @@ -87,7 +87,7 @@ class RouteParser { /* * The route name has to be lowercase, for symfony to match it correctly. - * This is required because smyfony allows mixed casing for controller names in the routes. + * This is required because symfony allows mixed casing for controller names in the routes. * To avoid breaking all the existing route names, registering and matching will only use the lowercase names. * This is also safe on the PHP side because class and method names collide regardless of the casing. */ diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php index 24918992ea3..9af65a37ab8 100644 --- a/lib/private/AppFramework/Utility/SimpleContainer.php +++ b/lib/private/AppFramework/Utility/SimpleContainer.php @@ -153,13 +153,13 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { return $closure($this); }; $name = $this->sanitizeName($name); - if (isset($this[$name])) { - unset($this[$name]); + if (isset($this->container[$name])) { + unset($this->container[$name]); } if ($shared) { - $this[$name] = $wrapped; + $this->container[$name] = $wrapped; } else { - $this[$name] = $this->container->factory($wrapped); + $this->container[$name] = $this->container->factory($wrapped); } } |