1

I'm trying to set up a simple quiz module. I'm using a Matrix field called quiz, with a plain text question field and an answers table field. In the table field, there's two columns, plain text answer and checkbox correct. See image:

enter image description here

The idea being that there's only one correct answer.

EDIT: Using James' amazing code as a base, I've tried to get that into PHP and it's coming along ok. Still working on it...

$userAnswers = Craft::$app->getRequest()->getBodyParam('answers');
$user = Craft::$app->getUser()->getIdentity();

$allQuestions = $quiz->quizMatrix->all(); $numberOfQuestions = count($allQuestions);

$correctAnswersByQuestion = [];

foreach ($allQuestions as $question) { $correctAnswer = array_map(function($answer) { return (bool)$answer['correct']; }, $question['answers']); $correctAnswersByQuestion[] = $correctAnswer; }

$totalCorrect = 0;

foreach ($userAnswers as $key => $value) { $questionIndex = $key; $answerIndex = $value; $isCorrect = $correctAnswersByQuestion[$questionIndex][$answerIndex]; echo "<p>Question " . ($questionIndex+1) . " was " . ($isCorrect ? 'correct' : 'incorrect') . "</p>"; $totalCorrect += $isCorrect ? 1 : 0; }

$score = ($totalCorrect / $numberOfQuestions) * 100; $data = 'Your score is '.$score.'%'; $response = Craft::$app->getResponse(); $response->data = $data; return $response;

supazu
  • 576
  • 4
  • 12

1 Answers1

3

Have you considered doing this in Twig instead? If your needs are complex, then a custom module in PHP might be best, but since you described it as a "simple" quiz, I'd probably go with Twig. Here's a fully functional example:

{% set allQuestions = entry.quiz.all() %}
<form method="post">
    {% for question in allQuestions %}
        <h3>{{ question.question }}</h3>
        {% for answer in question.answers %}
            <label for="answer-{{ question.id }}-{{ loop.index0 }}">
                <input type="radio" name="answers[{{ loop.parent.loop.index0 }}]" value="{{ loop.index0 }}" id="answer-{{ question.id }}-{{ loop.index0 }}">
                {{ answer.answer }}
            </label>
        {% endfor %}
    {% endfor %}
    <button>Submit</button>
</form>

{% if craft.app.request.param('answers') %} {% set correctAnswersByQuestion = [] %} {% for question in allQuestions %} {% set correctAnswer = question.answers|map(answer => answer.correct ? true : false) %} {% set correctAnswersByQuestion = correctAnswersByQuestion|push(correctAnswer) %} {% endfor %}

&lt;h2&gt;Results:&lt;/h2&gt;
{% set totalCorrect = 0 %}
{% for questionIndex, answerIndex in craft.app.request.param('answers') %}
    &lt;p&gt;Question {{ questionIndex+1 }} was {{ correctAnswersByQuestion[questionIndex][answerIndex] ? 'correct' : 'incorrect' }}&lt;/p&gt;
    {% set totalCorrect = correctAnswersByQuestion[questionIndex][answerIndex] ? totalCorrect+1 : totalCorrect %}
{% endfor %}

&lt;h2&gt;Score:&lt;/h2&gt;
{{ totalCorrect/allQuestions|length * 100 }}%

{% endif %}

James Smith
  • 5,154
  • 14
  • 15
  • Thanks! I hadn't really considered it, but that's an amazing start. I did say simple, but I would like the quiz to evolve in the future; for example, saving results to a User's profile, and possibly text input fields rather than just radio inputs. – supazu Feb 23 '23 at 00:15