1 | <?php |
||
2 | /* For licensing terms, see /license.txt */ |
||
3 | |||
4 | /** |
||
5 | * Class UserDataGenerator |
||
6 | * Class to select, sort and transform object data into array data, |
||
7 | * used for a student's general view. |
||
8 | * |
||
9 | * @author Bert Steppé |
||
10 | */ |
||
11 | class UserDataGenerator |
||
12 | { |
||
13 | // Sorting types constants |
||
14 | public const UDG_SORT_TYPE = 1; |
||
15 | public const UDG_SORT_NAME = 2; |
||
16 | public const UDG_SORT_COURSE = 4; |
||
17 | public const UDG_SORT_CATEGORY = 8; |
||
18 | public const UDG_SORT_AVERAGE = 16; |
||
19 | public const UDG_SORT_SCORE = 32; |
||
20 | public const UDG_SORT_MASK = 64; |
||
21 | |||
22 | public const UDG_SORT_ASC = 128; |
||
23 | public const UDG_SORT_DESC = 256; |
||
24 | |||
25 | private $items; |
||
26 | private $userid; |
||
27 | |||
28 | private $coursecodecache; |
||
29 | private $categorycache; |
||
30 | private $scorecache; |
||
31 | private $avgcache; |
||
32 | |||
33 | /** |
||
34 | * UserDataGenerator constructor. |
||
35 | * |
||
36 | * @param int $userid |
||
37 | * @param array $evals |
||
38 | * @param array $links |
||
39 | */ |
||
40 | public function __construct($userid, $evals = [], $links = []) |
||
41 | { |
||
42 | $this->userid = $userid; |
||
43 | $result = []; |
||
44 | foreach ($evals as $eval) { |
||
45 | $toadd = true; |
||
46 | $coursecode = $eval->get_course_code(); |
||
47 | if (isset($coursecode)) { |
||
48 | $result = Result::load(null, $userid, $eval->get_id()); |
||
49 | if (0 == count($result)) { |
||
50 | $toadd = false; |
||
51 | } |
||
52 | } |
||
53 | if ($toadd) { |
||
54 | $evals_filtered_copy = $evals; |
||
55 | } |
||
56 | } |
||
57 | if (0 == count($result)) { |
||
58 | $evals_filtered = $evals; |
||
59 | } else { |
||
60 | $evals_filtered = $evals_filtered_copy; |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
61 | } |
||
62 | $this->items = array_merge($evals_filtered, $links); |
||
63 | |||
64 | $this->coursecodecache = []; |
||
65 | $this->categorycache = []; |
||
66 | $this->scorecache = null; |
||
67 | $this->avgcache = null; |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Get total number of items (rows). |
||
72 | */ |
||
73 | public function get_total_items_count() |
||
74 | { |
||
75 | return count($this->items); |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Get actual array data. |
||
80 | * |
||
81 | * @return array 2-dimensional array - each array contains the elements: |
||
82 | * 0: eval/link object |
||
83 | * 1: item name |
||
84 | * 2: course name |
||
85 | * 3: category name |
||
86 | * 4: average score |
||
87 | * 5: student's score |
||
88 | * 6: student's score as custom display (only if custom scoring enabled) |
||
89 | */ |
||
90 | public function get_data( |
||
91 | $sorting = 0, |
||
92 | $start = 0, |
||
93 | $count = null, |
||
94 | $ignore_score_color = false |
||
95 | ) { |
||
96 | // do some checks on count, redefine if invalid value |
||
97 | if (!isset($count)) { |
||
98 | $count = count($this->items) - $start; |
||
99 | } |
||
100 | if ($count < 0) { |
||
101 | $count = 0; |
||
102 | } |
||
103 | $allitems = $this->items; |
||
104 | |||
105 | // sort users array |
||
106 | if ($sorting & self::UDG_SORT_TYPE) { |
||
107 | usort($allitems, ['UserDataGenerator', 'sort_by_type']); |
||
108 | } elseif ($sorting & self::UDG_SORT_NAME) { |
||
109 | usort($allitems, ['UserDataGenerator', 'sort_by_name']); |
||
110 | } elseif ($sorting & self::UDG_SORT_COURSE) { |
||
111 | usort($allitems, ['UserDataGenerator', 'sort_by_course']); |
||
112 | } elseif ($sorting & self::UDG_SORT_CATEGORY) { |
||
113 | usort($allitems, ['UserDataGenerator', 'sort_by_category']); |
||
114 | } elseif ($sorting & self::UDG_SORT_AVERAGE) { |
||
115 | // if user sorts on average scores, first calculate them and cache them |
||
116 | foreach ($allitems as $item) { |
||
117 | $this->avgcache[$item->get_item_type().$item->get_id()] = $item->calc_score(); |
||
118 | } |
||
119 | usort($allitems, ['UserDataGenerator', 'sort_by_average']); |
||
120 | } elseif ($sorting & self::UDG_SORT_SCORE) { |
||
121 | // if user sorts on student's scores, first calculate them and cache them |
||
122 | foreach ($allitems as $item) { |
||
123 | $this->scorecache[$item->get_item_type().$item->get_id()] = $item->calc_score($this->userid); |
||
124 | } |
||
125 | usort($allitems, ['UserDataGenerator', 'sort_by_score']); |
||
126 | } elseif ($sorting & self::UDG_SORT_MASK) { |
||
127 | // if user sorts on student's masks, first calculate scores and cache them |
||
128 | foreach ($allitems as $item) { |
||
129 | $this->scorecache[$item->get_item_type().$item->get_id()] = $item->calc_score($this->userid); |
||
130 | } |
||
131 | usort($allitems, ['UserDataGenerator', 'sort_by_mask']); |
||
132 | } |
||
133 | |||
134 | if ($sorting & self::UDG_SORT_DESC) { |
||
135 | $allitems = array_reverse($allitems); |
||
136 | } |
||
137 | // select the items we have to display |
||
138 | $visibleitems = array_slice($allitems, $start, $count); |
||
139 | |||
140 | // fill score cache if not done yet |
||
141 | if (!isset($this->scorecache)) { |
||
142 | foreach ($visibleitems as $item) { |
||
143 | $this->scorecache[$item->get_item_type().$item->get_id()] = $item->calc_score($this->userid); |
||
144 | } |
||
145 | } |
||
146 | // generate the data to display |
||
147 | $scoredisplay = ScoreDisplay::instance(); |
||
148 | $data = []; |
||
149 | $model = ExerciseLib::getCourseScoreModel(); |
||
150 | foreach ($visibleitems as $item) { |
||
151 | $row = []; |
||
152 | $row[] = $item; |
||
153 | $row[] = $item->get_name(); |
||
154 | $row[] = $this->build_course_name($item); |
||
155 | $row[] = $this->build_category_name($item); |
||
156 | |||
157 | if (!empty($model)) { |
||
158 | if (isset($this->avgcache)) { |
||
159 | $avgscore = $this->avgcache[$item->get_item_type().$item->get_id()]; |
||
160 | } else { |
||
161 | $avgscore = $item->calc_score(); |
||
162 | } |
||
163 | $row[] = ExerciseLib::show_score($avgscore[0], $avgscore[1]); |
||
164 | $score = $this->scorecache[$item->get_item_type().$item->get_id()]; |
||
165 | $displayScore = ExerciseLib::show_score($score[0], $score[1]); |
||
166 | $row[] = $displayScore; |
||
167 | if ($scoredisplay->is_custom()) { |
||
168 | $row[] = $displayScore; |
||
169 | } |
||
170 | } else { |
||
171 | $row[] = $this->build_average_column($item, $ignore_score_color); |
||
172 | $row[] = $this->build_result_column($item, $ignore_score_color); |
||
173 | if ($scoredisplay->is_custom()) { |
||
174 | $row[] = $this->build_mask_column($item, $ignore_score_color); |
||
175 | } |
||
176 | } |
||
177 | |||
178 | $data[] = $row; |
||
179 | } |
||
180 | |||
181 | return $data; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * @param $item1 |
||
186 | * @param $item2 |
||
187 | * |
||
188 | * @return int |
||
189 | */ |
||
190 | public function sort_by_type($item1, $item2) |
||
191 | { |
||
192 | if ($item1->get_item_type() == $item2->get_item_type()) { |
||
193 | return $this->sort_by_name($item1, $item2); |
||
194 | } else { |
||
195 | return $item1->get_item_type() < $item2->get_item_type() ? -1 : 1; |
||
196 | } |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * @param $item1 |
||
201 | * @param $item2 |
||
202 | * |
||
203 | * @return int |
||
204 | */ |
||
205 | public function sort_by_course($item1, $item2) |
||
206 | { |
||
207 | $name1 = api_strtolower( |
||
208 | $this->get_course_name_from_code_cached($item1->get_course_code()) |
||
209 | ); |
||
210 | $name2 = api_strtolower( |
||
211 | $this->get_course_name_from_code_cached($item2->get_course_code()) |
||
212 | ); |
||
213 | |||
214 | return api_strnatcmp($name1, $name2); |
||
215 | } |
||
216 | |||
217 | /** |
||
218 | * @param $item1 |
||
219 | * @param $item2 |
||
220 | * |
||
221 | * @return int |
||
222 | */ |
||
223 | public function sort_by_category($item1, $item2) |
||
224 | { |
||
225 | $cat1 = $this->get_category_cached($item1->get_category_id()); |
||
226 | $cat2 = $this->get_category_cached($item2->get_category_id()); |
||
227 | $name1 = api_strtolower($this->get_category_name_to_display($cat1)); |
||
228 | $name2 = api_strtolower($this->get_category_name_to_display($cat2)); |
||
229 | |||
230 | return api_strnatcmp($name1, $name2); |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * @param $item1 |
||
235 | * @param $item2 |
||
236 | * |
||
237 | * @return int |
||
238 | */ |
||
239 | public function sort_by_name($item1, $item2) |
||
240 | { |
||
241 | return api_strnatcmp($item1->get_name(), $item2->get_name()); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * @param $item1 |
||
246 | * @param $item2 |
||
247 | * |
||
248 | * @return int |
||
249 | */ |
||
250 | public function sort_by_average($item1, $item2) |
||
251 | { |
||
252 | $score1 = $this->avgcache[$item1->get_item_type().$item1->get_id()]; |
||
253 | $score2 = $this->avgcache[$item2->get_item_type().$item2->get_id()]; |
||
254 | |||
255 | return $this->compare_scores($score1, $score2); |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * @param $item1 |
||
260 | * @param $item2 |
||
261 | * |
||
262 | * @return int |
||
263 | */ |
||
264 | public function sort_by_score($item1, $item2) |
||
265 | { |
||
266 | $score1 = $this->scorecache[$item1->get_item_type().$item1->get_id()]; |
||
267 | $score2 = $this->scorecache[$item2->get_item_type().$item2->get_id()]; |
||
268 | |||
269 | return $this->compare_scores($score1, $score2); |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * @param $item1 |
||
274 | * @param $item2 |
||
275 | * |
||
276 | * @return int |
||
277 | */ |
||
278 | public function sort_by_mask($item1, $item2) |
||
279 | { |
||
280 | $score1 = $this->scorecache[$item1->get_item_type().$item1->get_id()]; |
||
281 | $score2 = $this->scorecache[$item2->get_item_type().$item2->get_id()]; |
||
282 | |||
283 | return ScoreDisplay::compare_scores_by_custom_display($score1, $score2); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * @param $score1 |
||
288 | * @param $score2 |
||
289 | * |
||
290 | * @return int |
||
291 | */ |
||
292 | public function compare_scores($score1, $score2) |
||
293 | { |
||
294 | if (!isset($score1)) { |
||
295 | return isset($score2) ? 1 : 0; |
||
296 | } elseif (!isset($score2)) { |
||
297 | return -1; |
||
298 | } elseif (($score1[0] / $score1[1]) == ($score2[0] / $score2[1])) { |
||
299 | return 0; |
||
300 | } else { |
||
301 | return ($score1[0] / $score1[1]) < ($score2[0] / $score2[1]) ? -1 : 1; |
||
302 | } |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * @param $item |
||
307 | * |
||
308 | * @return mixed |
||
309 | */ |
||
310 | private function build_course_name($item) |
||
311 | { |
||
312 | return $this->get_course_name_from_code_cached($item->get_course_code()); |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * @param $item |
||
317 | * |
||
318 | * @return string |
||
319 | */ |
||
320 | private function build_category_name($item) |
||
321 | { |
||
322 | $cat = $this->get_category_cached($item->get_category_id()); |
||
323 | |||
324 | return $this->get_category_name_to_display($cat); |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * @param $item |
||
329 | * @param $ignore_score_color |
||
330 | * |
||
331 | * @return string |
||
332 | */ |
||
333 | private function build_average_column($item, $ignore_score_color) |
||
334 | { |
||
335 | if (isset($this->avgcache)) { |
||
336 | $avgscore = $this->avgcache[$item->get_item_type().$item->get_id()]; |
||
337 | } else { |
||
338 | $avgscore = $item->calc_score('', 'average'); |
||
339 | } |
||
340 | $scoredisplay = ScoreDisplay::instance(); |
||
341 | $displaytype = SCORE_AVERAGE; |
||
342 | |||
343 | return $scoredisplay->display_score($avgscore, $displaytype); |
||
344 | } |
||
345 | |||
346 | /** |
||
347 | * @param $item |
||
348 | * @param $ignore_score_color |
||
349 | * |
||
350 | * @return string |
||
351 | */ |
||
352 | private function build_result_column($item, $ignore_score_color) |
||
353 | { |
||
354 | $studscore = $this->scorecache[$item->get_item_type().$item->get_id()]; |
||
355 | $scoredisplay = ScoreDisplay::instance(); |
||
356 | $displaytype = SCORE_DIV_PERCENT; |
||
357 | if ($ignore_score_color) { |
||
358 | $displaytype |= SCORE_IGNORE_SPLIT; |
||
359 | } |
||
360 | |||
361 | return $scoredisplay->display_score( |
||
362 | $studscore, |
||
363 | $displaytype, |
||
364 | SCORE_ONLY_DEFAULT |
||
365 | ); |
||
366 | } |
||
367 | |||
368 | /** |
||
369 | * @param $item |
||
370 | * @param $ignore_score_color |
||
371 | * |
||
372 | * @return string |
||
373 | */ |
||
374 | private function build_mask_column($item, $ignore_score_color) |
||
375 | { |
||
376 | $studscore = $this->scorecache[$item->get_item_type().$item->get_id()]; |
||
377 | $scoredisplay = ScoreDisplay::instance(); |
||
378 | $displaytype = SCORE_DIV_PERCENT; |
||
379 | if ($ignore_score_color) { |
||
380 | $displaytype |= SCORE_IGNORE_SPLIT; |
||
381 | } |
||
382 | |||
383 | return $scoredisplay->display_score( |
||
384 | $studscore, |
||
385 | $displaytype, |
||
386 | SCORE_ONLY_CUSTOM |
||
387 | ); |
||
388 | } |
||
389 | |||
390 | /** |
||
391 | * @param string $coursecode |
||
392 | * |
||
393 | * @return mixed |
||
394 | */ |
||
395 | private function get_course_name_from_code_cached($coursecode) |
||
396 | { |
||
397 | if (isset($this->coursecodecache) && |
||
398 | isset($this->coursecodecache[$coursecode]) |
||
399 | ) { |
||
400 | return $this->coursecodecache[$coursecode]; |
||
401 | } else { |
||
402 | $name = CourseManager::getCourseNameFromCode($coursecode); |
||
403 | $this->coursecodecache[$coursecode] = $name; |
||
404 | |||
405 | return $name; |
||
406 | } |
||
407 | } |
||
408 | |||
409 | /** |
||
410 | * @param int $category_id |
||
411 | */ |
||
412 | private function get_category_cached($category_id) |
||
413 | { |
||
414 | if (isset($this->categorycache) && |
||
415 | isset($this->categorycache[$category_id]) |
||
416 | ) { |
||
417 | return $this->categorycache[$category_id]; |
||
418 | } else { |
||
419 | $cat = Category::load($category_id); |
||
420 | if (isset($cat)) { |
||
421 | $this->categorycache[$category_id] = $cat[0]; |
||
422 | |||
423 | return $cat[0]; |
||
424 | } else { |
||
425 | return null; |
||
426 | } |
||
427 | } |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * @param $cat |
||
432 | * |
||
433 | * @return string |
||
434 | */ |
||
435 | private function get_category_name_to_display($cat) |
||
436 | { |
||
437 | if (isset($cat)) { |
||
438 | if ('0' == $cat->get_parent_id() || null == $cat->get_parent_id()) { |
||
439 | return ''; |
||
440 | } else { |
||
441 | return $cat->get_name(); |
||
442 | } |
||
443 | } |
||
444 | |||
445 | return ''; |
||
446 | } |
||
447 | } |
||
448 |