You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web/Sources/src/app/Container.php

109 lines
3.0 KiB

<?php
namespace App;
use Psr\Container\ContainerInterface;
use Shared\Log;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
class Container implements ContainerInterface
{
private array $entries = [];
public function get(string $id)
{
if ($this->has($id)) {
$entry = $this->entries[$id];
if (is_callable($entry)) {
return $entry($this);
}
$id = $entry;
}
return $this->resolve($id);
}
public function has(string $id): bool
{
return isset($this->entries[$id]);
}
public function set(string $id, callable|string $concrete): void
{
$this->entries[$id] = $concrete;
}
public function resolve(string $id)
{
// 1. Inspect the class that we are trying to get from the container
try {
$reflectionClass = new \ReflectionClass($id);
} catch (\ReflectionException $e) {
throw new \Exception($e->getMessage(), $e->getCode(), $e);
}
if (!$reflectionClass->isInstantiable()) {
throw new \Exception('Class "' . $id . '" is not instantiable');
}
// 2. Inspect the constructor of the class
$constructor = $reflectionClass->getConstructor();
if (!$constructor) {
return new $id;
}
// 3. Inspect the constructor parameters (dependencies)
$parameters = $constructor->getParameters();
if (!$parameters) {
return new $id;
}
// 4. If the constructor parameter is a class then try to resolve that class using the container
$dependencies = array_map(
function (\ReflectionParameter $param) use ($id) {
$name = $param->getName();
$type = $param->getType();
// Check for a default value
if ($param->isDefaultValueAvailable()) {
return $param->getDefaultValue();
}
if (!$type) {
throw new \Exception(
'Failed to resolve class "' . $id . '" because param "' . $name . '" is missing a type hint'
);
}
if ($type instanceof \ReflectionUnionType) {
throw new \Exception(
'Failed to resolve class "' . $id . '" because of union type for param "' . $name . '"'
);
}
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
return $this->get($type->getName());
}
throw new \Exception(
'Failed to resolve class "' . $id . '" because invalid param "' . $name . '"'
);
},
$parameters
);
return $reflectionClass->newInstanceArgs($dependencies);
}
public function getAllRegisteredClassNames(): array
{
return array_keys($this->entries);
}
}