You are here

QuizController.php in Quiz 8.6

File

src/Controller/QuizController.php
View source
<?php

namespace Drupal\quiz\Controller;

use Drupal;
use Drupal\Core\Access\AccessResultReasonInterface;
use Drupal\Core\Entity\Controller\EntityController;
use Drupal\quiz\Entity\Quiz;
use Drupal\quiz\Entity\QuizResult;
use Drupal\views\Views;
class QuizController extends EntityController {

  /**
   * Take the quiz.
   * @return type
   */
  function take(Quiz $quiz) {
    $page = [];
    $page['#cache'] = [
      'max-age' => 0,
    ];

    /* @var $result AccessResultReasonInterface */
    $result = $quiz
      ->access('take', NULL, TRUE);
    $message = '';
    if (is_subclass_of($result, AccessResultReasonInterface::class)) {
      $message = $result
        ->getReason();
    }
    $success = !$result
      ->isForbidden();
    if (!$success) {

      // Not allowed.
      $page['body']['#markup'] = $message;
      return $page;
    }
    elseif ($message) {

      // Allowed, but we have a message.
      \Drupal::messenger()
        ->addMessage($message);
    }
    if ($quiz_result = $this
      ->resume($quiz)) {

      // Resuming attempt.
      if (!empty($quiz_result->resume)) {

        // Show a message if this was reloaded from the database and not just
        // from the session.
        \Drupal::messenger()
          ->addStatus(t('Resuming a previous @quiz in-progress.', array(
          '@quiz' => _quiz_get_quiz_name(),
        )));
      }
      return $this
        ->redirect('quiz.question.take', [
        'quiz' => $quiz
          ->id(),
        'question_number' => $_SESSION['quiz'][$quiz
          ->id()]['current'],
      ]);
    }
    else {

      // Create new result.
      if ($success) {

        // Test a build of questions.
        $questions = $quiz
          ->buildLayout();
        if (empty($questions)) {
          \Drupal::messenger()
            ->addError(t('Not enough questions were found. Please add more questions before trying to take this @quiz.', array(
            '@quiz' => _quiz_get_quiz_name(),
          )));
          return $this
            ->redirect('entity.quiz.canonical', [
            'quiz' => $quiz
              ->id(),
          ]);
        }

        // Creat a new Quiz result.
        $quiz_result = QuizResult::create(array(
          'qid' => $quiz
            ->id(),
          'vid' => $quiz
            ->getRevisionId(),
          'uid' => \Drupal::currentUser()
            ->id(),
          'type' => $quiz
            ->get('result_type')
            ->getString(),
        ));
        $build_on_last = $quiz
          ->get('build_on_last')
          ->getString() != 'fresh' && $quiz_result
          ->findOldResult();
        $instances = Drupal::service('entity_field.manager')
          ->getFieldDefinitions('quiz_result', $quiz
          ->get('result_type')
          ->getString());
        foreach ($instances as $field_name => $field) {
          if ($build_on_last || is_a($field, Drupal\field\Entity\FieldConfig::class) && $field
            ->getThirdPartySetting('quiz', 'show_field')) {

            // We found a field to be filled out.
            $redirect_url = \Drupal\Core\Url::fromRoute('entity.quiz.take', [
              'quiz' => $quiz_result
                ->getQuiz()
                ->id(),
            ]);
            $form = \Drupal::service('entity.form_builder')
              ->getForm($quiz_result, 'default', [
              'redirect' => $redirect_url,
            ]);
            return $form;
          }
        }
      }
      else {
        $page['body']['#markup'] = $result['message'];
        return $page;
      }
    }

    // New attempt.
    $quiz_result
      ->save();
    $_SESSION['quiz'][$quiz
      ->id()]['result_id'] = $quiz_result
      ->id();
    $_SESSION['quiz'][$quiz
      ->id()]['current'] = 1;
    return $this
      ->redirect('quiz.question.take', [
      'quiz' => $quiz
        ->id(),
      'question_number' => 1,
    ]);
  }

  /**
   * Creates a form for quiz questions.
   *
   * Handles the manage questions tab.
   *
   * @param $node
   *   The quiz node we are managing questions for.
   * @return ???
   *   String containing the form.
   */
  function manageQuestions(Quiz $quiz) {
    if ($quiz
      ->get('randomization')
      ->getString() < 3) {
      $manage_questions = Drupal::formBuilder()
        ->getForm(\Drupal\quiz\Form\QuizQuestionsForm::class, $quiz);
      return $manage_questions;
      $question_bank = Views::getView('quiz_question_bank')
        ->preview();

      // Insert into vert tabs.
      $form['vert_tabs'] = array(
        '#type' => 'x',
        // @todo wtf?
        '#weight' => 0,
        '#default_tab' => 'edit-questions',
      );
      $form['vert_tabs']['questions'] = array(
        '#type' => 'details',
        '#title' => t('Manage questions'),
        '#group' => 'vert_tabs',
        'questions' => $manage_questions,
      );
      $form['vert_tabs']['bank'] = array(
        '#type' => 'details',
        '#title' => t('Question bank'),
        '#group' => 'vert_tabs',
        'bank' => $question_bank,
      );
      return $manage_questions;
    }
    else {
      $form = \Drupal::service('entity.manager')
        ->getFormObject('quiz', 'default')
        ->setEntity($quiz);
      $form = \Drupal::formBuilder()
        ->getForm($form);
    }
    foreach (\Drupal\Core\Render\Element::children($form) as $key) {
      if (in_array($key, array_keys($quiz
        ->getFieldDefinitions())) || $form[$key]['#type'] == 'details') {
        if (!in_array($key, [
          'quiz_terms',
          'random',
          'quiz',
        ])) {
          $form[$key]['#access'] = FALSE;
        }
      }
    }
    return $form;
  }

  /**
   * Resume a quiz.
   *
   * Search the database for an in progress attempt, and put it back into the
   * session if allowed.
   *
   * @return QuizResult
   */
  function resume($quiz) {
    $user = \Drupal::currentUser();

    // Make sure we use the same revision of the quiz throughout the quiz taking
    // session.
    $result_id = !empty($_SESSION['quiz'][$quiz
      ->id()]['result_id']) ? $_SESSION['quiz'][$quiz
      ->id()]['result_id'] : NULL;
    if ($result_id && ($quiz_result = QuizResult::load($result_id))) {
      return $quiz_result;
    }
    else {

      // User doesn't have attempt in session. If we allow resuming we can load it
      // from the database.
      if ($quiz
        ->get('allow_resume')
        ->getString() && $user
        ->isAuthenticated()) {
        if ($quiz_result = $quiz
          ->getResumeableResult($user)) {

          // Put the result in the user's session.
          $_SESSION['quiz'][$quiz
            ->id()]['result_id'] = $quiz_result
            ->id();
          $_SESSION['quiz'][$quiz
            ->id()]['current'] = 1;

          // Now advance the user to after the last answered question.
          $prev = NULL;
          foreach ($quiz_result
            ->getLayout() as $qra) {
            if ($prev) {
              if ($qra
                ->get('answer_timestamp')
                ->isEmpty() && !$prev
                ->get('answer_timestamp')
                ->isEmpty()) {

                // This question has not been answered, but the previous
                // question has.
                $_SESSION['quiz'][$quiz
                  ->id()]['current'] = $qra
                  ->get('number')
                  ->getString();
              }
            }
            $prev = clone $qra;
          }

          // Mark this quiz as being resumed from the database.
          $quiz_result->resume = TRUE;
          return $quiz_result;
        }
      }
    }
    return FALSE;
  }

}

Classes

Namesort descending Description
QuizController