Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
49 / 49
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
category_page
100.00% covered (success)
100.00%
49 / 49
100.00% covered (success)
100.00%
3 / 3
14
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 reasons
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
8
 export_for_template
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
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
17namespace local_atrisk\output;
18
19use renderable;
20use renderer_base;
21use 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 */
30class 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}