From 96feeaafb3ae5b3caa1cf3dedebb23f28794dd46 Mon Sep 17 00:00:00 2001
From: Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de>
Date: Mon, 27 May 2024 14:03:18 +0200
Subject: [PATCH] fix warnings on PHP 8, re #160

---
 controllers/config.php                        |  8 -----
 controllers/groups.php                        |  2 +-
 controllers/sheets.php                        | 13 ++++---
 exercises/Exercise.php                        |  2 +-
 exercises/cloze_exercise.php                  | 24 ++++++++-----
 exercises/lt_exercise.php                     | 18 +++++-----
 exercises/seq_exercise.php                    | 10 +++---
 exercises/tb_exercise.php                     | 34 +++++++++++--------
 lib/VipsAssignment.php                        | 11 +++---
 views/exercises/cloze_exercise/correct.php    |  4 +--
 views/exercises/cloze_exercise/print.php      |  2 +-
 views/exercises/cloze_exercise/xml.php        |  2 +-
 views/exercises/correct_exercise.php          |  2 +-
 views/exercises/lt_exercise/xml.php           |  2 +-
 views/exercises/sc_exercise/xml.php           |  2 +-
 views/exercises/seq_exercise/xml.php          |  2 +-
 views/exercises/tb_exercise/correct.php       | 22 ++++++------
 views/exercises/tb_exercise/solve.php         | 10 +++---
 views/exercises/tb_exercise/xml.php           |  4 +--
 views/sheets/copy_assignment_dialog.php       |  6 ++--
 views/sheets/ip_range_tooltip.php             |  2 +-
 views/sheets/show_exercise.php                |  2 +-
 views/solutions/assignments_list_student.php  |  2 +-
 .../student_assignment_solutions.php          |  2 +-
 24 files changed, 102 insertions(+), 86 deletions(-)

diff --git a/controllers/config.php b/controllers/config.php
index 833f72a..415fb97 100644
--- a/controllers/config.php
+++ b/controllers/config.php
@@ -76,14 +76,6 @@ class ConfigController extends StudipController
         }
 
         if ($ip_ranges) {
-            if ($config->VIPS_EXAM_ROOMS === null) {
-                $config->create('VIPS_EXAM_ROOMS', [
-                    'description' => 'Zentral verwaltete IP-Adressen für PC-Räume',
-                    'type' => 'array',
-                    'value' => '[]'
-                ]);
-            }
-
             ksort($ip_ranges);
             $config->store('VIPS_EXAM_ROOMS', $ip_ranges);
         }
diff --git a/controllers/groups.php b/controllers/groups.php
index 3253a64..b2fd99f 100644
--- a/controllers/groups.php
+++ b/controllers/groups.php
@@ -191,7 +191,7 @@ class GroupsController extends StudipController
 
         if (!$settings->VIPS_GROUP_SELFASSIGN) {
             PageLayout::postError(_vips('Selbsteintrag ist nicht aktiviert.'));
-        } else if ($current_group->id == $group_id) {
+        } else if ($current_group && $current_group->id == $group_id) {
             PageLayout::postError(_vips('Sie befinden sich schon in dieser Gruppe.'));
         } else if ($current_group) {
             PageLayout::postError(_vips('Sie befinden sich schon in einer anderen Gruppe.'));
diff --git a/controllers/sheets.php b/controllers/sheets.php
index a9bb34e..d915fca 100644
--- a/controllers/sheets.php
+++ b/controllers/sheets.php
@@ -119,6 +119,7 @@ class SheetsController extends StudipController
         if ($assignment->checkAccess($solver_id) || $assignment->checkEditPermission()) {
             if ($assignment->isResetAllowed() || $assignment->type === 'exam') {
                 $assignment->deleteSolution($solver_id, $exercise_id);
+                $undo_link = '';
 
                 if ($assignment->type === 'exam' && !$assignment->isSelfAssessment()) {
                     $undo_link = sprintf(' <a href="%s">%s</a>',
@@ -209,7 +210,7 @@ class SheetsController extends StudipController
 
         vips_require_view_permission($assignment);
 
-        if ($assignment->checkAccess($solver_id)) {
+        if ($assignment->checkAccess($GLOBALS['user']->id)) {
             if ($assignment->finishAssignmentAttempt($GLOBALS['user']->id)) {
                 PageLayout::postSuccess(_vips('Das Aufgabenblatt wurde abgeschlossen, eine weitere Bearbeitung ist nicht mehr möglich.'));
             } else {
@@ -507,7 +508,7 @@ class SheetsController extends StudipController
         foreach ($assignments as $assignment) {
             if ($assignment->isRunning() && $assignment->isVisible($GLOBALS['user']->id)) {
                 if ($assignment->checkIPAccess($ip_address)) {
-                    if ($assignment->block->group_id) {
+                    if (isset($assignment->block->group_id)) {
                         $this->blocks['']['assignments'][] = $assignment;
                     } else {
                         $this->blocks[$assignment->block_id]['assignments'][] = $assignment;
@@ -518,7 +519,7 @@ class SheetsController extends StudipController
 
         // delete empty blocks
         foreach ($blocks as $block) {
-            if (!$this->blocks[$block->id]['assignments']) {
+            if (empty($this->blocks[$block->id]['assignments'])) {
                 unset($this->blocks[$block->id]);
             }
         }
@@ -1469,7 +1470,7 @@ class SheetsController extends StudipController
             'type'      => $assignment_type,
             'start'     => $start,
             'end'       => $end,
-            'block_id'  => $block->id
+            'block_id'  => $block ? $block->id : null
         ]);
 
         // update options array
@@ -1739,6 +1740,10 @@ class SheetsController extends StudipController
         $this->exercise          = $exercise;
         $this->exercise_position = $exercise_ref->position;
         $this->max_points        = $exercise_ref->points;
+        $this->solution          = new VipsSolution();
+        $this->show_solution     = false;
+        $this->print_correction  = false;
+        $this->user_id           = null;
 
         $this->render_template('exercises/print_exercise');
     }
diff --git a/exercises/Exercise.php b/exercises/Exercise.php
index b7e82c6..6d85b3e 100644
--- a/exercises/Exercise.php
+++ b/exercises/Exercise.php
@@ -341,7 +341,7 @@ abstract class Exercise extends SimpleORMap
         $result = [];
 
         for ($i = 0; $i < $this->itemCount(); ++$i) {
-            $result[] = trim($request['answer'][$i]);
+            $result[] = isset($request['answer'][$i]) ? trim($request['answer'][$i]) : '';
         }
 
         return $result;
diff --git a/exercises/cloze_exercise.php b/exercises/cloze_exercise.php
index 8499b8a..213a381 100644
--- a/exercises/cloze_exercise.php
+++ b/exercises/cloze_exercise.php
@@ -112,6 +112,7 @@ class cloze_exercise extends Exercise
     public function initXML($exercise)
     {
         parent::initXML($exercise);
+        $select = null;
 
         foreach ($exercise->items->item->description->children() as $name => $elem) {
             if ($name == 'text') {
@@ -149,17 +150,21 @@ class cloze_exercise extends Exercise
                 $this->task['layout'] = 'drag';
         }
 
-        if ($exercise->items->item->{'submission-hints'}->input['width']) {
-            $this->task['input_width'] = (int) $exercise->items->item->{'submission-hints'}->input['width'];
+        if ($exercise->items->item->{'submission-hints'}) {
+            if ($exercise->items->item->{'submission-hints'}->input['width']) {
+                $this->task['input_width'] = (int) $exercise->items->item->{'submission-hints'}->input['width'];
+            }
         }
 
-        switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
-            case 'ignorecase':
-                $this->task['compare'] = 'ignorecase';
-                break;
-            case 'numeric':
-                $this->task['compare'] = 'numeric';
-                $this->task['epsilon'] = (float) $exercise->items->item->{'evaluation-hints'}->{'input-data'};
+        if ($exercise->items->item->{'evaluation-hints'}) {
+            switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
+                case 'ignorecase':
+                    $this->task['compare'] = 'ignorecase';
+                    break;
+                case 'numeric':
+                    $this->task['compare'] = 'numeric';
+                    $this->task['epsilon'] = (float) $exercise->items->item->{'evaluation-hints'}->{'input-data'};
+            }
         }
     }
 
@@ -408,6 +413,7 @@ class cloze_exercise extends Exercise
 
         // $question_array contains text elements and blanks (surrounded by [[ and ]]).
         $parts = preg_split('/(\[\[(?:".*?"|.)*?\]\])/s', $question, -1, PREG_SPLIT_DELIM_CAPTURE);
+        $select = null;
 
         foreach ($parts as $part) {
             if (preg_match('/^\[\[(.*)\]\]$/s', $part, $matches)) {
diff --git a/exercises/lt_exercise.php b/exercises/lt_exercise.php
index 746f272..c658134 100644
--- a/exercises/lt_exercise.php
+++ b/exercises/lt_exercise.php
@@ -201,14 +201,16 @@ class lt_exercise extends Exercise
 
         $this->options['lang'] = (string) $exercise['lang'];
 
-        switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
-            case 'levenshtein':
-            case 'soundex':
-                $this->task['compare'] = (string) $exercise->items->item->{'evaluation-hints'}->similarity['type'];
-                break;
-            case 'numeric':
-                $this->task['compare'] = 'numeric';
-                $this->task['epsilon'] = (float) $exercise->items->item->{'evaluation-hints'}->{'input-data'};
+        if ($exercise->items->item->{'evaluation-hints'}) {
+            switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
+                case 'levenshtein':
+                case 'soundex':
+                    $this->task['compare'] = (string) $exercise->items->item->{'evaluation-hints'}->similarity['type'];
+                    break;
+                case 'numeric':
+                    $this->task['compare'] = 'numeric';
+                    $this->task['epsilon'] = (float) $exercise->items->item->{'evaluation-hints'}->{'input-data'};
+            }
         }
     }
 
diff --git a/exercises/seq_exercise.php b/exercises/seq_exercise.php
index c4c478f..d253c91 100644
--- a/exercises/seq_exercise.php
+++ b/exercises/seq_exercise.php
@@ -159,10 +159,12 @@ class seq_exercise extends Exercise
             ];
         }
 
-        switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
-            case 'position':
-            case 'sequence':
-                $this->task['compare'] = (string) $exercise->items->item->{'evaluation-hints'}->similarity['type'];
+        if ($exercise->items->item->{'evaluation-hints'}) {
+            switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
+                case 'position':
+                case 'sequence':
+                    $this->task['compare'] = (string) $exercise->items->item->{'evaluation-hints'}->similarity['type'];
+            }
         }
 
         $this->createIds();
diff --git a/exercises/tb_exercise.php b/exercises/tb_exercise.php
index 67a22c8..27d1678 100644
--- a/exercises/tb_exercise.php
+++ b/exercises/tb_exercise.php
@@ -337,24 +337,30 @@ class tb_exercise extends Exercise
 
         $this->options['lang'] = (string) $exercise['lang'];
 
-        switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
-            case 'levenshtein':
-                $this->task['compare'] = 'levenshtein';
+        if ($exercise->items->item->{'evaluation-hints'}) {
+            switch ($exercise->items->item->{'evaluation-hints'}->similarity['type']) {
+                case 'levenshtein':
+                    $this->task['compare'] = 'levenshtein';
+            }
         }
 
-        switch ($exercise->items->item->{'submission-hints'}->input['type']) {
-            case 'markup':
-                $this->task['layout'] = 'markup';
-                break;
-            case 'code':
-                $this->task['layout'] = 'code';
-                break;
-            case 'none':
-                $this->task['layout'] = 'none';
+        if ($exercise->items->item->{'submission-hints'}->input) {
+            switch ($exercise->items->item->{'submission-hints'}->input['type']) {
+                case 'markup':
+                    $this->task['layout'] = 'markup';
+                    break;
+                case 'code':
+                    $this->task['layout'] = 'code';
+                    break;
+                case 'none':
+                    $this->task['layout'] = 'none';
+            }
         }
 
-        if ($exercise->items->item->{'submission-hints'}->attachments['upload'] == 'true') {
-            $this->options['file_upload'] = 1;
+        if ($exercise->items->item->{'submission-hints'}->attachments) {
+            if ($exercise->items->item->{'submission-hints'}->attachments['upload'] == 'true') {
+                $this->options['file_upload'] = 1;
+            }
         }
     }
 }
diff --git a/lib/VipsAssignment.php b/lib/VipsAssignment.php
index 834d01d..73451bf 100644
--- a/lib/VipsAssignment.php
+++ b/lib/VipsAssignment.php
@@ -477,6 +477,8 @@ class VipsAssignment extends SimpleORMap
      */
     public function exportXML()
     {
+        $files = [];
+
         foreach ($this->test->exercise_refs as $exercise_ref) {
             $exercise = $exercise_ref->exercise;
             $exercise->includeFilesForExport();
@@ -543,8 +545,10 @@ class VipsAssignment extends SimpleORMap
     {
         if (isset($access_code)) {
             $_SESSION['vips_access_' . $this->id] = $access_code;
-        } else {
+        } else if (isset($_SESSION['vips_access_' . $this->id])) {
             $access_code = $_SESSION['vips_access_' . $this->id];
+        } else {
+            $access_code = null;
         }
 
         return in_array($this->options['access_code'], [null, $access_code], true);
@@ -830,7 +834,6 @@ class VipsAssignment extends SimpleORMap
         // always set corrected to true for selftest exercises
         $selftest   = $this->type === 'selftest';
         $evaluation = $exercise->evaluate($solution);
-        $feedback   = $exercise->options['feedback'];
         $eval_safe  = $selftest ? $evaluation['safe'] !== null : $evaluation['safe'];
 
         $reached_points = round_to_half_point($evaluation['percent'] * $max_points);
@@ -841,8 +844,8 @@ class VipsAssignment extends SimpleORMap
         $solution->points = $reached_points;
         $solution->correction_time = date('Y-m-d H:i:s');
 
-        if ($selftest && $evaluation['percent'] != 1 && $feedback != '') {
-            $solution->corrector_comment = $feedback;
+        if ($selftest && $evaluation['percent'] != 1 && isset($exercise->options['feedback'])) {
+            $solution->corrector_comment = $exercise->options['feedback'];
         }
     }
 
diff --git a/views/exercises/cloze_exercise/correct.php b/views/exercises/cloze_exercise/correct.php
index 1f283cd..41eb395 100644
--- a/views/exercises/cloze_exercise/correct.php
+++ b/views/exercises/cloze_exercise/correct.php
@@ -12,7 +12,7 @@
                  --><span class="fuzzy_item math-tex"><?= htmlReady($response[$blank]) ?><!--
                      --><?= Icon::create('decline', 'status-yellow', ['class' => 'correction_inline', 'title' => _vips('fast richtig')]) ?><!--
                  --></span><!--
-                <? elseif (!$edit_solution || $results[$blank]['safe']): ?>
+                <? elseif (empty($edit_solution) || $results[$blank]['safe']): ?>
                  --><span class="wrong_item math-tex"><?= htmlReady($response[$blank]) ?><!--
                      --><?= Icon::create('decline', 'status-red', ['class' => 'correction_inline', 'title' => _vips('falsch')]) ?><!--
                  --></span><!--
@@ -22,7 +22,7 @@
                  --></span><!--
                 <? endif ?>
             <? endif ?>
-            <? if ($show_solution && $results[$blank]['points'] < 1 && $exercise->correctAnswers($blank)): ?>
+            <? if ($show_solution && (empty($results) || $results[$blank]['points'] < 1) && $exercise->correctAnswers($blank)): ?>
              --><span class="correct_item math-tex"><?= htmlReady(implode(' | ', $exercise->correctAnswers($blank))) ?></span><!--
             <? endif ?>
         <? endif ?>
diff --git a/views/exercises/cloze_exercise/print.php b/views/exercises/cloze_exercise/print.php
index b50948d..321ad04 100644
--- a/views/exercises/cloze_exercise/print.php
+++ b/views/exercises/cloze_exercise/print.php
@@ -23,7 +23,7 @@
             <? else: ?>
              --><?= str_repeat('_', $exercise->getInputWidth($blank)) ?><!--
             <? endif ?>
-            <? if ($show_solution && $results[$blank]['points'] < 1 && $exercise->correctAnswers($blank)): ?>
+            <? if ($show_solution && (empty($results) || $results[$blank]['points'] < 1) && $exercise->correctAnswers($blank)): ?>
              --><span class="correct_item math-tex"><?= htmlReady(implode(' | ', $exercise->correctAnswers($blank))) ?></span><!--
             <? endif ?>
         <? endif ?>
diff --git a/views/exercises/cloze_exercise/xml.php b/views/exercises/cloze_exercise/xml.php
index e0bb838..c1f8fcc 100644
--- a/views/exercises/cloze_exercise/xml.php
+++ b/views/exercises/cloze_exercise/xml.php
@@ -31,7 +31,7 @@
                     <input type="text" width="<?= (int) $exercise->task['input_width'] ?>"/>
                 </submission-hints>
             <? endif ?>
-            <? if ($exercise->task['compare']): ?>
+            <? if (!empty($exercise->task['compare'])): ?>
                 <evaluation-hints>
                     <similarity type="<?= vips_xml_encode($exercise->task['compare']) ?>"/>
                     <? if ($exercise->task['compare'] === 'numeric'): ?>
diff --git a/views/exercises/correct_exercise.php b/views/exercises/correct_exercise.php
index 70a2d6c..9671d46 100644
--- a/views/exercises/correct_exercise.php
+++ b/views/exercises/correct_exercise.php
@@ -20,7 +20,7 @@
 
     <?= $this->render_partial($exercise->getCorrectionTemplate($solution)) ?>
 
-    <? if ($exercise->options['comment'] && $solution->student_comment != '') : ?>
+    <? if (!empty($exercise->options['comment']) && $solution->student_comment != '') : ?>
         <div class="label-text">
             <?= _vips('Bemerkungen zur Lösung') ?>
         </div>
diff --git a/views/exercises/lt_exercise/xml.php b/views/exercises/lt_exercise/xml.php
index cb59d65..cb26b1e 100644
--- a/views/exercises/lt_exercise/xml.php
+++ b/views/exercises/lt_exercise/xml.php
@@ -21,7 +21,7 @@
                     </answer>
                 <? endforeach ?>
             </answers>
-            <? if ($exercise->task['compare']): ?>
+            <? if (!empty($exercise->task['compare'])): ?>
                 <evaluation-hints>
                     <similarity type="<?= vips_xml_encode($exercise->task['compare']) ?>"/>
                     <? if ($exercise->task['compare'] === 'numeric'): ?>
diff --git a/views/exercises/sc_exercise/xml.php b/views/exercises/sc_exercise/xml.php
index cefd537..a06434b 100644
--- a/views/exercises/sc_exercise/xml.php
+++ b/views/exercises/sc_exercise/xml.php
@@ -14,7 +14,7 @@
     <items>
         <? foreach ($exercise->task as $group => $task): ?>
             <item type="choice-single">
-                <? if ($task['description'] != ''): ?>
+                <? if (isset($task['description']) && $task['description'] != ''): ?>
                     <description>
                         <text><?= vips_xml_encode($task['description']) ?></text>
                     </description>
diff --git a/views/exercises/seq_exercise/xml.php b/views/exercises/seq_exercise/xml.php
index 15d789e..d3f689f 100644
--- a/views/exercises/seq_exercise/xml.php
+++ b/views/exercises/seq_exercise/xml.php
@@ -20,7 +20,7 @@
                     </answer>
                 <? endforeach ?>
             </answers>
-            <? if ($exercise->task['compare']): ?>
+            <? if (!empty($exercise->task['compare'])): ?>
                 <evaluation-hints>
                     <similarity type="<?= vips_xml_encode($exercise->task['compare']) ?>"/>
                 </evaluation-hints>
diff --git a/views/exercises/tb_exercise/correct.php b/views/exercises/tb_exercise/correct.php
index 5030cf3..644c264 100644
--- a/views/exercises/tb_exercise/correct.php
+++ b/views/exercises/tb_exercise/correct.php
@@ -1,4 +1,4 @@
-<? if ($exercise->task['layout'] !== 'none' && $response[0] != ''): ?>
+<? if ($exercise->getLayout() !== 'none' && $response[0] != ''): ?>
     <div class="vips_tabs <?= $solution->commented_solution ? '' : 'edit-hidden' ?>">
         <ul>
             <li class="edit-tab">
@@ -22,9 +22,9 @@
 
         <div id="commented-<?= $exercise->id ?>">
             <? if ($edit_solution): ?>
-                <? if ($exercise->task['layout'] === 'markup'): ?>
+                <? if ($exercise->getLayout() === 'markup'): ?>
                     <? $answer = $response[0] ?>
-                <? elseif ($exercise->task['layout'] === 'code'): ?>
+                <? elseif ($exercise->getLayout() === 'code'): ?>
                     <? $answer = "[pre][nop]\n{$response[0]}\n[/nop][/pre]" ?>
                 <? elseif (Studip\Markup::editorEnabled()): ?>
                     <? $answer = Studip\Markup::markAsHtml(htmlReady($response[0], true, true)) ?>
@@ -56,11 +56,11 @@
 
         <div id="solution-<?= $exercise->id ?>">
             <div class="vips_output">
-                <? if (empty($exercise->task['layout'])): ?>
+                <? if ($exercise->getLayout() === 'text'): ?>
                     <?= htmlReady($response[0], true, true) ?>
-                <? elseif ($exercise->task['layout'] === 'markup'): ?>
+                <? elseif ($exercise->getLayout() === 'markup'): ?>
                     <?= formatReady($response[0]) ?>
-                <? elseif ($exercise->task['layout'] === 'code'): ?>
+                <? elseif ($exercise->getLayout() === 'code'): ?>
                     <pre><?= htmlReady($response[0]) ?></pre>
                     <input type="hidden" class="download" value="<?= htmlReady($response[0]) ?>">
                 <? endif ?>
@@ -69,7 +69,7 @@
             <? if ($edit_solution): ?>
                 <?= Studip\Button::create(_vips('Lösung bearbeiten'), 'edit_solution', ['class' => 'edit_solution']) ?>
 
-                <? if ($exercise->task['layout'] === 'code'): ?>
+                <? if ($exercise->getLayout() === 'code'): ?>
                     <a hidden download="<?= htmlReady($exercise->title) ?>.txt" target="_blank"></a>
                     <?= Studip\Button::create(_vips('Lösung herunterladen'), 'download', ['class' => 'vips_file_download']) ?>
                 <? endif ?>
@@ -79,18 +79,18 @@
         <? if ($exercise->task['template'] != ''): ?>
             <div id="default-<?= $exercise->id ?>">
                 <div class="vips_output">
-                    <? if (empty($exercise->task['layout'])): ?>
+                    <? if ($exercise->getLayout() === 'text'): ?>
                         <?= htmlReady($exercise->task['template'], true, true) ?>
-                    <? elseif ($exercise->task['layout'] === 'markup'): ?>
+                    <? elseif ($exercise->getLayout() === 'markup'): ?>
                         <?= formatReady($exercise->task['template']) ?>
-                    <? elseif ($exercise->task['layout'] === 'code'): ?>
+                    <? elseif ($exercise->getLayout() === 'code'): ?>
                         <pre><?= htmlReady($exercise->task['template']) ?></pre>
                     <? endif ?>
                 </div>
             </div>
         <? endif ?>
     </div>
-<? elseif ($exercise->task['layout'] !== 'none'): ?>
+<? elseif ($exercise->getLayout() !== 'none'): ?>
     <div class="description" style="font-style: italic;">
         <?= _vips('Es wurde kein Text als Lösung abgegeben.') ?>
     </div>
diff --git a/views/exercises/tb_exercise/solve.php b/views/exercises/tb_exercise/solve.php
index b100356..bdb807d 100644
--- a/views/exercises/tb_exercise/solve.php
+++ b/views/exercises/tb_exercise/solve.php
@@ -1,4 +1,4 @@
-<? if ($exercise->task['layout'] !== 'none'): ?>
+<? if ($exercise->getLayout() !== 'none'): ?>
     <? if ($exercise->task['template'] != ''): ?>
         <div class="vips_tabs">
             <ul>
@@ -21,9 +21,9 @@
             <? /* student answer */ ?>
             <div id="solution-<?= $exercise->id ?>">
                 <? $answer = isset($response) ? $response[0] : $exercise->task['template'] ?>
-                <? if ($exercise->task['layout'] === 'markup'): ?>
+                <? if ($exercise->getLayout() === 'markup'): ?>
                     <textarea name="answer[0]" class="character_input size-l wysiwyg" data-editor="removePlugins=studip-quote,studip-upload,ImageUpload" rows="20"><?= wysiwygReady($answer) ?></textarea>
-                <? elseif ($exercise->task['layout'] === 'code'): ?>
+                <? elseif ($exercise->getLayout() === 'code'): ?>
                     <textarea name="answer[0]" class="character_input size-l monospace download" rows="20"><?= htmlReady($answer) ?></textarea>
 
                     <a hidden download="<?= htmlReady($exercise->title) ?>.txt" target="_blank"></a>
@@ -40,9 +40,9 @@
     <? else: ?>
             <? /* default answer */ ?>
             <div id="default-<?= $exercise->id ?>">
-                <? if ($exercise->task['layout'] === 'markup'): ?>
+                <? if ($exercise->getLayout() === 'markup'): ?>
                     <textarea readonly class="size-l wysiwyg" rows="20"><?= wysiwygReady($exercise->task['template']) ?></textarea>
-                <? elseif ($exercise->task['layout'] === 'code'): ?>
+                <? elseif ($exercise->getLayout() === 'code'): ?>
                     <textarea readonly class="size-l monospace" rows="20"><?= htmlReady($exercise->task['template']) ?></textarea>
                 <? else: ?>
                     <textarea readonly class="size-l" rows="20"><?= htmlReady($exercise->task['template']) ?></textarea>
diff --git a/views/exercises/tb_exercise/xml.php b/views/exercises/tb_exercise/xml.php
index 56d1b4f..08a5457 100644
--- a/views/exercises/tb_exercise/xml.php
+++ b/views/exercises/tb_exercise/xml.php
@@ -27,14 +27,14 @@
                 <? endforeach ?>
             </answers>
             <submission-hints>
-                <? if ($exercise->task['layout']): ?>
+                <? if (!empty($exercise->task['layout'])): ?>
                     <input type="<?= vips_xml_encode($exercise->task['layout']) ?>"/>
                 <? endif ?>
                 <? if ($exercise->options['file_upload']): ?>
                     <attachments upload="true"/>
                 <? endif ?>
             </submission-hints>
-            <? if ($exercise->task['compare']): ?>
+            <? if (!empty($exercise->task['compare'])): ?>
                 <evaluation-hints>
                     <similarity type="<?= vips_xml_encode($exercise->task['compare']) ?>"/>
                 </evaluation-hints>
diff --git a/views/sheets/copy_assignment_dialog.php b/views/sheets/copy_assignment_dialog.php
index d3d77f0..3d522e0 100644
--- a/views/sheets/copy_assignment_dialog.php
+++ b/views/sheets/copy_assignment_dialog.php
@@ -38,19 +38,19 @@
                     <th style="width: 45%;" class="<?= vips_sort_class($sort === 'test_title', $desc) ?>">
                         <input type="checkbox" data-proxyfor=".batch_select" data-activates=".batch_action" title="<?= _vips('Alle Aufgaben auswählen') ?>">
                         <a href="<?= $controller->link_for('sheets/copy_assignment_dialog',
-                            compact('assignment_id', 'search_filter') + ['sort' => 'test_title', 'desc' => $sort === 'test_title' && !$desc]) ?>" data-dialog="size=1200x800">
+                            compact('search_filter') + ['sort' => 'test_title', 'desc' => $sort === 'test_title' && !$desc]) ?>" data-dialog="size=1200x800">
                             <?= _vips('Aufgabenblatt') ?>
                         </a>
                     </th>
                     <th style="width: 40%;" class="<?= vips_sort_class($sort === 'course_name', $desc) ?>">
                         <a href="<?= $controller->link_for('sheets/copy_assignment_dialog',
-                            compact('assignment_id', 'search_filter') + ['sort' => 'course_name', 'desc' => $sort === 'course_name' && !$desc]) ?>" data-dialog="size=1200x800">
+                            compact('search_filter') + ['sort' => 'course_name', 'desc' => $sort === 'course_name' && !$desc]) ?>" data-dialog="size=1200x800">
                             <?= _vips('Veranstaltung') ?>
                         </a>
                     </th>
                     <th style="width: 15%;" class="<?= vips_sort_class($sort === 'start_time', $desc) ?>">
                         <a href="<?= $controller->link_for('sheets/copy_assignment_dialog',
-                            compact('assignment_id', 'search_filter') + ['sort' => 'start_time', 'desc' => $sort === 'start_time' && !$desc]) ?>" data-dialog="size=1200x800">
+                            compact('search_filter') + ['sort' => 'start_time', 'desc' => $sort === 'start_time' && !$desc]) ?>" data-dialog="size=1200x800">
                             <?= _vips('Semester') ?>
                         </a>
                     </th>
diff --git a/views/sheets/ip_range_tooltip.php b/views/sheets/ip_range_tooltip.php
index 5aa8ebb..0bd9ff7 100644
--- a/views/sheets/ip_range_tooltip.php
+++ b/views/sheets/ip_range_tooltip.php
@@ -13,7 +13,7 @@
     <dd>
         <?= _vips('gibt alle IPs aus dem Bereich 131.173.73 bis 131.173.75 frei.') ?>
     </dd>
-    <? if ($exam_rooms): ?>
+    <? if (!empty($exam_rooms)): ?>
         <dt>#94/E01</dt>
         <dd>
             <?= _vips('gibt alle IPs in diesem Raum frei.') ?>
diff --git a/views/sheets/show_exercise.php b/views/sheets/show_exercise.php
index 1709d76..3ee5fc9 100644
--- a/views/sheets/show_exercise.php
+++ b/views/sheets/show_exercise.php
@@ -99,7 +99,7 @@
             <? if (isset($exercise->options['comment']) && $exercise->options['comment']) : ?>
                 <label>
                     <?= _vips('Bemerkungen zur Lösung (optional)') ?>
-                    <textarea name="student_comment"><?= htmlReady($solution->student_comment) ?></textarea>
+                    <textarea name="student_comment"><?= $solution ? htmlReady($solution->student_comment) : '' ?></textarea>
                 </label>
             <? endif ?>
         </fieldset>
diff --git a/views/solutions/assignments_list_student.php b/views/solutions/assignments_list_student.php
index b3d8289..6ec6526 100644
--- a/views/solutions/assignments_list_student.php
+++ b/views/solutions/assignments_list_student.php
@@ -35,7 +35,7 @@
     </thead>
 
     <? foreach ($blocks as $block) :?>
-        <? if ($block_assignments[$block->id]): ?>
+        <? if (isset($block_assignments[$block->id])): ?>
             <tbody>
                 <? if (count($block_assignments) > 1): ?>
                     <tr class="header-row">
diff --git a/views/solutions/student_assignment_solutions.php b/views/solutions/student_assignment_solutions.php
index 6d7e16c..047ad3a 100644
--- a/views/solutions/student_assignment_solutions.php
+++ b/views/solutions/student_assignment_solutions.php
@@ -63,7 +63,7 @@
                     <? endif ?>
                 </td>
                 <td style="text-align: center;">
-                    <?= sprintf('%g', $solution->points) ?>
+                    <?= sprintf('%g', $solution ? $solution->points : 0) ?>
                 </td>
                 <td style="text-align: center;">
                     <?= sprintf('%g', $exercise_ref->points) ?>
-- 
GitLab