Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 42 additions & 49 deletions src/DI/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,37 @@

namespace Utopia\DI;

use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Utopia\DI\Exceptions\ContainerException;
use Utopia\DI\Exceptions\NotFoundException;

/**
* @phpstan-consistent-constructor
*/
class Container implements ContainerInterface
{
/**
* @var array<string, callable(ContainerInterface): mixed>
* Map of dependency IDs to their required dependency IDs.
*
* @var array<string, list<string>>
*/
private array $definitions = [];
private array $dependencies = [];

/**
* @var array<string, mixed>
* Map of dependency IDs to their factory callables.
*
* @var array<string, callable>
*/
private array $resolved = [];
private array $factories = [];

/**
* @var array<string, true>
* Map of dependency IDs to a cache of resolved instances.
*
* @var array<string, mixed>
*/
private array $resolving = [];
private array $concrete = [];

/**
* @param ContainerInterface|null $parent Optional parent container for hierarchical resolution.
*/
public function __construct(
private readonly ?ContainerInterface $parent = null,
) {
Expand All @@ -35,74 +41,61 @@ public function __construct(
/**
* Register a dependency factory on the current container.
*
* @param callable(ContainerInterface): mixed $factory
* If a dependency with the same ID already exists, it will be overridden.
*
* @param string $id Unique identifier for the dependency.
* @param callable $factory Factory callable invoked to create the instance.
* @param list<string> $dependencies List of dependency IDs required by the factory.
*/
Comment thread
loks0n marked this conversation as resolved.
public function set(string $key, callable $factory): static
public function set(string $id, callable $factory, array $dependencies): static
{
$this->definitions[$key] = $factory;
unset($this->resolved[$key]);
$this->factories[$id] = $factory;
$this->dependencies[$id] = $dependencies;

return $this;
}

/**
* Resolve an entry from the current container or its parent chain.
*
*
* @throws ContainerExceptionInterface
*/
public function get(string $id): mixed
{
if (\array_key_exists($id, $this->resolved)) {
return $this->resolved[$id];
if (\array_key_exists($id, $this->concrete)) {
return $this->concrete[$id];
}

if (\array_key_exists($id, $this->definitions)) {
if (isset($this->resolving[$id])) {
throw new ContainerException('Circular dependency detected for "'.$id.'".');
}

$this->resolving[$id] = true;

try {
$resolved = ($this->definitions[$id])($this);
} catch (NotFoundException|ContainerExceptionInterface $exception) {
throw $exception;
} catch (\Throwable $exception) {
throw new ContainerException(
'Failed to resolve dependency "'.$id.'".',
previous: $exception
);
} finally {
unset($this->resolving[$id]);
}

$this->resolved[$id] = $resolved;

return $resolved;
if (\array_key_exists($id, $this->factories)) {
$concrete = $this->build($id);
$this->concrete[$id] = $concrete;
return $concrete;
}

if ($this->parent instanceof ContainerInterface) {
return $this->parent->get($id);
}

throw new NotFoundException('Dependency not found: '.$id);
throw new Exceptions\NotFoundException("Dependency $id not found");
}

public function has(string $id): bool
{
if (\array_key_exists($id, $this->definitions)) {
if (\array_key_exists($id, $this->factories)) {
return true;
}

return $this->parent?->has($id) ?? false;
}

/**
* Create a child container that falls back to the current container.
* Build a dependency by resolving its dependencies and invoking its factory.
*
* @param string $id Identifier of the dependency to build.
* @return mixed The constructed dependency instance.
*/
public function scope(): static
private function build(string $id): mixed
{
return new static($this);
$dependencies = [];
foreach ($this->dependencies[$id] as $dependency) {
$dependencies[] = $this->get($dependency);
}

return \call_user_func($this->factories[$id], ...$dependencies);
}
Comment thread
loks0n marked this conversation as resolved.
}
32 changes: 0 additions & 32 deletions src/DI/Dependency.php

This file was deleted.

Loading
Loading