Description:
I would like to enhance the DI Container in the Pancake project to support auto-registration for services that are not explicitly registered in the container. This auto-registration feature should be enabled by default but configurable via a flag. Additionally, the container should be able to automatically resolve all dependencies, including constructor dependencies, for services that are auto-registered.
Related to #235
Below is an updated code example for the DIContainer class illustrating the requested functionality:
Updated DIContainer Example
<?php
namespace GuiBranco\Pancake;
class DIContainer
{
private array $services = [];
private array $sharedInstances = [];
private bool $autoRegisterEnabled = true;
public function __construct(bool $autoRegisterEnabled = true)
{
$this->autoRegisterEnabled = $autoRegisterEnabled;
}
public function register(string $name, callable $resolver, bool $shared = false)
{
$this->services[$name] = [
'resolver' => $resolver,
'shared' => $shared,
];
}
public function resolve(string $name)
{
if (isset($this->services[$name])) {
if ($this->services[$name]['shared']) {
if (!isset($this->sharedInstances[$name])) {
$this->sharedInstances[$name] = $this->services[$name]['resolver']($this);
}
return $this->sharedInstances[$name];
}
return $this->services[$name]['resolver']($this);
}
if ($this->autoRegisterEnabled) {
return $this->autoRegister($name);
}
throw new \Exception("Service '{$name}' not registered.");
}
private function autoRegister(string $name)
{
if (!class_exists($name)) {
throw new \Exception("Class '{$name}' does not exist.");
}
$reflectionClass = new \ReflectionClass($name);
$constructor = $reflectionClass->getConstructor();
if ($constructor === null) {
return new $name(); // No constructor, no dependencies.
}
$parameters = $constructor->getParameters();
$dependencies = [];
foreach ($parameters as $parameter) {
$parameterClass = $parameter->getType() ? $parameter->getType()->getName() : null;
if ($parameterClass && class_exists($parameterClass)) {
$dependencies[] = $this->resolve($parameterClass);
} else {
throw new \Exception("Cannot resolve parameter '{$parameter->getName()}' for class '{$name}'.");
}
}
return $reflectionClass->newInstanceArgs($dependencies);
}
public function registerSingleton(string $name, callable $resolver)
{
$this->register($name, $resolver, true);
}
public function registerTransient(string $name, callable $resolver)
{
$this->register($name, $resolver, false);
}
public function setAutoRegisterEnabled(bool $enabled)
{
$this->autoRegisterEnabled = $enabled;
}
}
New Features:
-
Auto-Registration of Services:
- If a service is not found in the registration array, the DI container will attempt to auto-register it by resolving its constructor dependencies.
- This auto-registration feature is enabled by default, but can be controlled using the
setAutoRegisterEnabled method.
-
Dependency Resolution:
- The DI container will automatically resolve constructor dependencies for both explicitly registered and auto-registered services.
- It will recursively resolve dependencies for services that require other services as constructor arguments.
Example of Auto-Registration:
<?php
// Assume a service with dependencies
class ServiceA {
public function __construct(ServiceB $serviceB) { }
}
class ServiceB {
public function __construct(ServiceC $serviceC) { }
}
class ServiceC {
public function __construct() { }
}
$container = new \GuiBranco\PocMvc\Src\Core\DIContainer();
// Automatically registers and resolves ServiceA, along with its dependencies (ServiceB, ServiceC)
$serviceA = $container->resolve(ServiceA::class);
Task Requirements:
- Add auto-registration functionality to the DI Container with support for resolving dependencies via reflection.
- Include a flag to enable/disable auto-registration (enabled by default).
- Ensure that both registered and auto-registered services have their dependencies resolved recursively.
Additional Requirements:
- Provide unit tests to verify:
- Auto-registration of services when not explicitly registered.
- Dependency resolution, including recursive dependencies.
- Correct behavior when auto-registration is disabled.
- Include integration tests to validate the new functionality in practical use cases.
Acceptance Criteria:
Description:
I would like to enhance the DI Container in the Pancake project to support auto-registration for services that are not explicitly registered in the container. This auto-registration feature should be enabled by default but configurable via a flag. Additionally, the container should be able to automatically resolve all dependencies, including constructor dependencies, for services that are auto-registered.
Related to #235
Below is an updated code example for the DIContainer class illustrating the requested functionality:
Updated DIContainer Example
New Features:
Auto-Registration of Services:
setAutoRegisterEnabledmethod.Dependency Resolution:
Example of Auto-Registration:
Task Requirements:
Additional Requirements:
Acceptance Criteria: