dta_view_submission_utils.php 25.3 KB
Newer Older
1
<?php
2
// This file is part of Moodle - http://moodle.org/.
3
// 
4
5
6
7
8
9
10
11
12
13
14
15
// 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/>.
16

17
18
namespace assignsubmission_dta;

19
use assignsubmission_dta\dta_db_utils;
20
21
22
23
24
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;

25
26
27
28
29
30
/**
 * Utility class for DTA submission plugin result display.
 *
 * @package    assignsubmission_dta
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
31
class dta_view_submission_utils {
Lückemeyer's avatar
Lückemeyer committed
32

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

38
39
40
41
42
43
44
45
46
47
48
49
50
51
   /**
 * Generates a short summary HTML (like your old plugin).
 *
 * @param int $assignmentid The assignment ID.
 * @param int $submissionid The submission ID to create a report for.
 * @return string The HTML summary.
 */
public static function assignsubmission_dta_generate_summary_html(
    int $assignmentid,
    int $submissionid
): string {

    // 1) Retrieve the summary data from the DB (adjust your DB-utils class as needed).
    $summary = dta_db_utils::assignsubmission_dta_get_result_summary_from_database($assignmentid, $submissionid);
52
    print_r($summary);
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

    // 2) Prepare an HTML buffer.
    $html = '';

    // 3) Extract counts from your new method names:
    $unknowncount      = $summary->assignsubmission_dta_unknown_count();
    $compilecount      = $summary->assignsubmission_dta_compilation_error_count();
    $successcount      = $summary->assignsubmission_dta_successful_count();
    $failcount         = $summary->assignsubmission_dta_failed_count();
    $totalcount        = $summary->assignsubmission_dta_result_count();

    // 4) Compute success rate if no unknown/compile errors and total>0.
    $successrate = '?';
    if ($unknowncount === 0 && $compilecount === 0 && $totalcount > 0) {
        $successrate = round(($successcount / $totalcount) * 100, 2);
    }
69

70
71
72
73
74
75
76
77
78
79
80
81
    // 5) “X/Y (Z%) tests successful” line:
    //    If either compile errors or unknown exist -> we show "?"
    //    else X/Y (rate%).
    $html .= $successcount . '/';
    if ($compilecount === 0 && $unknowncount === 0) {
        $html .= ($totalcount > 0)
            ? ($totalcount . ' (' . $successrate . '%)')
            : ('0 (' . $successrate . ')');
    } else {
        $html .= '?';
    }
    $html .= get_string('tests_successful', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME) . "<br />";
82

83
84
85
86
87
88
    // 6) If there are compilation errors, show them:
    if ($compilecount > 0) {
        $html .= $compilecount
              . get_string('compilation_errors', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
              . "<br />";
    }
89

90
91
92
93
94
95
    // 7) If there are unknown results, show them:
    if ($unknowncount > 0) {
        $html .= $unknowncount
              . get_string('unknown_state', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
              . "<br />";
    }
Lückemeyer's avatar
Lückemeyer committed
96

97
98
99
100
101
102
103
    if ($failcount > 0) {
        $html .= $failcount
              . get_string('tests_failed', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
              . "<br />";
    }
    

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
    // 8) Competencies (like your old snippet):
    $showncompetencies   = explode(';', $summary->successfultestcompetencies);
    $overallcompetencies = explode(';', $summary->overalltestcompetencies);

    $tmp = '';
    $size = count($showncompetencies);
    for ($i = 0; $i < $size; $i++) {
        $shown = $showncompetencies[$i];
        $comp  = $overallcompetencies[$i];

        // If the competency was actually used (non-zero?), show a row.
        if ($shown !== '0') {
            $shownval = floatval($shown);
            $compval  = floatval($comp);

            // Guard division by zero:
            $pct = 0;
            if ($compval > 0) {
                $pct = 100.0 * $shownval / $compval;
Lückemeyer's avatar
Lückemeyer committed
123
            }
124
125
126
127

            // “compX XX%<br />”
            $tmp .= get_string('comp' . $i, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
                  . ' ' . round($pct, 2) . '%<br />';
Lückemeyer's avatar
Lückemeyer committed
128
        }
129
    }
Lückemeyer's avatar
Lückemeyer committed
130

131
132
    $html .= get_string('success_competencies', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
         . "<br />" . $tmp . "<br />";
133

134
135
136
    // 9) Wrap it in a DIV for styling, and return.
    return \html_writer::div($html, "dtaSubmissionSummary");
}
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
    /**
     * Generates detailed view HTML.
     *
     * @param int $assignmentid The assignment ID.
     * @param int $submissionid The submission to create a report for.
     * @return string HTML detail view.
     */
    public static function assignsubmission_dta_generate_detail_html(
        int $assignmentid,
        int $submissionid
    ): string {
        // Fetch data.
        $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
        );

        $html = '';

        // *** Summary Table ***
        $tableheaderrowattributes = ['class' => 'dtaTableHeaderRow'];
163
164
165
166
167
        $tablerowattributes       = ['class' => 'dtaTableRow'];
        $resultrowattributes      = $tablerowattributes;
        $unknownattributes        = 'dtaResultUnknown';
        $successattributes        = 'dtaResultSuccess';
        $failureattributes        = 'dtaResultFailure';
168
        $compilationerrorattributes = 'dtaResultCompilationError';
169
        $attributes               = ['class' => 'dtaTableData'];
170

171
        // Build the summary table header.
172
173
174
175
176
177
178
179
180
181
182
        $tmp = \html_writer::tag(
            'th',
            get_string('summary', self::ASSIGNSUBMISSION_DTA_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 = '';

183
184
185
186
187
188
189
        // Pull the counters from the summary object.
        $resultcount      = $summary->assignsubmission_dta_result_count();
        $successfulcount  = $summary->assignsubmission_dta_successful_count();
        $failedcount      = $summary->assignsubmission_dta_failed_count();
        $compilationcount = $summary->assignsubmission_dta_compilation_error_count();
        $unknowncount     = $summary->assignsubmission_dta_unknown_count();

190
191
192
193
194
195
196
        // Total items.
        $tmp = '';
        $tmp .= \html_writer::tag(
            'td',
            get_string('total_items', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
197
        $tmp .= \html_writer::tag('td', $resultcount, $attributes);
198
        $resultrowattributes = $tablerowattributes;
199
        // Original code colors this row as unknown by default:
200
201
202
203
204
205
206
207
208
209
        $resultrowattributes['class'] .= ' ' . $unknownattributes;
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Tests successful.
        $tmp = '';
        $tmp .= \html_writer::tag(
            'td',
            get_string('tests_successful', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
210
        $tmp .= \html_writer::tag('td', $successfulcount, $attributes);
211
        $resultrowattributes = $tablerowattributes;
212
213

        // Compute success rate if no unknown or compilation errors, and resultcount > 0.
214
        $successrate = '?';
215
216
        if ($unknowncount == 0 && $compilationcount == 0 && $resultcount > 0) {
            $successrate = round(($successfulcount / $resultcount) * 100, 2);
217
218
219
220
221
222
223
            if ($successrate < 50) {
                $resultrowattributes['class'] .= ' ' . $compilationerrorattributes;
            } else if ($successrate < 75) {
                $resultrowattributes['class'] .= ' ' . $failureattributes;
            } else {
                $resultrowattributes['class'] .= ' ' . $successattributes;
            }
224
225
226
        } else {
            // If unknown or compilation errors => highlight as unknown.
            $resultrowattributes['class'] .= ' ' . $unknownattributes;
Kurzenberger's avatar
Kurzenberger committed
227
        }
228
229
230
231
232
233
234
235
236
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Failures.
        $tmp = '';
        $tmp .= \html_writer::tag(
            'td',
            get_string('failures', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
237
        $tmp .= \html_writer::tag('td', $failedcount, $attributes);
238
        $resultrowattributes = $tablerowattributes;
239
        if ($failedcount > 0) {
240
            $resultrowattributes['class'] .= ' ' . $failureattributes;
Kurzenberger's avatar
Kurzenberger committed
241
        } else {
242
            $resultrowattributes['class'] .= ' ' . $successattributes;
Kurzenberger's avatar
Kurzenberger committed
243
        }
244
245
246
247
248
249
250
251
252
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Compilation errors.
        $tmp = '';
        $tmp .= \html_writer::tag(
            'td',
            get_string('compilation_errors', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
253
        $tmp .= \html_writer::tag('td', $compilationcount, $attributes);
254
        $resultrowattributes = $tablerowattributes;
255
        if ($compilationcount > 0) {
256
257
258
259
260
261
262
263
264
265
266
267
268
            $resultrowattributes['class'] .= ' ' . $compilationerrorattributes;
        } else {
            $resultrowattributes['class'] .= ' ' . $successattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

        // Unknown state.
        $tmp = '';
        $tmp .= \html_writer::tag(
            'td',
            get_string('unknown_state', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
            $attributes
        );
269
        $tmp .= \html_writer::tag('td', $unknowncount, $attributes);
270
        $resultrowattributes = $tablerowattributes;
271
        if ($unknowncount > 0) {
272
273
274
275
276
277
            $resultrowattributes['class'] .= ' ' . $unknownattributes;
        } else {
            $resultrowattributes['class'] .= ' ' . $successattributes;
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

278
        // Success rate row.
279
280
281
        $tmp = '';
        $tmp .= \html_writer::tag(
            'td',
282
            \html_writer::tag('b', get_string('success_rate', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)),
283
284
            $attributes
        );
285
286
287
288
        // If no compilation errors or unknown => show successrate, else "?".
        $suffix = ($compilationcount == 0 && $unknowncount == 0 && $resultcount > 0)
            ? ($resultcount . ' (' . $successrate . '%)')
            : '?';
289
290
        $tmp .= \html_writer::tag(
            'td',
291
            \html_writer::tag('b', $successfulcount . '/' . $suffix),
292
293
            $attributes
        );
294

295
        $resultrowattributes = $tablerowattributes;
296
        if ($compilationcount == 0 && $unknowncount == 0 && $resultcount > 0) {
297
298
299
300
            if ($successrate !== '?' && $successrate < 50) {
                $resultrowattributes['class'] .= ' ' . $compilationerrorattributes;
            } else if ($successrate !== '?' && $successrate < 75) {
                $resultrowattributes['class'] .= ' ' . $failureattributes;
301
            } else {
302
303
                $resultrowattributes['class'] .= ' ' . $successattributes;
            }
304
305
        } else {
            $resultrowattributes['class'] .= ' ' . $unknownattributes;
306
307
        }
        $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
308

309
310
        // Finalize the summary table.
        $body  = \html_writer::tag('tbody', $body);
311
312
        $table = \html_writer::tag('table', $header . $body, ['class' => 'dtaTable']);
        $html .= $table;
Kurzenberger's avatar
Kurzenberger committed
313

314
        // Spacing after the summary table.
315
        $html .= \html_writer::empty_tag('div', ['class' => 'dtaSpacer']);
316

317
318
319
        // *** Recommendations Table ***
        if (!empty($recommendations)) {
            $allowedsortfields = ['topic', 'exercise_name', 'difficulty', 'score'];
320
            $allowedsortdirs   = ['asc', 'desc'];
321

322
323
            $sortby  = $_POST['sortby']  ?? 'score';
            $sortdir = $_POST['sortdir'] ?? 'asc';
324

325
326
            if (!in_array($sortby, $allowedsortfields)) {
                $sortby = 'score';
Kurzenberger's avatar
Kurzenberger committed
327
            }
328
329
            if (!in_array($sortdir, $allowedsortdirs)) {
                $sortdir = 'asc';
Kurzenberger's avatar
Kurzenberger committed
330
            }
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
            usort($recommendations, function ($a, $b) use ($sortby, $sortdir) {
                $valuea = $a->{$sortby};
                $valueb = $b->{$sortby};

                if (is_numeric($valuea) && is_numeric($valueb)) {
                    $comparison = $valuea - $valueb;
                } else {
                    $comparison = strnatcasecmp($valuea, $valueb);
                }

                if ($comparison === 0) {
                    return 0;
                }
                if ($sortdir === 'asc') {
                    return ($comparison < 0) ? -1 : 1;
                } else {
                    return ($comparison < 0) ? 1 : -1;
                }
            });

            $html .= \html_writer::tag(
                'h3',
                get_string('recommendations', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );

            $generatesortableheader = function ($columnname, $displayname) use ($sortby, $sortdir) {
                $newsortdir = ($sortby === $columnname && $sortdir === 'asc') ? 'desc' : 'asc';
                $class = 'dtaTableHeader';
                if ($sortby === $columnname) {
                    $class .= ' sorted ' . $sortdir;
                }

                // Sort button.
                $button = \html_writer::empty_tag('input', [
366
367
                    'type'  => 'submit',
                    'name'  => 'sortbutton',
368
369
370
371
372
373
                    'value' => ($newsortdir === 'asc' ? '↑' : '↓'),
                    'class' => 'sort-button',
                ]);

                // Hidden inputs.
                $hiddeninputs = \html_writer::empty_tag('input', [
374
375
                    'type'  => 'hidden',
                    'name'  => 'sortby',
376
377
378
                    'value' => $columnname,
                ]);
                $hiddeninputs .= \html_writer::empty_tag('input', [
379
380
                    'type'  => 'hidden',
                    'name'  => 'sortdir',
381
382
383
384
385
                    'value' => $newsortdir,
                ]);

                $form = \html_writer::start_tag('form', [
                    'method' => 'post',
386
                    'style'  => 'display:inline',
387
388
389
390
391
392
393
394
                ]);
                $form .= $hiddeninputs;
                $form .= $displayname . ' ' . $button;
                $form .= \html_writer::end_tag('form');

                return \html_writer::tag('th', $form, ['class' => $class]);
            };

395
            // Build the recommendations table header.
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
            $tableheader = '';
            $tableheader .= $generatesortableheader(
                'topic',
                get_string('topic', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );
            $tableheader .= $generatesortableheader(
                '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 .= $generatesortableheader(
                'difficulty',
                get_string('difficulty', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );
            $tableheader .= $generatesortableheader(
                'score',
                get_string('score', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
            );

            $tableheader = \html_writer::tag('tr', $tableheader, ['class' => 'dtaTableHeaderRow']);
            $tableheader = \html_writer::tag('thead', $tableheader);

            // Table body for recommendations.
            $tablebody = '';
            foreach ($recommendations as $recommendation) {
                $row = '';
                $row .= \html_writer::tag('td', $recommendation->topic, $attributes);
                $row .= \html_writer::tag('td', $recommendation->exercise_name, $attributes);
                $row .= \html_writer::tag(
                    'td',
                    \html_writer::link($recommendation->url, $recommendation->url),
                    $attributes
                );
                $row .= \html_writer::tag('td', $recommendation->difficulty, $attributes);
                $row .= \html_writer::tag('td', $recommendation->score, $attributes);

                $tablebody .= \html_writer::tag('tr', $row, $tablerowattributes);
437
            }
438
            $tablebody = \html_writer::tag('tbody', $tablebody);
439

440
            $html .= \html_writer::tag('table', $tableheader . $tablebody, ['class' => 'dtaTable']);
Kurzenberger's avatar
Kurzenberger committed
441

442
            // Spacing after recommendations.
443
            $html .= \html_writer::empty_tag('div', ['class' => 'dtaSpacer']);
Kurzenberger's avatar
Kurzenberger committed
444
        }
Kurzenberger's avatar
Kurzenberger committed
445

446
447
        // *** Competency Assessment Table ***
        $body = '';
448
        $tmp  = '';
449
450
451
452
453
454
455
456
457
        $tmp .= \html_writer::tag(
            'th',
            get_string('competencies', self::ASSIGNSUBMISSION_DTA_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);

458
        $showncompetencies   = explode(';', $summary->successfultestcompetencies);
459
460
461
        $overallcompetencies = explode(';', $summary->overalltestcompetencies);

        for ($index = 0, $size = count($overallcompetencies); $index < $size; $index++) {
462
            $comp  = $overallcompetencies[$index];
463
            $shown = $showncompetencies[$index];
464
465

            // If the competency was actually assessed, add a row in the table.
466
            if ($comp !== '0') {
467
468
469
470
471
472
473
474
475
                $compval  = floatval($comp);
                $shownval = floatval($shown);

                // Guard division by zero:
                $pct = 0;
                if ($compval > 0) {
                    $pct = (100.0 * $shownval / $compval);
                }

476
477
478
479
480
481
482
483
484
                $resultrowattributes = $tablerowattributes;
                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('comp' . $index, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $resultrowattributes
                );
                $tmp .= \html_writer::tag(
                    'td',
485
                    round($pct, 2) . '% (' . $shown . ' / ' . $comp . ')',
486
487
488
489
490
491
492
493
494
                    $resultrowattributes
                );
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('comp_expl' . $index, self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $resultrowattributes
                );
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
            }
Kurzenberger's avatar
Kurzenberger committed
495
        }
496
497
        $body   = \html_writer::tag('tbody', $body);
        $html  .= \html_writer::tag('table', $header . $body, ['class' => 'dtaTable']);
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512

        // Add empty div for spacing.
        $html .= \html_writer::empty_tag('div', ['class' => 'dtaSpacer']);

        // *** Details Table ***
        $tmp = '';
        $tmp .= \html_writer::tag(
            'th',
            get_string('details', self::ASSIGNSUBMISSION_DTA_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);

513
        $body      = '';
514
515
516
517
518
519
        $spacerrow = null;
        foreach ($summary->results as $r) {
            // Add spacer first if not null.
            if (!is_null($spacerrow)) {
                $body .= $spacerrow;
            }
Kurzenberger's avatar
Kurzenberger committed
520

521
            $resultrowattributes = $tablerowattributes;
Kurzenberger's avatar
Kurzenberger committed
522

523
524
525
526
527
528
529
530
531
            // 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';
Kurzenberger's avatar
Kurzenberger committed
532
533
            }

534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
            $tmp = '';
            $tmp .= \html_writer::tag(
                'td',
                get_string('package_name', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag('td', $r->packagename, $attributes);
            $tmp .= \html_writer::tag(
                'td',
                get_string('unit_name', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag('td', $r->classname, $attributes);
            $tmp .= \html_writer::tag(
                'td',
                get_string('test_name', self::ASSIGNSUBMISSION_DTA_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::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                $attributes
            );
            $tmp .= \html_writer::tag(
                'td',
                dta_result::assignsubmission_dta_get_statename($r->state),
                $attributes
            );
            $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

568
            // If state != 1, show additional info.
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
            if ($r->state !== 1) {
                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('failure_type', self::ASSIGNSUBMISSION_DTA_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::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $attributes
                );
                $tmp .= \html_writer::tag('td', $r->failureReason, $attributes);
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);

                if (!is_null($r->lineNumber) && $r->lineNumber > 0) {
                    $tmp = '';
                    $tmp .= \html_writer::tag(
                        'td',
                        get_string('line_no', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                        $attributes
                    );
                    $tmp .= \html_writer::tag('td', $r->lineNumber, $attributes);
                    $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
                }

                if (!is_null($r->columnNumber) && $r->columnNumber > 0) {
                    $tmp = '';
                    $tmp .= \html_writer::tag(
                        'td',
                        get_string('col_no', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                        $attributes
                    );
                    $tmp .= \html_writer::tag('td', $r->columnNumber, $attributes);
                    $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
                }

                if (!is_null($r->position) && $r->position > 0) {
                    $tmp = '';
                    $tmp .= \html_writer::tag(
                        'td',
                        get_string('pos', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                        $attributes
                    );
                    $tmp .= \html_writer::tag('td', $r->position, $attributes);
                    $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
                }

                $tmp = '';
                $tmp .= \html_writer::tag(
                    'td',
                    get_string('stacktrace', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
                    $attributes
                );
                $tmp .= \html_writer::tag(
                    'td',
                    \html_writer::tag('details', $r->stacktrace, ['class' => 'dtaStacktraceDetails']),
                    $attributes
                );
                $body .= \html_writer::tag('tr', $tmp, $resultrowattributes);
Kurzenberger's avatar
Kurzenberger committed
633
634
            }

635
636
            if (is_null($spacerrow)) {
                $spacerrow = \html_writer::empty_tag('tr', ['class' => 'dtaTableSpacer']);
Kurzenberger's avatar
Kurzenberger committed
637
638
639
            }
        }

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

642
643
        // Wrap generated HTML into final div.
        $html = \html_writer::div($html, 'dtaSubmissionDetails');
Kurzenberger's avatar
Kurzenberger committed
644

645
646
        return $html;
    }
647
}