@@ -17,16 +17,146 @@ class DynamicLoader extends NodeVisitorAbstract
17
17
{
18
18
public $ definitionCollector ;
19
19
public $ prettyPrinter ;
20
+ public $ definitionResolver ;
21
+
22
+ private $ collectAutoload ;
20
23
21
- public function __construct (DefinitionCollector $ definitionCollector )
24
+ public function __construct (DefinitionCollector $ definitionCollector, DefinitionResolver $ definitionResolver , bool $ collectAutoload )
22
25
{
23
26
$ this ->definitionCollector = $ definitionCollector ;
27
+ $ this ->definitionResolver = $ definitionResolver ;
28
+ $ this ->collectAutoload = $ collectAutoload ;
24
29
$ this ->prettyPrinter = new PrettyPrinter ;
25
30
}
26
31
32
+ public function visitAutoloadClassDeclaration (Node $ node ) {
33
+ if (!($ node instanceof Node \Stmt \Class_)) {
34
+ return ;
35
+ }
36
+
37
+ $ extends = $ node ->extends ;
38
+ if (!isset ($ extends ->parts )) {
39
+ return ;
40
+ }
41
+ $ shouldAutoload = false ;
42
+ foreach ($ extends ->parts as $ part ) {
43
+ // TODO: add more criteria here?
44
+ if ($ part === "CI_Controller " || $ part === "ST_Controller " ||
45
+ $ part === "ST_Auth_Controller " ) {
46
+ $ shouldAutoload = true ;
47
+ break ;
48
+ }
49
+ }
50
+
51
+ if (!$ shouldAutoload ) {
52
+ return ;
53
+ }
54
+
55
+ if (isset ($ this ->definitionResolver ->autoloadLibraries )) {
56
+ foreach ($ this ->definitionResolver ->autoloadLibraries as $ key => $ value ) {
57
+ $ this ->createAutoloadDefinition ($ node , $ value );
58
+ }
59
+ }
60
+
61
+ if (isset ($ this ->definitionResolver ->autoloadModels )) {
62
+ foreach ($ this ->definitionResolver ->autoloadModels as $ key => $ value ) {
63
+ $ this ->createAutoloadDefinition ($ node , $ value );
64
+ }
65
+ }
66
+
67
+ if (isset ($ this ->definitionResolver ->autoloadHelpers )) {
68
+ foreach ($ this ->definitionResolver ->autoloadHelpers as $ key => $ value ) {
69
+ $ this ->createAutoloadDefinition ($ node , $ value );
70
+ }
71
+ }
72
+
73
+ if (isset ($ this ->definitionResolver ->autoloadConfig )) {
74
+ foreach ($ this ->definitionResolver ->autoloadConfig as $ key => $ value ) {
75
+ $ this ->createAutoloadDefinition ($ node , $ value );
76
+ }
77
+ }
78
+
79
+ if (isset ($ this ->definitionResolver ->autoloadLanguage )) {
80
+ foreach ($ this ->definitionResolver ->autoloadLanguage as $ key => $ value ) {
81
+ $ this ->createAutoloadDefinition ($ node , $ value );
82
+ }
83
+ }
84
+ }
85
+
86
+ public function visitAutoloadNode (Node $ node ) {
87
+ // looking at array assignments.
88
+ if (!($ node instanceof Node \Expr \Assign)) {
89
+ return ;
90
+ }
91
+
92
+ // check left hand side.
93
+ $ lhs = $ node ->var ;
94
+ if (!($ lhs instanceof Node \Expr \ArrayDimFetch)) {
95
+ return ;
96
+ }
97
+
98
+ $ dimFetchVar = $ lhs ->var ;
99
+ if (!($ dimFetchVar instanceof Node \Expr \Variable)) {
100
+ return ;
101
+ }
102
+
103
+ if ($ dimFetchVar ->name !== "autoload " ) {
104
+ return ;
105
+ }
106
+ // end of checking left hand side.
107
+
108
+ $ dim = $ lhs ->dim ;
109
+ if (!($ dim instanceof Node \Scalar \String_)) {
110
+ return ;
111
+ }
112
+ // TODO: support more than libraries
113
+ $ target = $ dim ->value ;
114
+
115
+ // extract right hand side.
116
+ $ rhs = $ node ->expr ;
117
+ if (!($ rhs instanceof Node \Expr \Array_)) {
118
+ return ;
119
+ }
120
+
121
+ // $target -> $node reference
122
+ $ arrayOfLibs = $ rhs ->items ;
123
+ foreach ($ arrayOfLibs as $ lib ) {
124
+ $ libName = $ lib ->value ->value ;
125
+ switch ($ target ) {
126
+ case "libraries " :
127
+ $ this ->definitionResolver ->autoloadLibraries [$ libName ] = $ lib ;
128
+ break ;
129
+ case "helper " :
130
+ $ this ->definitionResolver ->autoloadHelpers [$ libName ] = $ lib ;
131
+ break ;
132
+ case "config " :
133
+ $ this ->definitionResolver ->autoloadConfig [$ libName ] = $ lib ;
134
+ break ;
135
+ case "model " :
136
+ $ this ->definitionResolver ->autoloadModels [$ libName ] = $ lib ;
137
+ break ;
138
+ case "language " :
139
+ $ this ->definitionResolver ->autoloadLanguage [$ libName ] = $ lib ;
140
+ break ;
141
+ }
142
+ }
143
+
144
+ }
145
+
27
146
public function enterNode (Node $ node )
28
147
{
29
- // check its name is 'model'
148
+ // handling autoloading.
149
+ if ($ this ->collectAutoload ) {
150
+ // records autoloading fields into definition resolver.
151
+ $ this ->visitAutoloadNode ($ node );
152
+ }
153
+
154
+ // spits autoloading fields to a class that is derived from controller classes.
155
+ $ this ->visitAutoloadClassDeclaration ($ node );
156
+
157
+ // The follwoing is for handling dynamic loading. (Finished)
158
+
159
+ // check its name is 'model', 'library' or 'helper'.
30
160
if (!($ node instanceof Node \Expr \MethodCall)) {
31
161
return ;
32
162
}
@@ -52,26 +182,69 @@ public function enterNode(Node $node)
52
182
if ($ argSize == 2 ) {
53
183
$ nameNode = $ node ->args [1 ]->value ;
54
184
}
55
- $ this ->createDefintion ($ node , $ node ->args [0 ]->value , $ nameNode );
185
+ $ this ->createDefinition ($ node , $ node ->args [0 ]->value , $ nameNode );
56
186
} else if ($ node ->args [0 ]->value instanceof Node \Expr \Array_) {
57
187
$ elems = $ node ->args [0 ]->value ->items ;
58
188
foreach ($ elems as $ item ) {
59
189
if ($ item ->value instanceof Node \Scalar \String_) {
60
- $ this ->createDefintion ($ node , $ item ->value , $ nameNode );
190
+ $ this ->createDefinition ($ node , $ item ->value , $ nameNode );
61
191
}
62
192
}
63
193
}
64
194
}
65
195
196
+ // copied from createDefinition and tailored.
197
+ public function createAutoloadDefinition (Node $ classNode , Node $ entityNode )
198
+ {
199
+ $ fieldName = $ entityNode ->value ->value ;
200
+
201
+ $ enclosedClass = $ classNode ;
202
+ $ classFqn = $ enclosedClass ->namespacedName ->toString ();
203
+ $ fqn = $ classFqn . "-> " . $ fieldName ;
204
+
205
+ // if we cannot find definition, just return.
206
+ if ($ fqn === NULL ) {
207
+ return ;
208
+ }
209
+
210
+ // add fqn to nodes and definitions.
211
+ $ this ->definitionCollector ->nodes [$ fqn ] = $ entityNode ;
212
+
213
+ // Create symbol
214
+ // $classFqnParts = preg_split('/(::|->|\\\\)/', $fqn);
215
+ // array_pop($classFqnParts);
216
+ // $classFqn = implode('\\', $classFqnParts);
217
+ $ sym = new SymbolInformation ($ fieldName , SymbolKind::PROPERTY , Location::fromNode ($ entityNode ), $ classFqn );
218
+
219
+ // Create type
220
+ // array_push($entityParts, ucwords($enityName));
221
+ // $typeName = implode('\\', $entityParts);
222
+ $ typeName = ucwords ($ fieldName );
223
+ $ type = new Types \Object_ (new Fqsen ('\\' . $ typeName ));
224
+
225
+ // Create defintion from symbol, type and all others
226
+ $ def = new Definition ;
227
+ $ def ->canBeInstantiated = false ;
228
+ $ def ->isGlobal = false ; // TODO check the meaning of this, why public field has this set to false?
229
+ $ def ->isStatic = false ; // it should not be a static field
230
+ $ def ->fqn = $ fqn ;
231
+ $ def ->symbolInformation = $ sym ;
232
+ $ def ->type = $ type ;
233
+ // Maybe this is not the best
234
+ $ def ->declarationLine = $ fieldName ; // $this->prettyPrinter->prettyPrint([$argNode]);
235
+ $ def ->documentation = "Dynamically Generated Field: " . $ fieldName ;
236
+
237
+ $ this ->definitionCollector ->definitions [$ fqn ] = $ def ;
238
+ }
66
239
67
- public function createDefintion ($ callNode , $ entityNode , $ nameNode )
240
+ public function createDefinition ($ callNode , $ entityNode , $ nameNode )
68
241
{
69
242
$ entityString = $ entityNode ->value ;
70
243
$ entityParts = explode ('/ ' , $ entityString );
71
244
$ enityName = array_pop ($ entityParts );
72
245
$ fieldName = $ enityName ;
73
246
74
- // deal with case like: $this->_CI->load->model('users_mdl', 'hahaha');
247
+ // deal with case like: $this->_CI->load->model('users_mdl', 'hahaha');
75
248
if ($ callNode ->name = "model " && $ nameNode !== NULL ) {
76
249
if (!($ nameNode instanceof Node \Scalar \String_)) {
77
250
return ;
0 commit comments