Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
49 / 49 |
|
100.00% |
3 / 3 |
CRAP | |
100.00% |
1 / 1 |
| category_page | |
100.00% |
49 / 49 |
|
100.00% |
3 / 3 |
14 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| reasons | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
8 | |||
| export_for_template | |
100.00% |
36 / 36 |
|
100.00% |
1 / 1 |
5 | |||
| 1 | <?php |
| 2 | // This file is part of Moodle - https://moodle.org/ |
| 3 | // |
| 4 | // Moodle is free software: you can redistribute it and/or modify |
| 5 | // it under the terms of the GNU General Public License as published by |
| 6 | // the Free Software Foundation, either version 3 of the License, or |
| 7 | // (at your option) any later version. |
| 8 | // |
| 9 | // Moodle is distributed in the hope that it will be useful, |
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | // GNU General Public License for more details. |
| 13 | // |
| 14 | // You should have received a copy of the GNU General Public License |
| 15 | // along with Moodle. If not, see <https://www.gnu.org/licenses/>. |
| 16 | |
| 17 | namespace local_atrisk\output; |
| 18 | |
| 19 | use renderable; |
| 20 | use renderer_base; |
| 21 | use templatable; |
| 22 | |
| 23 | /** |
| 24 | * The list of flagged students in a category. |
| 25 | * |
| 26 | * @package local_atrisk |
| 27 | * @copyright 2026 DevLMS <contact@devlms.com> |
| 28 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
| 29 | */ |
| 30 | class category_page implements renderable, templatable { |
| 31 | /** |
| 32 | * Constructor. |
| 33 | * |
| 34 | * @param \core_course_category $category |
| 35 | * @param \stdClass[] $rows from contacts::for_category() |
| 36 | */ |
| 37 | public function __construct( |
| 38 | /** @var \core_course_category the category */ |
| 39 | private \core_course_category $category, |
| 40 | /** @var \stdClass[] flag rows */ |
| 41 | private array $rows |
| 42 | ) { |
| 43 | } |
| 44 | |
| 45 | /** |
| 46 | * Why this student is listed, using the current thresholds. |
| 47 | * |
| 48 | * @param \stdClass $r |
| 49 | * @return array of [kind, label] |
| 50 | */ |
| 51 | private function reasons(\stdClass $r): array { |
| 52 | $inactivedays = (int) get_config('local_atrisk', 'inactivedays'); |
| 53 | $missed = (int) get_config('local_atrisk', 'misseddeadlines'); |
| 54 | $gradebelow = (int) get_config('local_atrisk', 'gradebelow'); |
| 55 | $out = []; |
| 56 | if ($inactivedays && $r->inactive >= $inactivedays) { |
| 57 | $out[] = ['kind' => 'inactive', 'label' => get_string('reason_inactive', 'local_atrisk', (int) $r->inactive)]; |
| 58 | } |
| 59 | if ($missed && $r->missed >= $missed) { |
| 60 | $out[] = ['kind' => 'missed', 'label' => get_string('reason_missed', 'local_atrisk', (int) $r->missed)]; |
| 61 | } |
| 62 | if ($gradebelow && $r->grade !== null && (float) $r->grade < $gradebelow) { |
| 63 | $grade = format_float((float) $r->grade, 2, true, true); |
| 64 | $out[] = ['kind' => 'grade', 'label' => get_string('reason_grade', 'local_atrisk', $grade)]; |
| 65 | } |
| 66 | return $out; |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * Template context. |
| 71 | * |
| 72 | * @param renderer_base $output |
| 73 | * @return array |
| 74 | */ |
| 75 | public function export_for_template(renderer_base $output): array { |
| 76 | global $DB; |
| 77 | $staff = []; |
| 78 | $ids = array_filter(array_unique(array_map(fn($r) => (int) $r->lastcontactedby, $this->rows))); |
| 79 | if ($ids) { |
| 80 | $fields = 'id, ' . implode(', ', \core_user\fields::get_name_fields()); |
| 81 | $staff = $DB->get_records_list('user', 'id', $ids, '', $fields); |
| 82 | } |
| 83 | $rows = []; |
| 84 | foreach ($this->rows as $r) { |
| 85 | $contacted = false; |
| 86 | if ($r->lastcontacted) { |
| 87 | $by = $staff[$r->lastcontactedby] ?? null; |
| 88 | $contacted = [ |
| 89 | 'by' => $by ? fullname($by) : get_string('someone', 'local_atrisk'), |
| 90 | 'when' => userdate($r->lastcontacted, get_string('strftimedatetimeshort', 'langconfig')), |
| 91 | 'note' => (string) $r->lastnote, |
| 92 | ]; |
| 93 | } |
| 94 | $rows[] = [ |
| 95 | 'name' => fullname($r), |
| 96 | 'profileurl' => (new \moodle_url('/user/view.php', ['id' => $r->userid, 'course' => $r->courseid]))->out(false), |
| 97 | 'course' => format_string($r->coursename, true, [ |
| 98 | 'context' => \context_course::instance($r->courseid), |
| 99 | 'escape' => false, |
| 100 | ]), |
| 101 | 'courseurl' => (new \moodle_url('/course/view.php', ['id' => $r->courseid]))->out(false), |
| 102 | 'reasons' => $this->reasons($r), |
| 103 | 'contacted' => $contacted, |
| 104 | 'contacturl' => (new \moodle_url('/local/atrisk/contact.php', [ |
| 105 | 'id' => $r->id, |
| 106 | 'cat' => $this->category->id, |
| 107 | ]))->out(false), |
| 108 | ]; |
| 109 | } |
| 110 | return [ |
| 111 | 'category' => $this->category->get_formatted_name(), |
| 112 | 'count' => count($rows), |
| 113 | 'rows' => $rows, |
| 114 | 'empty' => !$rows, |
| 115 | ]; |
| 116 | } |
| 117 | } |