Skip to content

Commit

Permalink
going nuclear: ripping out pimple
Browse files Browse the repository at this point in the history
Signed-off-by: Robin Appelman <robin@icewind.nl>
  • Loading branch information
icewind1991 committed Feb 8, 2023
1 parent 407ee8e commit 23aab0c
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 48 deletions.
4 changes: 2 additions & 2 deletions lib/private/AppFramework/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static function getAppIdForClass(string $className, string $topNamespace
* @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
*/
Expand Down Expand Up @@ -241,7 +241,7 @@ public static function main(string $controllerName, string $methodName, DIContai
* 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) {
Expand Down
9 changes: 7 additions & 2 deletions lib/private/AppFramework/DependencyInjection/DIContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ 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['appName'] = $appName;
$this['urlParams'] = $urlParams;
Expand Down Expand Up @@ -455,6 +454,8 @@ 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)) {
Expand All @@ -480,7 +481,7 @@ public function query(string $name, bool $autoload = true) {
* @return mixed
* @throws QueryException if the query could not be resolved
*/
public function queryNoFallback($name) {
public function queryNoFallback(string $name) {
$name = $this->sanitizeName($name);

if ($this->offsetExists($name)) {
Expand All @@ -496,4 +497,8 @@ public function queryNoFallback($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));
}
}
19 changes: 19 additions & 0 deletions lib/private/AppFramework/Utility/ServiceFactory.php
Original file line number Diff line number Diff line change
@@ -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);
}
}
90 changes: 50 additions & 40 deletions lib/private/AppFramework/Utility/SimpleContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
use Closure;
use OCP\AppFramework\QueryException;
use OCP\IContainer;
use Pimple\Container;
use Psr\Container\ContainerInterface;
use ReflectionClass;
use ReflectionException;
Expand All @@ -42,17 +41,11 @@
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 {
/** @var Container */
private $container;
/** @var array<string, string[]> */
private array $aliasesByService = [];

public function __construct() {
$this->container = new Container();
}
protected array $items = [];
protected array $aliases = [];

/**
* @template T
Expand All @@ -69,7 +62,7 @@ public function get(string $id) {

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 isset($this->items[$id]) || class_exists($id);
}

/**
Expand Down Expand Up @@ -136,13 +129,21 @@ public function resolve($name) {

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 (isset($this->items[$name])) {
$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->container[$name] = $object;
$this->items[$name] = $object;
return $object;
}

Expand All @@ -154,7 +155,7 @@ public function query(string $name, bool $autoload = true) {
* @param mixed $value
*/
public function registerParameter($name, $value) {
$this[$name] = $value;
$this->items[$name] = $value;
}

/**
Expand All @@ -167,26 +168,11 @@ public function registerParameter($name, $value) {
* @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[$name])) {
unset($this[$name]);

// when overriding, we need to re-point any aliases
if (isset($this->aliasesByService[$name])) {
foreach ($this->aliasesByService[$name] as $alias) {
$this->registerService($alias, function (ContainerInterface $container) use ($name) {
return $container->get($name);
});
}
}
}
if ($shared) {
$this[$name] = $wrapped;
$this->items[$name] = $closure;
} else {
$this[$name] = $this->container->factory($wrapped);
$this->items[$name] = new ServiceFactory($this, $closure);
}
}

Expand All @@ -198,10 +184,12 @@ public function registerService($name, Closure $closure, $shared = true) {
* @param string $target the target that should be resolved instead
*/
public function registerAlias($alias, $target) {
$this->aliasesByService[$target][] = $alias;
$this->registerService($alias, function (ContainerInterface $container) use ($target) {
return $container->get($target);
});
$alias = $this->sanitizeName($alias);
$target = $this->sanitizeName($target);
if ($alias === $target) {
throw new QueryNotFoundException('Can\'t alias to self');
}
$this->aliases[$alias] = $target;
}

/*
Expand All @@ -216,7 +204,7 @@ protected function sanitizeName($name) {
* @deprecated 20.0.0 use \Psr\Container\ContainerInterface::has
*/
public function offsetExists($id): bool {
return $this->container->offsetExists($id);
return isset($this->items[$id]);
}

/**
Expand All @@ -225,20 +213,42 @@ public function offsetExists($id): bool {
*/
#[\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($id, $service): void {
$this->container->offsetSet($id, $service);
$this->items[$id] = $service;
}

/**
* @deprecated 20.0.0
*/
public function offsetUnset($offset): void {
$this->container->offsetUnset($offset);
unset($this->items[$offset]);
}

/**
* Check if we already have a resolved instance of $name
*/
public function isResolved($name): bool {
if (!isset($this->items[$name])) {
return false;
}
$item = $this->items[$name];
if ($item instanceof ServiceFactory) {
return false;
} else {
return !is_callable($item);
}
}

protected function resolveAlias(string $name): string {
while (isset($this->aliases[$name])) {
$name = $this->aliases[$name];
}
return $name;
}
}
7 changes: 3 additions & 4 deletions lib/private/ServerContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ class ServerContainer extends SimpleContainer {
* ServerContainer constructor.
*/
public function __construct() {
parent::__construct();
$this->appContainers = [];
$this->namespaces = [];
$this->hasNoAppContainer = [];
Expand Down Expand Up @@ -137,9 +136,9 @@ public function has($id, bool $noRecursion = false): bool {
* @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get
*/
public function query(string $name, bool $autoload = true) {
// short circuit if have a registered instance ourselves
if (isset($this[$name])) {
return $this[$name];
// if we have a resolved instance ourselves, there is no need to try and delegate
if ($this->isResolved($name)) {
return $this->items[$name];
}
$name = $this->sanitizeName($name);

Expand Down

0 comments on commit 23aab0c

Please sign in to comment.