Skip to content

Commit 0859463

Browse files
committed
Add tests for unresolvable argument dependencies
1 parent fa19cb5 commit 0859463

File tree

4 files changed

+120
-8
lines changed

4 files changed

+120
-8
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Technically\DependencyResolver\Specs\Fixtures;
4+
5+
final class MyUnresolvableScalarArgumentService
6+
{
7+
public $name;
8+
9+
public function __construct(string $name)
10+
{
11+
$this->name = $name;
12+
}
13+
}

specs/dependency-resolver.spec.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
use Psr\Container\ContainerInterface;
44
use Technically\ArrayContainer\ArrayContainer;
55
use Technically\DependencyResolver\DependencyResolver;
6+
use Technically\DependencyResolver\Exceptions\CannotAutowireDependencyArgument;
67
use Technically\DependencyResolver\Exceptions\ClassCannotBeInstantiated;
78
use Technically\DependencyResolver\Specs\Fixtures\MyAbstractClass;
89
use Technically\DependencyResolver\Specs\Fixtures\MyConcreteContainerService;
910
use Technically\DependencyResolver\Specs\Fixtures\MyAbstractContainerService;
1011
use Technically\DependencyResolver\Specs\Fixtures\MyNullableArgumentService;
1112
use Technically\DependencyResolver\Specs\Fixtures\MyOptionalArgumentService;
13+
use Technically\DependencyResolver\Specs\Fixtures\MyUnresolvableScalarArgumentService;
1214

1315
describe('DependencyResolver', function() {
1416
it('should instantiate', function () {
@@ -85,4 +87,38 @@
8587
assert($exception instanceof ClassCannotBeInstantiated);
8688
assert($exception->getClassName() === MyAbstractClass::class);
8789
});
90+
91+
it('should throw exception if dependency class cannot be autowired', function () {
92+
$container = new ArrayContainer();
93+
$resolver = new DependencyResolver($container);
94+
95+
try {
96+
$resolver->resolve(MyAbstractContainerService::class);
97+
} catch (Exception $exception) {
98+
// passthru
99+
}
100+
101+
assert(isset($exception));
102+
assert($exception instanceof CannotAutowireDependencyArgument);
103+
assert($exception->getDependencyName() === MyAbstractContainerService::class);
104+
assert($exception->getArgumentName() === 'container');
105+
assert($exception->getMessage() === 'Could not autowire argument `container` for `Technically\DependencyResolver\Specs\Fixtures\MyAbstractContainerService`.');
106+
});
107+
108+
it('should throw exception if scalar dependency cannot be autowired', function () {
109+
$container = new ArrayContainer();
110+
$resolver = new DependencyResolver($container);
111+
112+
try {
113+
$resolver->resolve(MyUnresolvableScalarArgumentService::class);
114+
} catch (Exception $exception) {
115+
// passthru
116+
}
117+
118+
assert(isset($exception));
119+
assert($exception instanceof CannotAutowireDependencyArgument);
120+
assert($exception->getDependencyName() === MyUnresolvableScalarArgumentService::class);
121+
assert($exception->getArgumentName() === 'name');
122+
assert($exception->getMessage() === 'Could not autowire argument `name` for `Technically\DependencyResolver\Specs\Fixtures\MyUnresolvableScalarArgumentService`.');
123+
});
88124
});

src/DependencyResolver.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Technically\DependencyResolver;
44

5-
use LogicException;
5+
use Psr\Container\ContainerExceptionInterface;
66
use Psr\Container\ContainerInterface;
77
use ReflectionClass;
88
use ReflectionMethod;
@@ -11,7 +11,9 @@
1111
use ReflectionUnionType;
1212
use Technically\DependencyResolver\Arguments\Argument;
1313
use Technically\DependencyResolver\Arguments\Type;
14+
use Technically\DependencyResolver\Exceptions\CannotAutowireDependencyArgument;
1415
use Technically\DependencyResolver\Exceptions\ClassCannotBeInstantiated;
16+
use Technically\DependencyResolver\Exceptions\DependencyResolutionException;
1517

1618
final class DependencyResolver
1719
{
@@ -48,7 +50,7 @@ public function resolve(string $className, array $bindings = [])
4850

4951
if ($constructor = $reflection->getConstructor()) {
5052
$arguments = $this->parseArguments($constructor);
51-
$values = $this->resolveArguments($arguments, $bindings);
53+
$values = $this->resolveArguments($className, $arguments, $bindings);
5254
}
5355

5456
return $reflection->newInstanceArgs($values);
@@ -77,28 +79,34 @@ private function parseArguments(ReflectionMethod $function): array
7779
}
7880

7981
/**
82+
* @param string $className
8083
* @param Argument[] $arguments
8184
* @param array $bindings
8285
* @return array
86+
*
87+
* @throws CannotAutowireDependencyArgument
8388
* @throws \Psr\Container\ContainerExceptionInterface
8489
* @throws \Psr\Container\NotFoundExceptionInterface
8590
*/
86-
private function resolveArguments(array $arguments, array $bindings = []): array
91+
private function resolveArguments(string $className, array $arguments, array $bindings = []): array
8792
{
8893
$values = [];
8994
foreach ($arguments as $argument) {
90-
$values[] = $this->resolveArgument($argument, $bindings);
95+
$values[] = $this->resolveArgument($className, $argument, $bindings);
9196
}
9297

9398
return $values;
9499
}
95100

96101
/**
102+
* @param string $className
97103
* @param Argument $argument
98104
* @param array $bindings
99105
* @return mixed|null
106+
*
107+
* @throws CannotAutowireDependencyArgument
100108
*/
101-
private function resolveArgument(Argument $argument, array $bindings)
109+
private function resolveArgument(string $className, Argument $argument, array $bindings)
102110
{
103111
if (array_key_exists($argument->getName(), $bindings)) {
104112
return $bindings[$argument->getName()];
@@ -107,7 +115,11 @@ private function resolveArgument(Argument $argument, array $bindings)
107115
foreach ($argument->getTypes() as $type) {
108116
$class = $type->getClassName();
109117
if (! empty($class) && $this->container->has($class)) {
110-
return $this->container->get($class);
118+
try {
119+
return $this->container->get($class);
120+
} catch (ContainerExceptionInterface $exception) {
121+
throw new CannotAutowireDependencyArgument($className, $argument->getName());
122+
}
111123
}
112124
}
113125

@@ -121,11 +133,15 @@ private function resolveArgument(Argument $argument, array $bindings)
121133

122134
foreach ($argument->getTypes() as $type) {
123135
if ($class = $type->getClassName()) {
124-
return $this->resolve($class);
136+
try {
137+
return $this->resolve($class);
138+
} catch (DependencyResolutionException $exception) {
139+
// try another one
140+
}
125141
}
126142
}
127143

128-
throw new LogicException("Cannot resolve argument: `{$argument->getName()}`.");
144+
throw new CannotAutowireDependencyArgument($className, $argument->getName());
129145
}
130146

131147
private static function reflectClass(string $class): ReflectionClass
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Technically\DependencyResolver\Exceptions;
4+
5+
use Throwable;
6+
7+
final class CannotAutowireDependencyArgument extends DependencyResolutionException
8+
{
9+
/**
10+
* @var string
11+
*/
12+
private $dependencyName;
13+
14+
/**
15+
* @var string
16+
*/
17+
private $argumentName;
18+
19+
/**
20+
* @param string $dependencyName
21+
* @param string $argumentName
22+
* @param Throwable|null $previous
23+
*/
24+
public function __construct(string $dependencyName, string $argumentName, Throwable $previous = null)
25+
{
26+
$this->dependencyName = $dependencyName;
27+
$this->argumentName = $argumentName;
28+
29+
parent::__construct("Could not autowire argument `{$argumentName}` for `${dependencyName}`.", 0, $previous);
30+
}
31+
32+
/**
33+
* @return string
34+
*/
35+
public function getDependencyName(): string
36+
{
37+
return $this->dependencyName;
38+
}
39+
40+
/**
41+
* @return string
42+
*/
43+
public function getArgumentName(): string
44+
{
45+
return $this->argumentName;
46+
}
47+
}

0 commit comments

Comments
 (0)