Update reflection container to support manual injecting
This commit is contained in:
35
src/Libs/Attributes/DI/Inject.php
Normal file
35
src/Libs/Attributes/DI/Inject.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Libs\Attributes\DI;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
readonly class Inject
|
||||
{
|
||||
/**
|
||||
* Dynamically override dependency resolve. This is useful when you want to
|
||||
* resolve a dependency to a specific class which is not the same as the
|
||||
* type-hinted interface.
|
||||
*
|
||||
* For example, you have an interface `LoggerInterface` and you have two
|
||||
* classes that implement this interface: `FileLogger` and `DatabaseLogger`.
|
||||
* And you want to resolve the `LoggerInterface` to `FileLogger` when it is
|
||||
* type-hinted in a constructor. You can use this attribute to achieve that.
|
||||
* By doing the following:
|
||||
*
|
||||
* <code>
|
||||
* class Example
|
||||
* {
|
||||
* public function __invoke(#[Inject(FileLogger::class)] private LoggerInterface $logger) {}
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(public string $name)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs\Extends;
|
||||
|
||||
use App\Libs\Attributes\DI\Inject;
|
||||
use League\Container\Argument\{ArgumentInterface,
|
||||
ArgumentResolverInterface,
|
||||
DefaultValueArgument,
|
||||
@@ -200,6 +201,24 @@ class ReflectionContainer implements ArgumentResolverInterface, ContainerInterfa
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes = $param->getAttributes(Inject::class);
|
||||
if (count($attributes) > 0) {
|
||||
$injector = $attributes[0]->newInstance();
|
||||
assert($injector instanceof Inject);
|
||||
if (array_key_exists($injector->name, $args)) {
|
||||
$arguments[] = new LiteralArgument($args[$injector->name]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
$arguments[] = new DefaultValueArgument($injector->name, $param->getDefaultValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments[] = new ResolvableArgument($injector->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $param->getType();
|
||||
|
||||
if ($type instanceof ReflectionNamedType) {
|
||||
@@ -225,12 +244,10 @@ class ReflectionContainer implements ArgumentResolverInterface, ContainerInterfa
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new NotFoundException(
|
||||
r("Unable to resolve a value for parameter '{param}' in the function/method '{method}'.", [
|
||||
'param' => $name,
|
||||
'method' => $method->getName(),
|
||||
])
|
||||
);
|
||||
throw new NotFoundException(r("Unable to resolve a value for parameter '{param}' in '{method}'.", [
|
||||
'param' => $name,
|
||||
'method' => $method->getName(),
|
||||
]));
|
||||
}
|
||||
|
||||
return $this->resolveArguments($arguments);
|
||||
|
||||
Reference in New Issue
Block a user