view_submission_utils.php 9.57 KB
Newer Older
1
<?php
2
namespace assignsubmission_dta;
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17

Lückemeyer's avatar
Lückemeyer committed
18
19
20
21
22
23
/**
 * utility class for DTA submission plugin result display
 *
 * @package assignsubmission_dta
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
24
25
26
27
28
29
use assignsubmission_dta\db_utils;
use assignsubmission_dta\dta_backend_utils;
use assignsubmission_dta\models\dta_result;
use assignsubmission_dta\models\dta_result_summary;
use assignsubmission_dta\models\dta_recommendation;

Lückemeyer's avatar
Lückemeyer committed
30
31
class view_submission_utils {

Lückemeyer's avatar
Lückemeyer committed
32
    /**
Lückemeyer's avatar
Lückemeyer committed
33
34
     * Broadly used in logic, parametrized for easier change.
     */
35
36
    const COMPONENT_NAME = "assignsubmission_dta";

37
38
39
    /**
     * generates a short summary html
     *
Lückemeyer's avatar
Lückemeyer committed
40
41
     * @param int $assignmentid assignment
     * @param int $submissionid submission to create a report for
42
43
     * @return string html
     */
44
    public static function generate_summary_html(
45
46
        int $assignmentid,
        int $submissionid
47
48
    ): string {

49
        // Fetch data.
50
        $summary = db_utils::get_Result_Summary_From_Database($assignmentid, $submissionid);
51
52
        $html = "";

53
        // Calculate success rate, if no unknown result states or compilation errors.
54
        $successrate = "?";
55
        if ($summary->unknownCount() == 0 && $summary->compilationErrorCount() == 0) {
56
            $successrate = round(($summary->successfulCount() / $summary->resultCount()) * 100, 2 );
57
58
        }

59
        // Generate html.
60
61
        $html .= $summary->successfulCount() . "/";
        $html .= ($summary->compilationErrorCount() == 0 && $summary->unknownCount() == 0)
62
            ? $summary->result_Count() . " (" . $successrate . "%)"
63
                : "?";
Lückemeyer's avatar
Lückemeyer committed
64
        $html .= get_string("tests_successful", self::COMPONENT_NAME) . "<br />";
65
66

        if ($summary->compilationErrorCount() > 0) {
Lückemeyer's avatar
Lückemeyer committed
67
            $html .= $summary->compilationErrorCount() . get_string("compilation_errors", self::COMPONENT_NAME) . "<br />";
68
69
70
        }

        if ($summary->unknownCount() > 0) {
Lückemeyer's avatar
Lückemeyer committed
71
            $html .= $summary->unknownCount() . get_string("unknown_state", self::COMPONENT_NAME) . "<br />";
72
        }
73

Lückemeyer's avatar
Lückemeyer committed
74
75
        $showncompetencies = explode(";", $summary->successfultestcompetencies);
        $overallcompetencies = explode(";", $summary->overalltestcompetencies);
Lückemeyer's avatar
Lückemeyer committed
76

Lückemeyer's avatar
Lückemeyer committed
77
        $tmp = "";
Lückemeyer's avatar
Lückemeyer committed
78
79
80
        for ($index = 0, $size = count($showncompetencies); $index < $size; $index++) {
            $shown = $showncompetencies[$index];
            $comp = $overallcompetencies[$index];
Lückemeyer's avatar
Lückemeyer committed
81
            // If the competency was actually assessed by the assignment and tests, add a summary entry.
Lückemeyer's avatar
Lückemeyer committed
82
            if ($shown != "0") {
Lückemeyer's avatar
Lückemeyer committed
83
                $tmp .= get_string("comp" . $index, self::COMPONENT_NAME) .
Lückemeyer's avatar
Lückemeyer committed
84
                " " . 100 * floatval($shown) / floatval($comp) . "% " . "<br />";
Lückemeyer's avatar
Lückemeyer committed
85
86
            }
        }
Lückemeyer's avatar
Lückemeyer committed
87

Lückemeyer's avatar
Lückemeyer committed
88
        $html .= get_string("success_competencies", self::COMPONENT_NAME) . "<br />" . $tmp . "<br />";
89

90
        return \html_writer::div($html, "dtaSubmissionSummary");
91
92
    }

93
 /**
Kurzenberger's avatar
Kurzenberger committed
94
95
96
97
98
99
 * Generiert die detaillierte HTML-Ansicht, einschließlich Zusammenfassung, Kompetenzen, Details und Empfehlungen.
 *
 * @param int $assignmentid Assignment-ID
 * @param int $submissionid Submission-ID, für die der Bericht erstellt wird
 * @return string HTML-Code
 */
100
public static function generate_detail_html(
Kurzenberger's avatar
Kurzenberger committed
101
102
103
104
105
106
107
108
    int $assignmentid,
    int $submissionid
): string {

    // HTML-Inhalt initialisieren
    $html = "";

    // Daten abrufen
109
    $summary = db_utils::get_Result_Summary_From_Database($assignmentid, $submissionid);
Kurzenberger's avatar
Kurzenberger committed
110
111
112
113
114
115
116
117
118
119
120

    // CSS-Klassen und HTML-Attributarrays definieren
    $tableheaderrowattributes = ["class" => "dtaTableHeaderRow"];
    $tablerowattributes = ["class" => "dtaTableRow"];
    $attributes = ["class" => "dtaTableData"];
    $unknownattributes = 'dtaResultUnknown';
    $successattributes = 'dtaResultSuccess';
    $failureattributes = 'dtaResultFailure';
    $compilationerrorattributes = 'dtaResultCompilationError';

    // **Zusammenfassungstabelle erstellen**
121
    // (Ihr bisheriger Code bleibt unverändert)
122

Kurzenberger's avatar
Kurzenberger committed
123
    // **Abstand zwischen Tabellen**
124
    $html .= \html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
125

126
127
    // **Empfehlungstabelle hinzufügen**
    // Empfehlungen für die Submission abrufen
128
    $recommendations = db_utils::get_recommendations_from_database($assignmentid, $submissionid);
Kurzenberger's avatar
Kurzenberger committed
129

130
131
132
133
    if (!empty($recommendations)) {
        // **Sortierparameter abrufen**
        $allowed_sort_fields = ['topic', 'exercise_name', 'difficulty', 'score'];
        $allowed_sort_dirs = ['asc', 'desc'];
Kurzenberger's avatar
Kurzenberger committed
134

135
136
137
        // Sortierparameter aus POST-Daten abrufen
        $sortby = isset($_POST['sortby']) ? $_POST['sortby'] : 'score';
        $sortdir = isset($_POST['sortdir']) ? $_POST['sortdir'] : 'asc';
138

139
140
141
142
143
144
        // Sortierparameter validieren
        if (!in_array($sortby, $allowed_sort_fields)) {
            $sortby = 'score';
        }
        if (!in_array($sortdir, $allowed_sort_dirs)) {
            $sortdir = 'asc';
145
146
        }

147
148
149
150
        // Empfehlungen sortieren
        usort($recommendations, function($a, $b) use ($sortby, $sortdir) {
            $valueA = $a->{$sortby};
            $valueB = $b->{$sortby};
151

152
153
154
155
            if (is_numeric($valueA) && is_numeric($valueB)) {
                $comparison = $valueA - $valueB;
            } else {
                $comparison = strnatcasecmp($valueA, $valueB);
Kurzenberger's avatar
Kurzenberger committed
156
            }
157

158
159
            if ($comparison == 0) {
                return 0;
Kurzenberger's avatar
Kurzenberger committed
160
            }
161

162
163
164
165
            if ($sortdir == 'asc') {
                return ($comparison < 0) ? -1 : 1;
            } else {
                return ($comparison < 0) ? 1 : -1;
166
            }
167
        });
168

Kurzenberger's avatar
Kurzenberger committed
169
        // Überschrift für Empfehlungen
170
        $html .= \html_writer::tag('h3', get_string('recommendations', self::COMPONENT_NAME));
Kurzenberger's avatar
Kurzenberger committed
171

172
173
174
175
176
177
178
179
180
        // Helper-Funktion zum Generieren von sortierbaren Headern
        $generate_sortable_header = function($column_name, $display_name) use ($sortby, $sortdir) {
            $new_sortdir = ($sortby == $column_name && $sortdir == 'asc') ? 'desc' : 'asc';
            $class = 'dtaTableHeader';
            if ($sortby == $column_name) {
                $class .= ' sorted ' . $sortdir;
            }

            // Button erstellen
181
            $button = \html_writer::empty_tag('input', [
182
183
184
185
186
187
188
                'type' => 'submit',
                'name' => 'sortbutton',
                'value' => ($new_sortdir == 'asc' ? '↑' : '↓'),
                'class' => 'sort-button'
            ]);

            // Hidden Inputs für Sortierparameter
189
            $hidden_inputs = \html_writer::empty_tag('input', [
190
191
192
193
                'type' => 'hidden',
                'name' => 'sortby',
                'value' => $column_name
            ]);
194
            $hidden_inputs .= \html_writer::empty_tag('input', [
195
196
197
198
199
200
                'type' => 'hidden',
                'name' => 'sortdir',
                'value' => $new_sortdir
            ]);

            // Formular für den Button erstellen
201
            $form = \html_writer::start_tag('form', ['method' => 'post', 'style' => 'display:inline']);
202
203
            $form .= $hidden_inputs;
            $form .= $display_name . ' ' . $button;
204
            $form .= \html_writer::end_tag('form');
205

206
            return \html_writer::tag("th", $form, ["class" => $class]);
207
208
        };

Kurzenberger's avatar
Kurzenberger committed
209
210
        // Tabellenkopf für Empfehlungen
        $tableheader = "";
211
212
        $tableheader .= $generate_sortable_header('topic', get_string("topic", self::COMPONENT_NAME));
        $tableheader .= $generate_sortable_header('exercise_name', get_string("exercise_name", self::COMPONENT_NAME));
213
        $tableheader .= \html_writer::tag("th", get_string("url", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
214
215
        $tableheader .= $generate_sortable_header('difficulty', get_string("difficulty", self::COMPONENT_NAME));
        $tableheader .= $generate_sortable_header('score', get_string("score", self::COMPONENT_NAME));
Kurzenberger's avatar
Kurzenberger committed
216

217
218
        $tableheader = \html_writer::tag("tr", $tableheader, ["class" => "dtaTableHeaderRow"]);
        $tableheader = \html_writer::tag("thead", $tableheader);
Kurzenberger's avatar
Kurzenberger committed
219
220
221
222
223

        // Tabellenkörper für Empfehlungen
        $tablebody = "";
        foreach ($recommendations as $recommendation) {
            $tablerow = "";
224
225
226
227
228
            $tablerow .= \html_writer::tag("td", $recommendation->topic, $attributes);
            $tablerow .= \html_writer::tag("td", $recommendation->exercise_name, $attributes);
            $tablerow .= \html_writer::tag("td", \html_writer::link($recommendation->url, $recommendation->url), $attributes);
            $tablerow .= \html_writer::tag("td", $recommendation->difficulty, $attributes);
            $tablerow .= \html_writer::tag("td", $recommendation->score, $attributes);
Kurzenberger's avatar
Kurzenberger committed
229

230
            $tablebody .= \html_writer::tag("tr", $tablerow, $tablerowattributes);
Kurzenberger's avatar
Kurzenberger committed
231
        }
232
        $tablebody = \html_writer::tag("tbody", $tablebody);
233

Kurzenberger's avatar
Kurzenberger committed
234
        // Empfehlungstabelle zusammenstellen
235
        $html .= \html_writer::tag("table", $tableheader . $tablebody, ["class" => "dtaTable"]);
236
237
    }

Kurzenberger's avatar
Kurzenberger committed
238
    // Abschließendes Div für die gesamte HTML-Ausgabe
239
    $html = \html_writer::div($html, "dtaSubmissionDetails");
Kurzenberger's avatar
Kurzenberger committed
240
241
242
243
244

    return $html;
}


245
246


247
}