Properly implement the router with config and interfaces

Expand the container with aliases and argument autowiring
This commit is contained in:
Tim
2023-08-07 17:50:34 +02:00
parent e9a636554f
commit a55d1c3c2e
11 changed files with 406 additions and 48 deletions

View File

@ -3,19 +3,20 @@
namespace Ardent\Undercurrent\Container;
use Exception;
use ReflectionClass;
class GenericContainer
class GenericContainer implements ContainerInterface
{
private array $definitions = [];
private array $instances = [];
private array $aliases = [];
public function add(string $className, ?callable $definition = null, bool $singleton = true): self
{
if (!$definition) {
$definition = function () use ($className) {
return new $className();
};
$definition = fn() => $this->autowire($className);
}
$this->definitions[$className] = [
@ -26,29 +27,57 @@ class GenericContainer
return $this;
}
public function alias(string $alias, string $className): self
{
$this->aliases[$alias] = $className;
return $this;
}
/**
* @template TClassName
* @param class-string<TClassName> $className
* @return TClassName
* @throws Exception
* @inheritDoc
*/
public function get(string $className): object
{
if (isset($this->aliases[$className])) {
$className = $this->aliases[$className];
}
if (!isset($this->definitions[$className])) {
throw new Exception("Class $className not found in container");
}
$definition = $this->definitions[$className]['definition'];
if ($this->definitions[$className]['singleton']) {
if (isset($this->instances[$className])) {
return $this->instances[$className];
}
$instance = $definition();
$instance = $definition($this);
$this->instances[$className] = $instance;
} else {
$instance = $definition();
$instance = $definition($this);
}
return $instance;
}
private function autowire(string $className): ?object
{
$reflection = new ReflectionClass($className);
$constructor = $reflection->getConstructor();
if (!$constructor) {
return new $className();
}
$params = [];
foreach ($constructor->getParameters() as $parameter) {
$type = $parameter->getType();
if (!$type) {
throw new Exception("Parameter {$parameter->getName()} in $className has no type");
}
$params[] = $this->get($type->getName());
}
return new $className(...$params);
}
}