14
14
use Symfony \Component \DependencyInjection \ChildDefinition ;
15
15
use Symfony \Component \DependencyInjection \ContainerBuilder ;
16
16
use Symfony \Component \DependencyInjection \Definition ;
17
+ use Symfony \Component \DependencyInjection \Exception \LogicException ;
17
18
18
19
/**
19
20
* @author Alexander M. Turek <[email protected] >
20
21
*/
21
22
final class AttributeAutoconfigurationPass extends AbstractRecursivePass
22
23
{
24
+ private $ classAttributeConfigurators = [];
25
+ private $ methodAttributeConfigurators = [];
26
+ private $ propertyAttributeConfigurators = [];
27
+ private $ parameterAttributeConfigurators = [];
28
+
23
29
public function process (ContainerBuilder $ container ): void
24
30
{
25
31
if (80000 > \PHP_VERSION_ID || !$ container ->getAutoconfiguredAttributes ()) {
26
32
return ;
27
33
}
28
34
35
+ foreach ($ container ->getAutoconfiguredAttributes () as $ attributeName => $ callable ) {
36
+ $ callableReflector = new \ReflectionFunction (\Closure::fromCallable ($ callable ));
37
+ if ($ callableReflector ->getNumberOfParameters () <= 2 ) {
38
+ $ this ->classAttributeConfigurators [$ attributeName ] = $ callable ;
39
+ continue ;
40
+ }
41
+
42
+ $ reflectorParameter = $ callableReflector ->getParameters ()[2 ];
43
+ $ parameterType = $ reflectorParameter ->getType ();
44
+ $ types = [];
45
+ if ($ parameterType instanceof \ReflectionUnionType) {
46
+ foreach ($ parameterType ->getTypes () as $ type ) {
47
+ $ types [] = $ type ->getName ();
48
+ }
49
+ } elseif ($ parameterType instanceof \ReflectionNamedType) {
50
+ $ types [] = $ parameterType ->getName ();
51
+ } else {
52
+ throw new LogicException (sprintf ('Argument "$%s" of attribute autoconfigurator should have a type, use one or more of "\ReflectionClass|\ReflectionMethod|\ReflectionProperty|\ReflectionParameter|\Reflector" in "%s" on line "%d". ' , $ reflectorParameter ->getName (), $ callableReflector ->getFileName (), $ callableReflector ->getStartLine ()));
53
+ }
54
+
55
+ try {
56
+ $ attributeReflector = new \ReflectionClass ($ attributeName );
57
+ } catch (\ReflectionException $ e ) {
58
+ continue ;
59
+ }
60
+
61
+ $ targets = $ attributeReflector ->getAttributes (\Attribute::class)[0 ] ?? 0 ;
62
+ $ targets = $ targets ? $ targets ->getArguments ()[0 ] ?? -1 : 0 ;
63
+
64
+ foreach (['class ' , 'method ' , 'property ' , 'parameter ' ] as $ symbol ) {
65
+ if (['Reflector ' ] !== $ types ) {
66
+ if (!\in_array ('Reflection ' .ucfirst ($ symbol ), $ types , true )) {
67
+ continue ;
68
+ }
69
+ if (!($ targets & \constant ('Attribute::TARGET_ ' .strtoupper ($ symbol )))) {
70
+ throw new LogicException (sprintf ('Invalid type "Reflection%s" on argument "$%s": attribute "%s" cannot target a ' .$ symbol .' in "%s" on line "%d". ' , ucfirst ($ symbol ), $ reflectorParameter ->getName (), $ attributeName , $ callableReflector ->getFileName (), $ callableReflector ->getStartLine ()));
71
+ }
72
+ }
73
+ $ this ->{$ symbol .'AttributeConfigurators ' }[$ attributeName ] = $ callable ;
74
+ }
75
+ }
76
+
29
77
parent ::process ($ container );
30
78
}
31
79
@@ -35,21 +83,74 @@ protected function processValue($value, bool $isRoot = false)
35
83
|| !$ value ->isAutoconfigured ()
36
84
|| $ value ->isAbstract ()
37
85
|| $ value ->hasTag ('container.ignore_attributes ' )
38
- || !($ reflector = $ this ->container ->getReflectionClass ($ value ->getClass (), false ))
86
+ || !($ classReflector = $ this ->container ->getReflectionClass ($ value ->getClass (), false ))
39
87
) {
40
88
return parent ::processValue ($ value , $ isRoot );
41
89
}
42
90
43
- $ autoconfiguredAttributes = $ this ->container ->getAutoconfiguredAttributes ();
44
91
$ instanceof = $ value ->getInstanceofConditionals ();
45
- $ conditionals = $ instanceof [$ reflector ->getName ()] ?? new ChildDefinition ('' );
46
- foreach ($ reflector ->getAttributes () as $ attribute ) {
47
- if ($ configurator = $ autoconfiguredAttributes [$ attribute ->getName ()] ?? null ) {
48
- $ configurator ($ conditionals , $ attribute ->newInstance (), $ reflector );
92
+ $ conditionals = $ instanceof [$ classReflector ->getName ()] ?? new ChildDefinition ('' );
93
+
94
+ if ($ this ->classAttributeConfigurators ) {
95
+ foreach ($ classReflector ->getAttributes () as $ attribute ) {
96
+ if ($ configurator = $ this ->classAttributeConfigurators [$ attribute ->getName ()] ?? null ) {
97
+ $ configurator ($ conditionals , $ attribute ->newInstance (), $ classReflector );
98
+ }
49
99
}
50
100
}
51
- if (!isset ($ instanceof [$ reflector ->getName ()]) && new ChildDefinition ('' ) != $ conditionals ) {
52
- $ instanceof [$ reflector ->getName ()] = $ conditionals ;
101
+
102
+ if ($ this ->parameterAttributeConfigurators && $ constructorReflector = $ this ->getConstructor ($ value , false )) {
103
+ foreach ($ constructorReflector ->getParameters () as $ parameterReflector ) {
104
+ foreach ($ parameterReflector ->getAttributes () as $ attribute ) {
105
+ if ($ configurator = $ this ->parameterAttributeConfigurators [$ attribute ->getName ()] ?? null ) {
106
+ $ configurator ($ conditionals , $ attribute ->newInstance (), $ parameterReflector );
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ if ($ this ->methodAttributeConfigurators || $ this ->parameterAttributeConfigurators ) {
113
+ foreach ($ classReflector ->getMethods (\ReflectionMethod::IS_PUBLIC ) as $ methodReflector ) {
114
+ if ($ methodReflector ->isStatic () || $ methodReflector ->isConstructor () || $ methodReflector ->isDestructor ()) {
115
+ continue ;
116
+ }
117
+
118
+ if ($ this ->methodAttributeConfigurators ) {
119
+ foreach ($ methodReflector ->getAttributes () as $ attribute ) {
120
+ if ($ configurator = $ this ->methodAttributeConfigurators [$ attribute ->getName ()] ?? null ) {
121
+ $ configurator ($ conditionals , $ attribute ->newInstance (), $ methodReflector );
122
+ }
123
+ }
124
+ }
125
+
126
+ if ($ this ->parameterAttributeConfigurators ) {
127
+ foreach ($ methodReflector ->getParameters () as $ parameterReflector ) {
128
+ foreach ($ parameterReflector ->getAttributes () as $ attribute ) {
129
+ if ($ configurator = $ this ->parameterAttributeConfigurators [$ attribute ->getName ()] ?? null ) {
130
+ $ configurator ($ conditionals , $ attribute ->newInstance (), $ parameterReflector );
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ if ($ this ->propertyAttributeConfigurators ) {
139
+ foreach ($ classReflector ->getProperties (\ReflectionProperty::IS_PUBLIC ) as $ propertyReflector ) {
140
+ if ($ propertyReflector ->isStatic ()) {
141
+ continue ;
142
+ }
143
+
144
+ foreach ($ propertyReflector ->getAttributes () as $ attribute ) {
145
+ if ($ configurator = $ this ->propertyAttributeConfigurators [$ attribute ->getName ()] ?? null ) {
146
+ $ configurator ($ conditionals , $ attribute ->newInstance (), $ propertyReflector );
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ if (!isset ($ instanceof [$ classReflector ->getName ()]) && new ChildDefinition ('' ) != $ conditionals ) {
153
+ $ instanceof [$ classReflector ->getName ()] = $ conditionals ;
53
154
$ value ->setInstanceofConditionals ($ instanceof );
54
155
}
55
156
0 commit comments