6
6
7
7
use DI \Annotation \Inject ;
8
8
use DI \Annotation \Injectable ;
9
+ use DI \Definition \AutowireDefinition ;
9
10
use DI \Definition \Exception \InvalidAnnotation ;
10
11
use DI \Definition \ObjectDefinition ;
11
12
use DI \Definition \ObjectDefinition \MethodInjection ;
32
33
*/
33
34
class AnnotationBasedAutowiring implements DefinitionSource, Autowiring
34
35
{
36
+ // Annotations configuration flags:
37
+ // enable on implicit definitions
38
+ const IMPLICIT = 1 ;
39
+ // enable on all autowire definitions (which are written in DI config) by default
40
+ const EXPLICIT = 2 ;
41
+ // read @Injectable annotations for classes
42
+ const INJECTABLE = 4 ;
43
+ // read @Inject annotations for properties
44
+ const PROPERTIES = 8 ;
45
+ // read @Inject annotations for methods' parameters
46
+ const METHODS = 16 ;
47
+ // all options enabled
48
+ const ALL = 31 ;
49
+
50
+ /**
51
+ * @var int
52
+ */
53
+ private $ flags ;
54
+
35
55
/**
36
56
* @var Reader
37
57
*/
@@ -47,9 +67,10 @@ class AnnotationBasedAutowiring implements DefinitionSource, Autowiring
47
67
*/
48
68
private $ ignorePhpDocErrors ;
49
69
50
- public function __construct ($ ignorePhpDocErrors = false )
70
+ public function __construct ($ ignorePhpDocErrors = false , int $ flags = 0 )
51
71
{
52
72
$ this ->ignorePhpDocErrors = (bool ) $ ignorePhpDocErrors ;
73
+ $ this ->flags = $ flags > 0 ? $ flags : self ::ALL ; // all flags turned on by default
53
74
}
54
75
55
76
public function autowire (string $ name , ObjectDefinition $ definition = null )
@@ -61,16 +82,35 @@ public function autowire(string $name, ObjectDefinition $definition = null)
61
82
}
62
83
63
84
$ definition = $ definition ?: new ObjectDefinition ($ name );
85
+ $ useAnnotations = $ definition instanceof AutowireDefinition
86
+ ? ($ definition ->isUsingAnnotations () ?? ($ this ->flags & self ::EXPLICIT ))
87
+ : ($ this ->flags & self ::IMPLICIT );
64
88
65
- $ class = new ReflectionClass ($ className );
89
+ $ class = null ;
90
+ if ($ useAnnotations && $ this ->flags >= self ::INJECTABLE ) {
91
+ $ class = new ReflectionClass ($ className );
66
92
67
- $ this ->readInjectableAnnotation ($ class , $ definition );
93
+ if ($ this ->flags & self ::INJECTABLE ) {
94
+ $ this ->readInjectableAnnotation ($ class , $ definition );
95
+ }
68
96
69
- // Browse the class properties looking for annotated properties
70
- $ this ->readProperties ($ class , $ definition );
97
+ // Browse the class properties looking for annotated properties
98
+ if ($ this ->flags & self ::PROPERTIES ) {
99
+ $ this ->readProperties ($ class , $ definition );
100
+ }
71
101
72
- // Browse the object's methods looking for annotated methods
73
- $ this ->readMethods ($ class , $ definition );
102
+ // Browse the object's methods looking for annotated methods
103
+ if ($ this ->flags & self ::METHODS ) {
104
+ $ this ->readMethods ($ class , $ definition );
105
+ }
106
+ }
107
+
108
+ // constructor parameters should always be read, even if annotations are disabled (completely or i.a. for methods)
109
+ // so that it behaves at least as ReflectionBasedAutowiring
110
+ if (!$ useAnnotations || !($ this ->flags & self ::METHODS )) {
111
+ $ class = $ class ?? new ReflectionClass ($ className );
112
+ $ this ->readConstructor ($ class , $ definition );
113
+ }
74
114
75
115
return $ definition ;
76
116
}
@@ -166,6 +206,28 @@ private function readMethods(ReflectionClass $class, ObjectDefinition $objectDef
166
206
}
167
207
}
168
208
209
+ /**
210
+ * Browse the object's constructor parameters and inject dependencies.
211
+ */
212
+ private function readConstructor (ReflectionClass $ class , ObjectDefinition $ definition )
213
+ {
214
+ if (!($ constructor = $ class ->getConstructor ()) || !$ constructor ->isPublic ()) {
215
+ return ;
216
+ }
217
+
218
+ $ parameters = [];
219
+ foreach ($ constructor ->getParameters () as $ index => $ parameter ) {
220
+ $ entryName = $ this ->getMethodParameter ($ index , $ parameter , []);
221
+
222
+ if ($ entryName !== null ) {
223
+ $ parameters [$ index ] = new Reference ($ entryName );
224
+ }
225
+ }
226
+
227
+ $ constructorInjection = MethodInjection::constructor ($ parameters );
228
+ $ definition ->completeConstructorInjection ($ constructorInjection );
229
+ }
230
+
169
231
/**
170
232
* @param ReflectionMethod $method
171
233
*
0 commit comments