Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bdc0751c0 | |||
| bb632f0cfa | |||
| 38673662d8 | |||
| e6931e11e5 | |||
| f9dc997403 | |||
| 4e56211a6c | |||
| 5dcdafc616 | |||
| 03c90f66ae | |||
| 274313f8ca | |||
| b8ff2ffe8a | |||
| b70a3e6f34 | |||
| c3a96b9790 | |||
| 3f487633d5 | |||
| 8f4a19ccab | |||
| 83d74782df | |||
| d9351b8fd0 | |||
| 1b6be5f081 |
@@ -1045,6 +1045,7 @@ return array(
|
||||
'OC\\AppFramework\\Services\\InitialState' => $baseDir . '/lib/private/AppFramework/Services/InitialState.php',
|
||||
'OC\\AppFramework\\Utility\\ControllerMethodReflector' => $baseDir . '/lib/private/AppFramework/Utility/ControllerMethodReflector.php',
|
||||
'OC\\AppFramework\\Utility\\QueryNotFoundException' => $baseDir . '/lib/private/AppFramework/Utility/QueryNotFoundException.php',
|
||||
'OC\\AppFramework\\Utility\\ServiceFactory' => $baseDir . '/lib/private/AppFramework/Utility/ServiceFactory.php',
|
||||
'OC\\AppFramework\\Utility\\SimpleContainer' => $baseDir . '/lib/private/AppFramework/Utility/SimpleContainer.php',
|
||||
'OC\\AppFramework\\Utility\\TimeFactory' => $baseDir . '/lib/private/AppFramework/Utility/TimeFactory.php',
|
||||
'OC\\AppScriptDependency' => $baseDir . '/lib/private/AppScriptDependency.php',
|
||||
|
||||
@@ -1086,6 +1086,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
||||
'OC\\AppFramework\\Services\\InitialState' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Services/InitialState.php',
|
||||
'OC\\AppFramework\\Utility\\ControllerMethodReflector' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/ControllerMethodReflector.php',
|
||||
'OC\\AppFramework\\Utility\\QueryNotFoundException' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/QueryNotFoundException.php',
|
||||
'OC\\AppFramework\\Utility\\ServiceFactory' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/ServiceFactory.php',
|
||||
'OC\\AppFramework\\Utility\\SimpleContainer' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/SimpleContainer.php',
|
||||
'OC\\AppFramework\\Utility\\TimeFactory' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/TimeFactory.php',
|
||||
'OC\\AppScriptDependency' => __DIR__ . '/../../..' . '/lib/private/AppScriptDependency.php',
|
||||
|
||||
@@ -89,7 +89,7 @@ class App {
|
||||
* @param string $controllerName the name of the controller under which it is
|
||||
* stored in the DI container
|
||||
* @param string $methodName the method that you want to call
|
||||
* @param DIContainer $container an instance of a pimple container.
|
||||
* @param DIContainer $container an instance of a container.
|
||||
* @param array $urlParams list of URL parameters (optional)
|
||||
* @throws HintException
|
||||
*/
|
||||
@@ -231,7 +231,7 @@ class App {
|
||||
* stored in the DI container
|
||||
* @param string $methodName the method that you want to call
|
||||
* @param array $urlParams an array with variables extracted from the routes
|
||||
* @param DIContainer $container an instance of a pimple container.
|
||||
* @param DIContainer $container an instance of container.
|
||||
*/
|
||||
public static function part(string $controllerName, string $methodName, array $urlParams,
|
||||
DIContainer $container) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
namespace OC\AppFramework\DependencyInjection;
|
||||
|
||||
use OC;
|
||||
use OC\AppFramework\App;
|
||||
use OC\AppFramework\Http;
|
||||
use OC\AppFramework\Http\Dispatcher;
|
||||
use OC\AppFramework\Http\Output;
|
||||
@@ -57,6 +58,7 @@ use Psr\Log\LoggerInterface;
|
||||
*/
|
||||
class DIContainer extends SimpleContainer implements IAppContainer {
|
||||
private string $appName;
|
||||
private string $nameSpace;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
@@ -73,8 +75,8 @@ class DIContainer extends SimpleContainer implements IAppContainer {
|
||||
* @param ServerContainer|null $server
|
||||
*/
|
||||
public function __construct(string $appName, array $urlParams = [], ?ServerContainer $server = null) {
|
||||
parent::__construct();
|
||||
$this->appName = $appName;
|
||||
$this->nameSpace = App::buildAppNamespace($this->appName);
|
||||
$this['appName'] = $appName;
|
||||
$this['urlParams'] = $urlParams;
|
||||
|
||||
@@ -398,21 +400,30 @@ class DIContainer extends SimpleContainer implements IAppContainer {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value): void {
|
||||
if ($offset === 'AppName' || $offset === 'appName') {
|
||||
$this->appName = $value;
|
||||
}
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
|
||||
public function query(string $name, bool $autoload = true) {
|
||||
if ($name === 'AppName' || $name === 'appName') {
|
||||
return $this->appName;
|
||||
}
|
||||
$name = $this->sanitizeName($name);
|
||||
$name = $this->resolveAlias($name);
|
||||
|
||||
$isServerClass = str_starts_with($name, 'OCP\\') || str_starts_with($name, 'OC\\');
|
||||
if ($isServerClass && !$this->has($name)) {
|
||||
return $this->getServer()->query($name, $autoload);
|
||||
return $this->server->queryNoApps($name, $autoload);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->queryNoFallback($name);
|
||||
} catch (QueryException $firstException) {
|
||||
try {
|
||||
return $this->getServer()->query($name, $autoload);
|
||||
return $this->server->query($name, $autoload);
|
||||
} catch (QueryException $secondException) {
|
||||
if ($firstException->getCode() === 1) {
|
||||
throw $secondException;
|
||||
@@ -427,20 +438,22 @@ class DIContainer extends SimpleContainer implements IAppContainer {
|
||||
* @return mixed
|
||||
* @throws QueryException if the query could not be resolved
|
||||
*/
|
||||
public function queryNoFallback($name) {
|
||||
$name = $this->sanitizeName($name);
|
||||
|
||||
public function queryNoFallback(string $name) {
|
||||
if ($this->offsetExists($name)) {
|
||||
return parent::query($name);
|
||||
} elseif ($this->appName === 'settings' && str_starts_with($name, 'OC\\Settings\\')) {
|
||||
return parent::query($name);
|
||||
} elseif ($this->appName === 'core' && str_starts_with($name, 'OC\\Core\\')) {
|
||||
return parent::query($name);
|
||||
} elseif (str_starts_with($name, \OC\AppFramework\App::buildAppNamespace($this->appName) . '\\')) {
|
||||
} elseif (str_starts_with($name, $this->nameSpace)) {
|
||||
return parent::query($name);
|
||||
}
|
||||
|
||||
throw new QueryException('Could not resolve ' . $name . '!' .
|
||||
' Class can not be instantiated', 1);
|
||||
}
|
||||
|
||||
protected function resolveAlias(string $name): string {
|
||||
return parent::resolveAlias($this->server->resolveAlias($name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace OC\AppFramework\Utility;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class ServiceFactory {
|
||||
private $factory;
|
||||
private ContainerInterface $container;
|
||||
|
||||
public function __construct(ContainerInterface $container, callable $factory) {
|
||||
$this->container = $container;
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
public function get() {
|
||||
return ($this->factory)($this->container);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ use ArrayAccess;
|
||||
use Closure;
|
||||
use OCP\AppFramework\QueryException;
|
||||
use OCP\IContainer;
|
||||
use Pimple\Container;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionClass;
|
||||
@@ -21,16 +20,12 @@ use ReflectionParameter;
|
||||
use function class_exists;
|
||||
|
||||
/**
|
||||
* SimpleContainer is a simple implementation of a container on basis of Pimple
|
||||
* SimpleContainer is a simple implementation of a container
|
||||
*/
|
||||
class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
public static bool $useLazyObjects = false;
|
||||
|
||||
private Container $container;
|
||||
|
||||
public function __construct() {
|
||||
$this->container = new Container();
|
||||
}
|
||||
protected array $items = [];
|
||||
protected array $aliases = [];
|
||||
|
||||
/**
|
||||
* @template T
|
||||
@@ -46,12 +41,13 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
|
||||
public function has(string $id): bool {
|
||||
// If a service is no registered but is an existing class, we can probably load it
|
||||
return isset($this->container[$id]) || class_exists($id);
|
||||
return array_key_exists($id, $this->items) || array_key_exists($id, $this->aliases) || class_exists($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class the class to instantiate
|
||||
* @return object the created class
|
||||
* @template T of object
|
||||
* @param ReflectionClass<T> $class the class to instantiate
|
||||
* @return T the created class
|
||||
* @suppress PhanUndeclaredClassInstanceof
|
||||
*/
|
||||
private function buildClass(ReflectionClass $class): object {
|
||||
@@ -79,7 +75,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
$resolveName = $parameter->getName();
|
||||
|
||||
// try to find out if it is a class or a simple parameter
|
||||
if ($parameterType !== null && ($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
|
||||
if (($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
|
||||
$resolveName = $parameterType->getName();
|
||||
}
|
||||
|
||||
@@ -93,7 +89,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
return $parameter->getDefaultValue();
|
||||
}
|
||||
|
||||
if ($parameterType !== null && ($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
|
||||
if (($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
|
||||
$resolveName = $parameter->getName();
|
||||
try {
|
||||
return $this->query($resolveName);
|
||||
@@ -131,19 +127,25 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
|
||||
public function query(string $name, bool $autoload = true) {
|
||||
$name = $this->sanitizeName($name);
|
||||
if (isset($this->container[$name])) {
|
||||
return $this->container[$name];
|
||||
$name = $this->resolveAlias($name);
|
||||
|
||||
if (array_key_exists($name, $this->items)) {
|
||||
$item = $this->items[$name];
|
||||
if ($item instanceof ServiceFactory) {
|
||||
return $item->get();
|
||||
} elseif (is_callable($item)) {
|
||||
$this->items[$name] = $item($this);
|
||||
}
|
||||
return $this->items[$name];
|
||||
}
|
||||
|
||||
if ($autoload) {
|
||||
$object = $this->resolve($name);
|
||||
$this->registerService($name, function () use ($object) {
|
||||
return $object;
|
||||
});
|
||||
$this->items[$name] = $object;
|
||||
return $object;
|
||||
}
|
||||
|
||||
throw new QueryNotFoundException('Could not resolve ' . $name . '!');
|
||||
throw new QueryNotFoundException('Could not resolve ' . $name . '!' . get_class($this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +153,8 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function registerParameter($name, $value) {
|
||||
$this[$name] = $value;
|
||||
$this->items[$name] = $value;
|
||||
unset($this->aliases[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,17 +167,12 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
* @param bool $shared
|
||||
*/
|
||||
public function registerService($name, Closure $closure, $shared = true) {
|
||||
$wrapped = function () use ($closure) {
|
||||
return $closure($this);
|
||||
};
|
||||
$name = $this->sanitizeName($name);
|
||||
if (isset($this->container[$name])) {
|
||||
unset($this->container[$name]);
|
||||
}
|
||||
unset($this->aliases[$name]);
|
||||
if ($shared) {
|
||||
$this->container[$name] = $wrapped;
|
||||
$this->items[$name] = $closure;
|
||||
} else {
|
||||
$this->container[$name] = $this->container->factory($wrapped);
|
||||
$this->items[$name] = new ServiceFactory($this, $closure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,9 +184,13 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
* @param string $target the target that should be resolved instead
|
||||
*/
|
||||
public function registerAlias($alias, $target) {
|
||||
$this->registerService($alias, function (ContainerInterface $container) use ($target) {
|
||||
return $container->get($target);
|
||||
}, false);
|
||||
$alias = $this->sanitizeName($alias);
|
||||
$target = $this->sanitizeName($target);
|
||||
if ($alias === $target) {
|
||||
throw new QueryNotFoundException('Can\'t alias to self');
|
||||
}
|
||||
unset($this->items[$alias]);
|
||||
$this->aliases[$alias] = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,17 +198,14 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitizeName($name) {
|
||||
if (isset($name[0]) && $name[0] === '\\') {
|
||||
return ltrim($name, '\\');
|
||||
}
|
||||
return $name;
|
||||
return ltrim($name, '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 20.0.0 use \Psr\Container\ContainerInterface::has
|
||||
*/
|
||||
public function offsetExists($id): bool {
|
||||
return $this->container->offsetExists($id);
|
||||
return array_key_exists($id, $this->items) || array_key_exists($id, $this->aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,20 +214,43 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($id) {
|
||||
return $this->container->offsetGet($id);
|
||||
return $this->query($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 20.0.0 use \OCP\IContainer::registerService
|
||||
*/
|
||||
public function offsetSet($offset, $value): void {
|
||||
$this->container->offsetSet($offset, $value);
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 20.0.0
|
||||
*/
|
||||
public function offsetUnset($offset): void {
|
||||
$this->container->offsetUnset($offset);
|
||||
unset($this->items[$offset]);
|
||||
unset($this->aliases[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we already have a resolved instance of $name
|
||||
*/
|
||||
public function isResolved($name): bool {
|
||||
if (!array_key_exists($name, $this->items)) {
|
||||
return false;
|
||||
}
|
||||
$item = $this->items[$name];
|
||||
if ($item instanceof ServiceFactory) {
|
||||
return false;
|
||||
} else {
|
||||
return !is_callable($item);
|
||||
}
|
||||
}
|
||||
|
||||
protected function resolveAlias(string $name): string {
|
||||
while (array_key_exists($name, $this->aliases)) {
|
||||
$name = $this->aliases[$name];
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ class ServerContainer extends SimpleContainer {
|
||||
* ServerContainer constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->appContainers = [];
|
||||
$this->namespaces = [];
|
||||
$this->hasNoAppContainer = [];
|
||||
@@ -119,26 +118,23 @@ class ServerContainer extends SimpleContainer {
|
||||
* @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get
|
||||
*/
|
||||
public function query(string $name, bool $autoload = true) {
|
||||
// if we have a resolved instance ourselves, there is no need to try and delegate
|
||||
// we check this before doing any sanitization, because usually the name already is sanitized
|
||||
if ($this->isResolved($name)) {
|
||||
return $this->items[$name];
|
||||
}
|
||||
$name = $this->sanitizeName($name);
|
||||
|
||||
if (str_starts_with($name, 'OCA\\')) {
|
||||
// Skip server container query for app namespace classes
|
||||
// In case the service starts with OCA\ we try to find the service in
|
||||
// the apps container first.
|
||||
if (!array_key_exists($name, $this->items) && !array_key_exists($name, $this->aliases) && ($appContainer = $this->getAppContainerForService($name)) !== null) {
|
||||
try {
|
||||
return parent::query($name, false);
|
||||
return $appContainer->queryNoFallback($name);
|
||||
} catch (QueryException $e) {
|
||||
// Continue with general autoloading then
|
||||
}
|
||||
// In case the service starts with OCA\ we try to find the service in
|
||||
// the apps container first.
|
||||
if (($appContainer = $this->getAppContainerForService($name)) !== null) {
|
||||
try {
|
||||
return $appContainer->queryNoFallback($name);
|
||||
} catch (QueryException $e) {
|
||||
// Didn't find the service or the respective app container
|
||||
// In this case the service won't be part of the core container,
|
||||
// so we can throw directly
|
||||
throw $e;
|
||||
}
|
||||
// Didn't find the service or the respective app container
|
||||
// In this case the service won't be part of the core container,
|
||||
// so we can throw directly
|
||||
throw $e;
|
||||
}
|
||||
} elseif (str_starts_with($name, 'OC\\Settings\\') && substr_count($name, '\\') >= 3) {
|
||||
$segments = explode('\\', $name);
|
||||
@@ -154,6 +150,13 @@ class ServerContainer extends SimpleContainer {
|
||||
return parent::query($name, $autoload);
|
||||
}
|
||||
|
||||
public function queryNoApps(string $name, bool $autoload = true) {
|
||||
if ($this->isResolved($name)) {
|
||||
return $this->items[$name];
|
||||
}
|
||||
return parent::query($name, $autoload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param string $id
|
||||
|
||||
Reference in New Issue
Block a user