<?php // 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/>. /** * utility class for DTA submission plugin result display * * @package assignsubmission_dta * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class view_submission_utils { /** * Broadly used in logic, parametrized for easier change. */ const COMPONENT_NAME = "assignsubmission_dta"; /** * generates a short summary html * * @param int $assignmentid assignment * @param int $submissionid submission to create a report for * @return string html */ public static function generatesummaryhtml( int $assignmentid, int $submissionid ): string { // Fetch data. $summary = DbUtils::getResultSummaryFromDatabase($assignmentid, $submissionid); $html = ""; // Calculate success rate, if no unknown result states or compilation errors. $successrate = "?"; if ($summary->unknownCount() == 0 && $summary->compilationErrorCount() == 0) { $successrate = round(($summary->successfulCount() / $summary->resultCount()) * 100, 2 ); } // Generate html. $html .= $summary->successfulCount() . "/"; $html .= ($summary->compilationErrorCount() == 0 && $summary->unknownCount() == 0) ? $summary->resultCount() . " (" . $successrate . "%)" : "?"; $html .= get_string("tests_successful", self::COMPONENT_NAME) . "<br />"; if ($summary->compilationErrorCount() > 0) { $html .= $summary->compilationErrorCount() . get_string("compilation_errors", self::COMPONENT_NAME) . "<br />"; } if ($summary->unknownCount() > 0) { $html .= $summary->unknownCount() . get_string("unknown_state", self::COMPONENT_NAME) . "<br />"; } $showncompetencies = explode(";", $summary->successfultestcompetencies); $overallcompetencies = explode(";", $summary->overalltestcompetencies); $tmp = ""; for ($index = 0, $size = count($showncompetencies); $index < $size; $index++) { $shown = $showncompetencies[$index]; $comp = $overallcompetencies[$index]; // If the competency was actually assessed by the assignment and tests, add a summary entry. if ($shown != "0") { $tmp .= get_string("comp" . $index, self::COMPONENT_NAME) . " " . 100 * floatval($shown) / floatval($comp) . "% " . "<br />"; } } $html .= get_string("success_competencies", self::COMPONENT_NAME) . "<br />" . $tmp . "<br />"; return html_writer::div($html, "dtaSubmissionSummary"); } /** * 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 */ public static function generatedetailhtml( int $assignmentid, int $submissionid ): string { // HTML-Inhalt initialisieren $html = ""; // Daten abrufen $summary = DbUtils::getResultSummaryFromDatabase($assignmentid, $submissionid); // 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** // Kopfzeile $tmp = ""; $tmp .= html_writer::tag("th", get_string("summary", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]); $header = html_writer::tag("tr", $tmp, $tableheaderrowattributes); $header = html_writer::tag("thead", $header); // Tabellenkörper $body = ""; // Gesamtanzahl $tmp = ""; $tmp .= html_writer::tag("td", get_string("total_items", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $summary->resultCount(), $attributes); $resultrowattributes = $tablerowattributes; $resultrowattributes['class'] .= " " . $unknownattributes; $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Erfolgreiche Tests $tmp = ""; $tmp .= html_writer::tag("td", get_string("tests_successful", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $summary->successfulCount(), $attributes); $resultrowattributes = $tablerowattributes; $successrate = "?"; if ($summary->unknownCount() > 0 || $summary->compilationErrorCount() > 0) { $resultrowattributes['class'] .= " " . $unknownattributes; } else { $successrate = round(($summary->successfulCount() / $summary->resultCount()) * 100, 2 ); if ($successrate < 50) { $resultrowattributes['class'] .= " " . $compilationerrorattributes; } else if ($successrate < 75) { $resultrowattributes['class'] .= " " . $failureattributes; } else { $resultrowattributes['class'] .= " " . $successattributes; } } $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Fehlgeschlagene Tests $tmp = ""; $tmp .= html_writer::tag("td", get_string("failures", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $summary->failedCount(), $attributes); $resultrowattributes = $tablerowattributes; if ($summary->failedCount() > 0) { $resultrowattributes['class'] .= " " . $failureattributes; } else { $resultrowattributes['class'] .= " " . $successattributes; } $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Kompilierungsfehler $tmp = ""; $tmp .= html_writer::tag("td", get_string("compilation_errors", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $summary->compilationErrorCount(), $attributes); $resultrowattributes = $tablerowattributes; if ($summary->compilationErrorCount() > 0) { $resultrowattributes['class'] .= " " . $compilationerrorattributes; } else { $resultrowattributes['class'] .= " " . $successattributes; } $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Unbekannter Status $tmp = ""; $tmp .= html_writer::tag("td", get_string("unknown_state", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $summary->unknownCount(), $attributes); $resultrowattributes = $tablerowattributes; if ($summary->unknownCount() > 0) { $resultrowattributes['class'] .= " " . $unknownattributes; } else { $resultrowattributes['class'] .= " " . $successattributes; } $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Erfolgsrate $tmp = ""; $tmp .= html_writer::tag("td", html_writer::tag("b", get_string("success_rate", self::COMPONENT_NAME)), $attributes); $tmp .= html_writer::tag( "td", html_writer::tag("b", $summary->successfulCount() . "/" . (($summary->compilationErrorCount() == 0 && $summary->unknownCount() == 0) ? $summary->resultCount() . " (" . $successrate . "%)" : "?")), $attributes); $resultrowattributes = $tablerowattributes; if ($summary->unknownCount() > 0 || $summary->compilationErrorCount() > 0) { $resultrowattributes['class'] .= " " . $unknownattributes; } else { if ($successrate < 50) { $resultrowattributes['class'] .= " " . $compilationerrorattributes; } else if ($successrate < 75) { $resultrowattributes['class'] .= " " . $failureattributes; } else { $resultrowattributes['class'] .= " " . $successattributes; } } $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Tabelle zusammenstellen $body = html_writer::tag("tbody", $body); $table = html_writer::tag("table", $header . $body, ["class" => "dtaTable"]); $html .= $table; // **Abstand zwischen Tabellen** $html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]); // **Kompetenzbewertungstabelle erstellen** $body = ""; $tmp = ""; $tmp .= html_writer::tag("th", get_string("competencies", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]); $header = html_writer::tag("tr", $tmp, $tableheaderrowattributes); $header = html_writer::tag("thead", $header); $showncompetencies = explode(";", $summary->successfultestcompetencies); $overallcompetencies = explode(";", $summary->overalltestcompetencies); for ($index = 0, $size = count($overallcompetencies); $index < $size; $index++) { $comp = $overallcompetencies[$index]; $shown = $showncompetencies[$index]; // Kompetenz wird nur hinzugefügt, wenn sie bewertet wurde if ($comp != "0") { $resultrowattributes = $tablerowattributes; $tmp = ""; $tmp .= html_writer::tag("td", get_string("comp" . $index, self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", 100 * floatval($shown) / floatval($comp) . "% " . "(" . $shown . " / " . $comp . ")", $attributes); $tmp .= html_writer::tag("td", get_string("comp_expl" . $index, self::COMPONENT_NAME), $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); } } $body = html_writer::tag("tbody", $body); $html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]); // **Abstand zwischen Tabellen** $html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]); // **Detailtabelle erstellen** $tmp = ""; $tmp .= html_writer::tag("th", get_string("details", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]); $header = html_writer::tag("tr", $tmp, $tableheaderrowattributes); $header = html_writer::tag("thead", $header); $body = ""; $spacerrow = null; foreach ($summary->results as $r) { // Abstand zwischen den Ergebnissen if (!is_null($spacerrow)) { $body .= $spacerrow; } $resultrowattributes = $tablerowattributes; // CSS-Klasse basierend auf dem Status des Ergebnisses hinzufügen if ($r->state == 0) { $resultrowattributes['class'] .= ' dtaResultUnknown'; } else if ($r->state == 1) { $resultrowattributes['class'] .= ' dtaResultSuccess'; } else if ($r->state == 2) { $resultrowattributes['class'] .= ' dtaResultFailure'; } else if ($r->state == 3) { $resultrowattributes['class'] .= ' dtaResultCompilationError'; } $tmp = ""; $tmp .= html_writer::tag("td", get_string("package_name", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->packagename, $attributes); $tmp .= html_writer::tag("td", get_string("unit_name", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->classname, $attributes); $tmp .= html_writer::tag("td", get_string("test_name", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->name, $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); $tmp = ""; $tmp .= html_writer::tag("td", get_string("status", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", DtaResult::getStateName($r->state), $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Zusätzliche Informationen für nicht erfolgreiche Zustände if ($r->state != 1) { $tmp = ""; $tmp .= html_writer::tag("td", get_string("failure_type", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->failureType, $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); $tmp = ""; $tmp .= html_writer::tag("td", get_string("failure_reason", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->failureReason, $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); // Zeilennummer anzeigen, falls vorhanden if (!is_null($r->lineNumber) && $r->lineNumber > 0) { $tmp = ""; $tmp .= html_writer::tag("td", get_string("line_no", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->lineNumber, $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); } // Spaltennummer anzeigen, falls vorhanden if (!is_null($r->columnNumber) && $r->columnNumber > 0) { $tmp = ""; $tmp .= html_writer::tag("td", get_string("col_no", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->columnNumber, $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); } // Position anzeigen, falls vorhanden if (!is_null($r->position) && $r->position > 0) { $tmp = ""; $tmp .= html_writer::tag("td", get_string("pos", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", $r->position, $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); } // Stacktrace anzeigen $tmp = ""; $tmp .= html_writer::tag("td", get_string("stacktrace", self::COMPONENT_NAME), $attributes); $tmp .= html_writer::tag("td", html_writer::tag("details", $r->stacktrace, ["class" => "dtaStacktraceDetails"]), $attributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes); } // Spacerrow für den nächsten Durchlauf setzen if (is_null($spacerrow)) { $spacerrow = html_writer::empty_tag("tr", ["class" => "dtaTableSpacer"]); } } $body = html_writer::tag("tbody", $body); $html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]); // **Abstand zwischen Detailtabelle und Empfehlungstabelle** $html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]); // **Empfehlungstabelle hinzufügen** // Empfehlungen für die Submission abrufen $recommendations = DbUtils::get_recommendations_from_database($assignmentid, $submissionid); if (!empty($recommendations)) { // Überschrift für Empfehlungen $html .= html_writer::tag('h3', get_string('recommendations', self::COMPONENT_NAME)); // Tabellenkopf für Empfehlungen $tableheader = ""; $tableheader .= html_writer::tag("th", get_string("topic", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tableheader .= html_writer::tag("th", get_string("exercise_name", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tableheader .= html_writer::tag("th", get_string("url", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tableheader .= html_writer::tag("th", get_string("difficulty", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tableheader .= html_writer::tag("th", get_string("score", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tableheader = html_writer::tag("tr", $tableheader, ["class" => "dtaTableHeaderRow"]); $tableheader = html_writer::tag("thead", $tableheader); // Tabellenkörper für Empfehlungen $tablebody = ""; foreach ($recommendations as $recommendation) { $tablerow = ""; $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); $tablebody .= html_writer::tag("tr", $tablerow, $tablerowattributes); } $tablebody = html_writer::tag("tbody", $tablebody); // Empfehlungstabelle zusammenstellen $html .= html_writer::tag("table", $tableheader . $tablebody, ["class" => "dtaTable"]); } // Abschließendes Div für die gesamte HTML-Ausgabe $html = html_writer::div($html, "dtaSubmissionDetails"); return $html; } }