|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* This file is part of the Code-Insight library. |
|
4
|
|
|
* For the full copyright and license information, please view |
|
5
|
|
|
* the LICENSE file that was distributed with this source code. |
|
6
|
|
|
* |
|
7
|
|
|
* @copyright Alexander Obuhovich <[email protected]> |
|
8
|
|
|
* @link https://github.com/console-helpers/code-insight |
|
9
|
|
|
*/ |
|
10
|
|
|
|
|
11
|
|
|
namespace ConsoleHelpers\CodeInsight\KnowledgeBase\DataCollector; |
|
12
|
|
|
|
|
13
|
|
|
|
|
14
|
|
|
use Go\ParserReflection\ReflectionFileNamespace; |
|
15
|
|
|
|
|
16
|
|
|
class FunctionDataCollector extends AbstractDataCollector |
|
17
|
|
|
{ |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Collect data from a namespace. |
|
21
|
|
|
* |
|
22
|
|
|
* @param integer $file_id File id. |
|
23
|
|
|
* @param ReflectionFileNamespace $namespace Namespace. |
|
24
|
|
|
* |
|
25
|
|
|
* @return void |
|
26
|
|
|
*/ |
|
27
|
4 |
|
public function collectData($file_id, ReflectionFileNamespace $namespace) |
|
28
|
|
|
{ |
|
29
|
|
|
$sql = 'SELECT Name, Id |
|
30
|
|
|
FROM Functions |
|
31
|
4 |
|
WHERE FileId = :file_id'; |
|
32
|
4 |
|
$old_functions = $this->db->fetchPairs($sql, array( |
|
33
|
4 |
|
'file_id' => $file_id, |
|
34
|
4 |
|
)); |
|
35
|
|
|
|
|
36
|
|
|
$insert_sql = ' INSERT INTO Functions (FileId, Name, ParameterCount, RequiredParameterCount, IsVariadic, ReturnsReference, HasReturnType, ReturnType) |
|
37
|
4 |
|
VALUES (:file_id, :name, :parameter_count, :required_parameter_count, :is_variadic, :returns_reference, :has_return_type, :return_type)'; |
|
38
|
|
|
$update_sql = ' UPDATE Functions |
|
39
|
|
|
SET ParameterCount = :parameter_count, |
|
40
|
|
|
RequiredParameterCount = :required_parameter_count, |
|
41
|
|
|
IsVariadic = :is_variadic, |
|
42
|
|
|
ReturnsReference = :returns_reference, |
|
43
|
|
|
ReturnType = :return_type, |
|
44
|
|
|
HasReturnType = :has_return_type |
|
45
|
4 |
|
WHERE FileId = :file_id AND Name = :name'; |
|
46
|
|
|
|
|
47
|
4 |
|
$new_functions = array(); |
|
48
|
|
|
|
|
49
|
4 |
|
foreach ( $namespace->getFunctions() as $function ) { |
|
50
|
4 |
|
$function_name = $function->getName(); |
|
51
|
4 |
|
$new_functions[] = $function_name; |
|
52
|
|
|
|
|
53
|
4 |
|
$has_return_type = $function->hasReturnType(); |
|
54
|
4 |
|
$return_type = $has_return_type ? (string)$function->getReturnType() : null; |
|
55
|
|
|
|
|
56
|
4 |
|
$this->db->perform( |
|
57
|
4 |
|
isset($old_functions[$function_name]) ? $update_sql : $insert_sql, |
|
58
|
|
|
array( |
|
59
|
4 |
|
'file_id' => $file_id, |
|
60
|
4 |
|
'name' => $function_name, |
|
61
|
4 |
|
'parameter_count' => $function->getNumberOfParameters(), |
|
62
|
4 |
|
'required_parameter_count' => $function->getNumberOfRequiredParameters(), |
|
63
|
4 |
|
'is_variadic' => (int)$function->isVariadic(), |
|
64
|
4 |
|
'returns_reference' => (int)$function->returnsReference(), |
|
65
|
4 |
|
'has_return_type' => (int)$has_return_type, |
|
66
|
4 |
|
'return_type' => $return_type, |
|
67
|
|
|
) |
|
68
|
4 |
|
); |
|
69
|
|
|
|
|
70
|
4 |
|
$function_id = isset($old_functions[$function_name]) ? $old_functions[$function_name] : $this->db->lastInsertId(); |
|
71
|
4 |
|
$this->processFunctionParameters($function_id, $function); |
|
72
|
4 |
|
} |
|
73
|
|
|
|
|
74
|
4 |
|
$delete_functions = array_diff(array_keys($old_functions), $new_functions); |
|
75
|
|
|
|
|
76
|
4 |
|
if ( $delete_functions ) { |
|
77
|
|
|
$this->deleteFunctions($file_id, $delete_functions); |
|
78
|
|
|
} |
|
79
|
4 |
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* Deletes functions. |
|
83
|
|
|
* |
|
84
|
|
|
* @param integer $file_id File ID. |
|
85
|
|
|
* @param array $functions Methods. |
|
86
|
|
|
* |
|
87
|
|
|
* @return void |
|
88
|
|
|
*/ |
|
89
|
1 |
|
protected function deleteFunctions($file_id, array $functions) |
|
90
|
|
|
{ |
|
91
|
1 |
|
if ( $functions ) { |
|
92
|
|
|
// Delete only given functions. |
|
93
|
|
|
$sql = 'SELECT Id |
|
94
|
|
|
FROM Functions |
|
95
|
|
|
WHERE FileId = :file_id AND Name IN (:names)'; |
|
96
|
|
|
$function_ids = $this->db->fetchCol($sql, array( |
|
97
|
|
|
'file_id' => $file_id, |
|
98
|
|
|
'names' => $functions, |
|
99
|
|
|
)); |
|
100
|
|
|
} |
|
101
|
|
|
else { |
|
102
|
|
|
// Delete all functions in a file. |
|
103
|
|
|
$sql = 'SELECT Id |
|
104
|
|
|
FROM Functions |
|
105
|
1 |
|
WHERE FileId = :file_id'; |
|
106
|
1 |
|
$function_ids = $this->db->fetchCol($sql, array( |
|
107
|
1 |
|
'file_id' => $file_id, |
|
108
|
1 |
|
)); |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
// @codeCoverageIgnoreStart |
|
112
|
|
|
if ( !$function_ids ) { |
|
|
|
|
|
|
113
|
|
|
return; |
|
114
|
|
|
} |
|
115
|
|
|
// @codeCoverageIgnoreEnd |
|
116
|
|
|
|
|
117
|
1 |
|
$sql = 'DELETE FROM Functions WHERE Id IN (:function_ids)'; |
|
118
|
1 |
|
$this->db->perform($sql, array('function_ids' => $function_ids)); |
|
119
|
|
|
|
|
120
|
1 |
|
$sql = 'DELETE FROM FunctionParameters WHERE FunctionId IN (:function_ids)'; |
|
121
|
1 |
|
$this->db->perform($sql, array('function_ids' => $function_ids)); |
|
122
|
1 |
|
} |
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* Processes function parameters. |
|
126
|
|
|
* |
|
127
|
|
|
* @param integer $function_id Function ID. |
|
128
|
|
|
* @param \ReflectionFunction $function Function. |
|
129
|
|
|
* |
|
130
|
|
|
* @return void |
|
131
|
|
|
*/ |
|
132
|
4 |
|
protected function processFunctionParameters($function_id, \ReflectionFunction $function) |
|
133
|
|
|
{ |
|
134
|
|
|
$sql = 'SELECT Name |
|
135
|
|
|
FROM FunctionParameters |
|
136
|
4 |
|
WHERE FunctionId = :function_id'; |
|
137
|
4 |
|
$old_parameters = $this->db->fetchCol($sql, array( |
|
138
|
4 |
|
'function_id' => $function_id, |
|
139
|
4 |
|
)); |
|
140
|
|
|
|
|
141
|
|
|
$insert_sql = ' INSERT INTO FunctionParameters (FunctionId, Name, Position, TypeClass, HasType, TypeName, AllowsNull, IsArray, IsCallable, IsOptional, IsVariadic, CanBePassedByValue, IsPassedByReference, HasDefaultValue, DefaultValue, DefaultConstant) |
|
142
|
4 |
|
VALUES (:function_id, :name, :position, :type_class, :has_type, :type_name, :allows_null, :is_array, :is_callable, :is_optional, :is_variadic, :can_be_passed_by_value, :is_passed_by_reference, :has_default_value, :default_value, :default_constant)'; |
|
143
|
|
|
$update_sql = ' UPDATE FunctionParameters |
|
144
|
|
|
SET Position = :position, |
|
145
|
|
|
TypeClass = :type_class, |
|
146
|
|
|
HasType = :has_type, |
|
147
|
|
|
TypeName = :type_name, |
|
148
|
|
|
AllowsNull = :allows_null, |
|
149
|
|
|
IsArray = :is_array, |
|
150
|
|
|
IsCallable = :is_callable, |
|
151
|
|
|
IsOptional = :is_optional, |
|
152
|
|
|
IsVariadic = :is_variadic, |
|
153
|
|
|
CanBePassedByValue = :can_be_passed_by_value, |
|
154
|
|
|
IsPassedByReference = :is_passed_by_reference, |
|
155
|
|
|
HasDefaultValue = :has_default_value, |
|
156
|
|
|
DefaultValue = :default_value, |
|
157
|
|
|
DefaultConstant = :default_constant |
|
158
|
4 |
|
WHERE FunctionId = :function_id AND Name = :name'; |
|
159
|
|
|
|
|
160
|
4 |
|
$new_parameters = array(); |
|
161
|
|
|
|
|
162
|
4 |
|
foreach ( $function->getParameters() as $position => $parameter ) { |
|
163
|
4 |
|
$parameter_name = $parameter->getName(); |
|
164
|
4 |
|
$new_parameters[] = $parameter_name; |
|
165
|
|
|
|
|
166
|
4 |
|
$type_class = $parameter->getClass(); |
|
167
|
4 |
|
$type_class = $type_class ? $type_class->getName() : null; |
|
168
|
|
|
|
|
169
|
4 |
|
$has_type = $parameter->hasType(); |
|
170
|
4 |
|
$type_name = $has_type ? (string)$parameter->getType() : null; |
|
171
|
|
|
|
|
172
|
4 |
|
$has_default_value = $parameter->isDefaultValueAvailable(); |
|
173
|
4 |
|
$default_value_is_constant = $has_default_value ? $parameter->isDefaultValueConstant() : false; |
|
174
|
|
|
|
|
175
|
4 |
|
$this->db->perform( |
|
176
|
4 |
|
in_array($parameter_name, $old_parameters) ? $update_sql : $insert_sql, |
|
177
|
|
|
array( |
|
178
|
4 |
|
'function_id' => $function_id, |
|
179
|
4 |
|
'name' => $parameter_name, |
|
180
|
4 |
|
'position' => $position, |
|
181
|
4 |
|
'type_class' => $type_class, |
|
182
|
4 |
|
'has_type' => (int)$has_type, |
|
183
|
4 |
|
'type_name' => $type_name, |
|
184
|
4 |
|
'allows_null' => (int)$parameter->allowsNull(), |
|
185
|
4 |
|
'is_array' => (int)$parameter->isArray(), |
|
186
|
4 |
|
'is_callable' => (int)$parameter->isCallable(), |
|
187
|
4 |
|
'is_optional' => (int)$parameter->isOptional(), |
|
188
|
4 |
|
'is_variadic' => (int)$parameter->isVariadic(), |
|
189
|
4 |
|
'can_be_passed_by_value' => (int)$parameter->canBePassedByValue(), |
|
190
|
4 |
|
'is_passed_by_reference' => (int)$parameter->isPassedByReference(), |
|
191
|
4 |
|
'has_default_value' => (int)$has_default_value, |
|
192
|
4 |
|
'default_value' => $has_default_value ? json_encode($parameter->getDefaultValue()) : null, |
|
193
|
4 |
|
'default_constant' => $default_value_is_constant ? $parameter->getDefaultValueConstantName() : null, |
|
194
|
|
|
) |
|
195
|
4 |
|
); |
|
196
|
4 |
|
} |
|
197
|
|
|
|
|
198
|
4 |
|
$delete_parameters = array_diff($old_parameters, $new_parameters); |
|
199
|
|
|
|
|
200
|
4 |
|
if ( $delete_parameters ) { |
|
201
|
|
|
$sql = 'DELETE FROM FunctionParameters |
|
202
|
1 |
|
WHERE FunctionId = :function_id AND Name IN (:names)'; |
|
203
|
1 |
|
$this->db->perform($sql, array( |
|
204
|
1 |
|
'function_id' => $function_id, |
|
205
|
1 |
|
'names' => $delete_parameters, |
|
206
|
1 |
|
)); |
|
207
|
1 |
|
} |
|
208
|
4 |
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* Delete previously collected data for a files. |
|
212
|
|
|
* |
|
213
|
|
|
* @param array $file_ids File IDs. |
|
214
|
|
|
* |
|
215
|
|
|
* @return void |
|
216
|
|
|
*/ |
|
217
|
1 |
|
public function deleteData(array $file_ids) |
|
218
|
|
|
{ |
|
219
|
1 |
|
foreach ( $file_ids as $file_id ) { |
|
220
|
1 |
|
$this->deleteFunctions($file_id, array()); |
|
221
|
1 |
|
} |
|
222
|
1 |
|
} |
|
223
|
|
|
|
|
224
|
|
|
/** |
|
225
|
|
|
* Returns statistics about the code. |
|
226
|
|
|
* |
|
227
|
|
|
* @return array |
|
228
|
|
|
*/ |
|
229
|
1 |
|
public function getStatistics() |
|
230
|
|
|
{ |
|
231
|
|
|
$sql = 'SELECT COUNT(*) |
|
232
|
1 |
|
FROM Functions'; |
|
233
|
1 |
|
$function_count = $this->db->fetchValue($sql); |
|
234
|
|
|
|
|
235
|
|
|
return array( |
|
236
|
1 |
|
'Functions' => $function_count, |
|
237
|
1 |
|
); |
|
238
|
|
|
} |
|
239
|
|
|
|
|
240
|
|
|
} |
|
241
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.