"dta/classes/view.php" did not exist on "e69d8ecd01c835732269ab60b470264e8c8c45ab"
dta_view_submission_utils.php 20.4 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
use assignsubmission_dta\dta_db_utils;
25
26
27
28
29
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;

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

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
    const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = "assignsubmission_dta";
36

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 assignsubmission_dta_generate_summary_html(
45
46
        int $assignmentid,
        int $submissionid
47
48
    ): string {

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

53
        // Calculate success rate, if no unknown result states or compilation errors.
54
        $successrate = "?";
Kurzenberger's avatar
Kurzenberger committed
55
56
        if ($summary->unknown_count() == 0 && $summary->compilation_error_count() == 0) {
            $successrate = round(($summary->successful_count() / $summary->result_count()) * 100, 2 );
57
58
        }

59
        // Generate html.
Kurzenberger's avatar
Kurzenberger committed
60
61
        $html .= $summary->successful_count() . "/";
        $html .= ($summary->compilation_error_count() == 0 && $summary->unknown_count() == 0)
62
            ? $summary->result_Count() . " (" . $successrate . "%)"
63
                : "?";
64
        $html .= get_string("tests_successful", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME) . "<br />";
65

Kurzenberger's avatar
Kurzenberger committed
66
        if ($summary->compilation_error_count() > 0) {
67
            $html .= $summary->compilation_error_count() . get_string("compilation_errors", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME) . "<br />";
68
69
        }

Kurzenberger's avatar
Kurzenberger committed
70
        if ($summary->unknown_count() > 0) {
71
            $html .= $summary->unknown_count() . get_string("unknown_state", self::ASSIGNSUBMISSION_DTA_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") {
83
                $tmp .= get_string("comp" . $index, self::ASSIGNSUBMISSION_DTA_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

88
        $html .= get_string("success_competencies", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME) . "<br />" . $tmp . "<br />";
89

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

Kurzenberger's avatar
Kurzenberger committed
93
94
/**
 * generates detailed view html
Kurzenberger's avatar
Kurzenberger committed
95
 *
Kurzenberger's avatar
Kurzenberger committed
96
97
 * @param int $assignmentid assignment
 * @param int $submissionid submission to create a report for
Kurzenberger's avatar
Kurzenberger committed
98
 */
99
public static function assignsubmission_dta_generate_detail_html(
Kurzenberger's avatar
Kurzenberger committed
100
101
102
103
    int $assignmentid,
    int $submissionid
): string {

Kurzenberger's avatar
Kurzenberger committed
104
    // Fetch data.
105
106
    $summary = dta_db_utils::assignsubmission_dta_get_result_summary_from_database($assignmentid, $submissionid);
    $recommendations = dta_db_utils::assignsubmission_dta_get_recommendations_from_database($assignmentid, $submissionid);
Kurzenberger's avatar
Kurzenberger committed
107

Kurzenberger's avatar
Kurzenberger committed
108
    $html = "";
Kurzenberger's avatar
Kurzenberger committed
109

Kurzenberger's avatar
Kurzenberger committed
110
    // Define a few css classes and prepare html attribute arrays to beautify the output.
Kurzenberger's avatar
Kurzenberger committed
111
112
    $tableheaderrowattributes = ["class" => "dtaTableHeaderRow"];
    $tablerowattributes = ["class" => "dtaTableRow"];
Kurzenberger's avatar
Kurzenberger committed
113
    $resultrowattributes = $tablerowattributes;
Kurzenberger's avatar
Kurzenberger committed
114
115
116
117
    $unknownattributes = 'dtaResultUnknown';
    $successattributes = 'dtaResultSuccess';
    $failureattributes = 'dtaResultFailure';
    $compilationerrorattributes = 'dtaResultCompilationError';
Kurzenberger's avatar
Kurzenberger committed
118
119
120
121
122
123
124
    $attributes = ["class" => "dtaTableData"];

    // ***************
    // SUMMARY TABLE
    // ***************

    $tmp = "";
125
    $tmp .= \html_writer::tag("th", get_string("summary", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), ["class" => "dtaTableHeader"]);
Kurzenberger's avatar
Kurzenberger committed
126
127
128
129
130
131
132
133
    $tmp .= \html_writer::empty_tag("th", ["class" => "dtaTableHeader"]);
    $header = \html_writer::tag("tr", $tmp, $tableheaderrowattributes);
    $header = \html_writer::tag("thead", $header);

    $body = "";

    // Total items.
    $tmp = "";
134
    $tmp .= \html_writer::tag("td", get_string("total_items", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
135
136
137
138
139
140
141
    $tmp .= \html_writer::tag("td", $summary->result_count(), $attributes);
    $resultrowattributes = $tablerowattributes;
    $resultrowattributes['class'] .= " " . $unknownattributes;
    $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

    // Tests successful.
    $tmp = "";
142
    $tmp .= \html_writer::tag("td", get_string("tests_successful", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    $tmp .= \html_writer::tag("td", $summary->successful_count(), $attributes);
    $resultrowattributes = $tablerowattributes;
    $successrate = "?";
    if ($summary->unknown_count() > 0 || $summary->compilation_error_count() > 0) {
        $resultrowattributes['class'] .= " " . $unknownattributes;
    } else {
        $successrate = round(($summary->successful_count() / $summary->result_count()) * 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);

    // Failures.
    $tmp = "";
162
    $tmp .= \html_writer::tag("td", get_string("failures", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
163
164
165
166
167
168
169
170
171
172
173
    $tmp .= \html_writer::tag("td", $summary->failed_count(), $attributes);
    $resultrowattributes = $tablerowattributes;
    if ($summary->failed_count() > 0) {
        $resultrowattributes['class'] .= " " . $failureattributes;
    } else {
        $resultrowattributes['class'] .= " " . $successattributes;
    }
    $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

    // Compilation errors.
    $tmp = "";
174
    $tmp .= \html_writer::tag("td", get_string("compilation_errors", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
175
176
177
178
179
180
181
182
183
184
185
    $tmp .= \html_writer::tag("td", $summary->compilation_error_count(), $attributes);
    $resultrowattributes = $tablerowattributes;
    if ($summary->compilation_error_count() > 0) {
        $resultrowattributes['class'] .= " " . $compilationerrorattributes;
    } else {
        $resultrowattributes['class'] .= " " . $successattributes;
    }
    $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

    // Unknown state.
    $tmp = "";
186
    $tmp .= \html_writer::tag("td", get_string("unknown_state", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
187
188
189
190
191
192
193
194
195
196
197
    $tmp .= \html_writer::tag("td", $summary->unknown_count(), $attributes);
    $resultrowattributes = $tablerowattributes;
    if ($summary->unknown_count() > 0) {
        $resultrowattributes['class'] .= " " . $unknownattributes;
    } else {
        $resultrowattributes['class'] .= " " . $successattributes;
    }
    $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

    // Success rate.
    $tmp = "";
198
    $tmp .= \html_writer::tag("td", \html_writer::tag("b", get_string("success_rate", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)), $attributes);
Kurzenberger's avatar
Kurzenberger committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
    $tmp .= \html_writer::tag(
        "td",
        \html_writer::tag("b", $summary->successful_count() . "/" . 
            (($summary->compilation_error_count() == 0 && $summary->unknown_count() == 0) 
                ? $summary->result_count() . " (" . $successrate . "%)" 
                : "?")),
        $attributes
    );

    $resultrowattributes = $tablerowattributes;
    if ($summary->unknown_count() > 0 || $summary->compilation_error_count() > 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);
Kurzenberger's avatar
Kurzenberger committed
221

Kurzenberger's avatar
Kurzenberger committed
222
223
    $body = \html_writer::tag("tbody", $body);
    $table = \html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
224

Kurzenberger's avatar
Kurzenberger committed
225
    $html .= $table;
226

Kurzenberger's avatar
Kurzenberger committed
227
228
    // Add empty div for spacing after summary.
    $html .= \html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
Kurzenberger's avatar
Kurzenberger committed
229

Kurzenberger's avatar
Kurzenberger committed
230
231
232
    // ***************
    // RECOMMENDATIONS TABLE
    // ***************
233
    if (!empty($recommendations)) {
Kurzenberger's avatar
Kurzenberger committed
234
        // Sorting logic.
235
236
        $allowed_sort_fields = ['topic', 'exercise_name', 'difficulty', 'score'];
        $allowed_sort_dirs = ['asc', 'desc'];
Kurzenberger's avatar
Kurzenberger committed
237

238
239
        $sortby = isset($_POST['sortby']) ? $_POST['sortby'] : 'score';
        $sortdir = isset($_POST['sortdir']) ? $_POST['sortdir'] : 'asc';
240

241
242
243
244
245
        if (!in_array($sortby, $allowed_sort_fields)) {
            $sortby = 'score';
        }
        if (!in_array($sortdir, $allowed_sort_dirs)) {
            $sortdir = 'asc';
246
247
        }

248
249
250
        usort($recommendations, function($a, $b) use ($sortby, $sortdir) {
            $valueA = $a->{$sortby};
            $valueB = $b->{$sortby};
251

252
253
254
255
            if (is_numeric($valueA) && is_numeric($valueB)) {
                $comparison = $valueA - $valueB;
            } else {
                $comparison = strnatcasecmp($valueA, $valueB);
Kurzenberger's avatar
Kurzenberger committed
256
            }
257

258
259
            if ($comparison == 0) {
                return 0;
Kurzenberger's avatar
Kurzenberger committed
260
            }
261

262
263
264
265
            if ($sortdir == 'asc') {
                return ($comparison < 0) ? -1 : 1;
            } else {
                return ($comparison < 0) ? 1 : -1;
266
            }
267
        });
268

269
        $html .= \html_writer::tag('h3', get_string('recommendations', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
Kurzenberger's avatar
Kurzenberger committed
270

271
272
273
274
275
276
277
        $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;
            }

Kurzenberger's avatar
Kurzenberger committed
278
            // Sort button.
279
            $button = \html_writer::empty_tag('input', [
280
281
282
283
284
285
                'type' => 'submit',
                'name' => 'sortbutton',
                'value' => ($new_sortdir == 'asc' ? '↑' : '↓'),
                'class' => 'sort-button'
            ]);

Kurzenberger's avatar
Kurzenberger committed
286
            // Hidden inputs.
287
            $hidden_inputs = \html_writer::empty_tag('input', [
288
289
290
291
                'type' => 'hidden',
                'name' => 'sortby',
                'value' => $column_name
            ]);
292
            $hidden_inputs .= \html_writer::empty_tag('input', [
293
294
295
296
297
                'type' => 'hidden',
                'name' => 'sortdir',
                'value' => $new_sortdir
            ]);

298
            $form = \html_writer::start_tag('form', ['method' => 'post', 'style' => 'display:inline']);
299
300
            $form .= $hidden_inputs;
            $form .= $display_name . ' ' . $button;
301
            $form .= \html_writer::end_tag('form');
302

303
            return \html_writer::tag("th", $form, ["class" => $class]);
304
305
        };

Kurzenberger's avatar
Kurzenberger committed
306
        // Table header for recommendations.
Kurzenberger's avatar
Kurzenberger committed
307
        $tableheader = "";
308
309
310
311
312
        $tableheader .= $generate_sortable_header('topic', get_string("topic", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
        $tableheader .= $generate_sortable_header('exercise_name', get_string("exercise_name", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
        $tableheader .= \html_writer::tag("th", get_string("url", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), ["class" => "dtaTableHeader"]);
        $tableheader .= $generate_sortable_header('difficulty', get_string("difficulty", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
        $tableheader .= $generate_sortable_header('score', get_string("score", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
Kurzenberger's avatar
Kurzenberger committed
313

314
315
        $tableheader = \html_writer::tag("tr", $tableheader, ["class" => "dtaTableHeaderRow"]);
        $tableheader = \html_writer::tag("thead", $tableheader);
Kurzenberger's avatar
Kurzenberger committed
316

Kurzenberger's avatar
Kurzenberger committed
317
        // Table body for recommendations.
Kurzenberger's avatar
Kurzenberger committed
318
319
320
        $tablebody = "";
        foreach ($recommendations as $recommendation) {
            $tablerow = "";
321
322
323
324
325
            $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
326

327
            $tablebody .= \html_writer::tag("tr", $tablerow, $tablerowattributes);
Kurzenberger's avatar
Kurzenberger committed
328
        }
329
        $tablebody = \html_writer::tag("tbody", $tablebody);
330

331
        $html .= \html_writer::tag("table", $tableheader . $tablebody, ["class" => "dtaTable"]);
Kurzenberger's avatar
Kurzenberger committed
332
333
334

        // Add empty div for spacing after recommendations.
        $html .= \html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
335
336
    }

Kurzenberger's avatar
Kurzenberger committed
337
338
339
340
341
    // ***************
    // COMPETENCY ASSESSMENT TABLE
    // ***************
    $body = "";
    $tmp = "";
342
    $tmp .= \html_writer::tag("th", get_string("competencies", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), ["class" => "dtaTableHeader"]);
Kurzenberger's avatar
Kurzenberger committed
343
344
345
346
347
348
349
350
351
352
353
354
355
356
    $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];
        // If the competency was actually assessed by the assignment and tests, add a row in the table.
        if ($comp != "0") {
            $resultrowattributes = $tablerowattributes;
            $tmp = "";
357
            $tmp .= \html_writer::tag("td", get_string("comp" . $index, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $resultrowattributes);
Kurzenberger's avatar
Kurzenberger committed
358
            $tmp .= \html_writer::tag("td", (100 * floatval($shown) / floatval($comp)) . "% (" . $shown . " / " . $comp . ")", $resultrowattributes);
359
            $tmp .= \html_writer::tag("td", get_string("comp_expl" . $index, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $resultrowattributes);
Kurzenberger's avatar
Kurzenberger committed
360
361
362
363
364
365
366
367
368
369
370
371
372
373
            $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);
        }
    }
    $body = \html_writer::tag("tbody", $body);
    $html .= \html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);

    // Add empty div for spacing between competency and details table.
    $html .= \html_writer::empty_tag("div", ["class" => "dtaSpacer"]);

    // ***************
    // DETAILS TABLE
    // ***************

    $tmp = "";
374
    $tmp .= \html_writer::tag("th", get_string("details", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), ["class" => "dtaTableHeader"]);
Kurzenberger's avatar
Kurzenberger committed
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
    $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) {
        // Add spacer first if not null.
        if (!is_null($spacerrow)) {
            $body .= $spacerrow;
        }

        $resultrowattributes = $tablerowattributes;

        // Set CSS class for colored left-border according to results state.
        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 = "";
401
        $tmp .= \html_writer::tag("td", get_string("package_name", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
402
        $tmp .= \html_writer::tag("td", $r->packagename, $attributes);
403
        $tmp .= \html_writer::tag("td", get_string("unit_name", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
404
        $tmp .= \html_writer::tag("td", $r->classname, $attributes);
405
        $tmp .= \html_writer::tag("td", get_string("test_name", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
406
407
408
409
        $tmp .= \html_writer::tag("td", $r->name, $attributes);
        $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

        $tmp = "";
410
411
        $tmp .= \html_writer::tag("td", get_string("status", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
        $tmp .= \html_writer::tag("td", dta_result::assignsubmission_dta_get_statename($r->state), $attributes);
Kurzenberger's avatar
Kurzenberger committed
412
413
414
415
416
        $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

        // If state is different than successful, show additional info.
        if ($r->state != 1) {
            $tmp = "";
417
            $tmp .= \html_writer::tag("td", get_string("failure_type", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
418
419
420
421
            $tmp .= \html_writer::tag("td", $r->failureType, $attributes);
            $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

            $tmp = "";
422
            $tmp .= \html_writer::tag("td", get_string("failure_reason", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
423
424
425
426
427
            $tmp .= \html_writer::tag("td", $r->failureReason, $attributes);
            $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);

            if (!is_null($r->lineNumber) && $r->lineNumber > 0) {
                $tmp = "";
428
                $tmp .= \html_writer::tag("td", get_string("line_no", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
429
430
431
432
433
434
                $tmp .= \html_writer::tag("td", $r->lineNumber, $attributes);
                $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);
            }

            if (!is_null($r->columnNumber) && $r->columnNumber > 0) {
                $tmp = "";
435
                $tmp .= \html_writer::tag("td", get_string("col_no", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
436
437
438
439
440
441
                $tmp .= \html_writer::tag("td", $r->columnNumber, $attributes);
                $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);
            }

            if (!is_null($r->position) && $r->position > 0) {
                $tmp = "";
442
                $tmp .= \html_writer::tag("td", get_string("pos", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
443
444
445
446
447
                $tmp .= \html_writer::tag("td", $r->position, $attributes);
                $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);
            }

            $tmp = "";
448
            $tmp .= \html_writer::tag("td", get_string("stacktrace", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME), $attributes);
Kurzenberger's avatar
Kurzenberger committed
449
450
451
452
453
454
455
456
457
458
459
460
            $tmp .= \html_writer::tag("td", \html_writer::tag("details", $r->stacktrace, ["class" => "dtaStacktraceDetails"]), $attributes);
            $body .= \html_writer::tag("tr", $tmp, $resultrowattributes);
        }

        if (is_null($spacerrow)) {
            $spacerrow = \html_writer::empty_tag("tr", ["class" => "dtaTableSpacer"]);
        }
    }

    $html .= \html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);

    // Wrap generated html into final div.
461
    $html = \html_writer::div($html, "dtaSubmissionDetails");
Kurzenberger's avatar
Kurzenberger committed
462
463
464
465
466

    return $html;
}


467
468


Kurzenberger's avatar
Kurzenberger committed
469

470
}