feat(di): implement attribute resolver system for dependency injection
- Introduce `ParameterAttributeResolverInterface` for handling attribute-based parameter resolution. - Add `EnvAttributeResolver` to inject environment variables with type conversion. - Add `LogChannelAttributeResolver` to inject channel-specific loggers. - Create `ParameterAttributeResolverRegistry` to manage available resolvers. - Update `ParameterResolver` to delegate attribute resolution to the registry. - Add comprehensive unit tests for all attribute resolvers and registry functionality.
This commit is contained in:
@@ -14,6 +14,9 @@ use App\Framework\Logging\LogChannel;
|
||||
use App\Framework\Logging\Logger;
|
||||
use App\Framework\Logging\SupportsChannels;
|
||||
use App\Framework\Reflection\CachedReflectionProvider;
|
||||
use App\Framework\Config\Env as EnvAttribute;
|
||||
use App\Framework\Config\EnvKey;
|
||||
use App\Framework\Config\Environment;
|
||||
|
||||
// Test classes for parameter resolution
|
||||
final class ServiceWithLogChannelAttribute
|
||||
@@ -88,6 +91,29 @@ final class ServiceWithMixedParams
|
||||
}
|
||||
}
|
||||
|
||||
final class ServiceWithNullableInterface
|
||||
{
|
||||
public function __construct(public ?Logger $optionalLogger)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
final class ServiceWithNullableInterfaceResolved
|
||||
{
|
||||
public function __construct(public ?Logger $optionalLogger)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
final class ServiceWithEnvAttribute
|
||||
{
|
||||
public function __construct(
|
||||
#[EnvAttribute(EnvKey::APP_NAME)]
|
||||
public string $appName
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
$this->container = $this->createMock(Container::class);
|
||||
$this->reflectionProvider = new CachedReflectionProvider();
|
||||
@@ -200,6 +226,42 @@ describe('ParameterResolver', function () {
|
||||
expect($params[0])->toBeNull();
|
||||
});
|
||||
|
||||
it('resolves nullable interface from container when available', function () {
|
||||
$logger = $this->createMock(Logger::class);
|
||||
|
||||
$this->container->expects($this->once())
|
||||
->method('has')
|
||||
->with(Logger::class)
|
||||
->willReturn(true);
|
||||
|
||||
$this->container->expects($this->once())
|
||||
->method('get')
|
||||
->with(Logger::class)
|
||||
->willReturn($logger);
|
||||
|
||||
$className = ClassName::create(ServiceWithNullableInterfaceResolved::class);
|
||||
$params = $this->resolver->resolveMethodParameters($className, '__construct');
|
||||
|
||||
expect($params)->toHaveCount(1);
|
||||
expect($params[0])->toBe($logger);
|
||||
});
|
||||
|
||||
it('resolves nullable interface to null when container does not have it', function () {
|
||||
$this->container->expects($this->exactly(2))
|
||||
->method('has')
|
||||
->with(Logger::class)
|
||||
->willReturn(false);
|
||||
|
||||
$this->container->expects($this->never())
|
||||
->method('get');
|
||||
|
||||
$className = ClassName::create(ServiceWithNullableInterface::class);
|
||||
$params = $this->resolver->resolveMethodParameters($className, '__construct');
|
||||
|
||||
expect($params)->toHaveCount(1);
|
||||
expect($params[0])->toBeNull();
|
||||
});
|
||||
|
||||
it('throws exception when parameter cannot be resolved', function () {
|
||||
$this->container->method('has')->willReturn(false);
|
||||
|
||||
@@ -253,4 +315,24 @@ describe('ParameterResolver', function () {
|
||||
// Nullable
|
||||
expect($params[4])->toBeNull();
|
||||
});
|
||||
|
||||
it('resolves Env attribute from environment', function () {
|
||||
$environment = $this->createMock(Environment::class);
|
||||
|
||||
$environment->expects($this->once())
|
||||
->method('getString')
|
||||
->with(EnvKey::APP_NAME, '')
|
||||
->willReturn('Test App Name');
|
||||
|
||||
$this->container->expects($this->once())
|
||||
->method('get')
|
||||
->with(Environment::class)
|
||||
->willReturn($environment);
|
||||
|
||||
$className = ClassName::create(ServiceWithEnvAttribute::class);
|
||||
$params = $this->resolver->resolveMethodParameters($className, '__construct');
|
||||
|
||||
expect($params)->toHaveCount(1);
|
||||
expect($params[0])->toBe('Test App Name');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user