Skip to content

Commit a00907d

Browse files
authored
Merge pull request #292 from ray-di/optional-setter-injection
Handle missing dependencies in setter methods with @Inject(optional=true)
2 parents 3155fc6 + ff8f66c commit a00907d

File tree

12 files changed

+369
-308
lines changed

12 files changed

+369
-308
lines changed

src/di/AspectBind.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function __construct(AopBind $bind)
2222
/**
2323
* Instantiate interceptors
2424
*
25-
* @return array<string, array<MethodInterceptor>>
25+
* @return array<string, list<MethodInterceptor>>
2626
*/
2727
public function inject(Container $container): array
2828
{
@@ -32,7 +32,6 @@ public function inject(Container $container): array
3232
$interceptors = [];
3333
foreach ($interceptorClassNames as $interceptorClassName) {
3434
/** @var class-string $interceptorClassName */
35-
/** @psalm-suppress MixedAssignment */
3635
$interceptor = $container->getInstance($interceptorClassName);
3736
assert($interceptor instanceof MethodInterceptor);
3837
$interceptors[] = $interceptor;

src/di/AssistedInjectInterceptor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public function invoke(MethodInvocation $invocation)
6363
}
6464

6565
/**
66+
* @param MethodInvocation<object> $invocation
67+
*
6668
* @return array<string, mixed>
6769
*/
6870
private function getNamedArguments(MethodInvocation $invocation): array

src/di/ContainerFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
final class ContainerFactory
1212
{
1313
/**
14-
* @param AbstractModule|non-empty-array<AbstractModule>|null $module Module(s)
14+
* @param non-empty-string $classDir
15+
* @param AbstractModule|non-empty-array<AbstractModule>|null $module Module(s)
1516
*/
1617
public function __invoke($module, string $classDir): Container
1718
{

src/di/Dependency.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public function weaveAspects(CompilerInterface $compiler, array $pointcuts): voi
144144

145145
$class = $compiler->compile($className, $bind);
146146
/** @psalm-suppress ArgumentTypeCoercion */
147-
$this->newInstance->weaveAspects($class, $bind); // @phpstan-ignore-line
147+
$this->newInstance->weaveAspects($class, $bind);
148148
}
149149

150150
/** @inheritDoc */
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Ray\Di\Exception;
6+
7+
use RuntimeException;
8+
9+
class DirectoryNotWritable extends RuntimeException implements ExceptionInterface
10+
{
11+
}

src/di/Grapher.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414

1515
final class Grapher
1616
{
17-
/** @var string */
17+
/** @var non-empty-string */
1818
private $classDir;
1919

2020
/** @var Container */
2121
private $container;
2222

2323
/**
24-
* @param AbstractModule $module Binding module
24+
* @param AbstractModule $module Binding module
25+
* @param non-empty-string $classDir Class directory
2526
*
2627
* @throws AnnotationException
2728
*/

src/di/Injector.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@
66

77
use Doctrine\Common\Annotations\AnnotationException;
88
use Ray\Aop\Compiler;
9+
use Ray\Di\Exception\DirectoryNotWritable;
910
use Ray\Di\Exception\Untargeted;
1011

1112
use function assert;
1213
use function file_exists;
1314
use function is_dir;
15+
use function is_writable;
1416
use function spl_autoload_register;
1517
use function sprintf;
1618
use function str_replace;
1719
use function sys_get_temp_dir;
1820

1921
class Injector implements InjectorInterface
2022
{
21-
/** @var string */
23+
/** @var non-empty-string */
2224
private $classDir;
2325

2426
/** @var Container */
@@ -30,7 +32,13 @@ class Injector implements InjectorInterface
3032
*/
3133
public function __construct($module = null, string $tmpDir = '')
3234
{
33-
$this->classDir = is_dir($tmpDir) ? $tmpDir : sys_get_temp_dir();
35+
/** @var non-empty-string $classDir */
36+
$classDir = is_dir($tmpDir) ? $tmpDir : sys_get_temp_dir();
37+
if (! is_writable($classDir)) {
38+
throw new DirectoryNotWritable($classDir); // @CodeCoverageIgnore
39+
}
40+
41+
$this->classDir = $classDir;
3442
$this->container = (new ContainerFactory())($module, $this->classDir);
3543
// Bind injector (built-in bindings)
3644
(new Bind($this->container, InjectorInterface::class))->toInstance($this);

src/di/MethodInvocationProvider.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@
1212
*/
1313
final class MethodInvocationProvider implements ProviderInterface
1414
{
15-
/** @var ?MethodInvocation */
15+
/** @var ?MethodInvocation<object> */
1616
private $invocation;
1717

18+
/**
19+
* @param MethodInvocation<object> $invocation
20+
*/
1821
public function set(MethodInvocation $invocation): void
1922
{
2023
$this->invocation = $invocation;
2124
}
2225

26+
/**
27+
* @return MethodInvocation<object>
28+
*/
2329
public function get(): MethodInvocation
2430
{
2531
if ($this->invocation === null) {

src/di/MultiBinding/LazyTo.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ public function __construct(string $class)
2727
*/
2828
public function __invoke(InjectorInterface $injector)
2929
{
30-
return $injector->getInstance($this->class); // @phpstan-ignore-line
30+
return $injector->getInstance($this->class);
3131
}
3232
}

src/di/SetterMethod.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ public function setOptional(): void
6767
/** @inheritDoc */
6868
public function accept(VisitorInterface $visitor)
6969
{
70-
$visitor->visitSetterMethod($this->method, $this->arguments);
70+
try {
71+
$visitor->visitSetterMethod($this->method, $this->arguments);
72+
} catch (Unbound $e) {
73+
if ($this->isOptional) {
74+
// Return when no dependency given and @Inject(optional=true) annotated to setter method.
75+
return;
76+
}
77+
78+
// Throw exception when no dependency given and @Inject(optional=false) annotated to setter method.
79+
throw $e;
80+
}
7181
}
7282
}

0 commit comments

Comments
 (0)