You are here

class QuizQuestionController in Quiz 6.x

Same name and namespace in other branches
  1. 8.6 src/Controller/QuizQuestionController.php \Drupal\quiz\Controller\QuizQuestionController
  2. 8.5 src/Controller/QuizQuestionController.php \Drupal\quiz\Controller\QuizQuestionController

Hierarchy

Expanded class hierarchy of QuizQuestionController

File

src/Controller/QuizQuestionController.php, line 16

Namespace

Drupal\quiz\Controller
View source
class QuizQuestionController extends EntityController {

  /**
   * Show feedback for a question or page.
   *
   * @param Quiz $quiz
   * @param type $question_number
   *
   * @return type
   */
  function feedback(Quiz $quiz, $question_number) {
    $form = Drupal::formBuilder()
      ->getForm(QuizQuestionFeedbackForm::class, $quiz, $question_number);
    $page['body']['question'] = $form;
    return $page;
  }

  /**
   * Take a quiz questions.
   *
   * @param Quiz $quiz
   *   A quiz.
   * @param int $question_number
   *   A question number, starting at 1. Pages do not have question numbers.
   *   Quiz directions are considered part of the numbering.
   */
  function take(Quiz $quiz, $question_number) {

    /* @var $quiz_session \Drupal\quiz\Services\QuizSessionInterface */
    $quiz_session = \Drupal::service('quiz.session');
    if ($quiz_session
      ->isTakingQuiz($quiz)) {

      // Attempt to resume a quiz in progress.
      $quiz_result = $quiz_session
        ->getResult($quiz);
      $layout = $quiz_result
        ->getLayout();

      /* @var $question QuizResultAnswer */
      $question_relationship = $layout[$question_number];
      if (!empty($question_relationship->qqr_pid)) {

        // Find the parent.
        foreach ($layout as $pquestion) {
          if ($pquestion->qqr_id == $question_relationship->qqr_pid) {

            // Load the page that the requested question belongs to.
            $question = Drupal::entityTypeManager()
              ->getStorage('quiz_question')
              ->loadRevision($pquestion
              ->get('question_vid')
              ->getString());
          }
        }
      }
      else {

        // Load the question.
        $question = Drupal::entityTypeManager()
          ->getStorage('quiz_question')
          ->loadRevision($question_relationship
          ->get('question_vid')
          ->getString());
      }
    }
    if (!isset($question)) {

      // Question disappeared or invalid session. Start over. @todo d8 route
      $quiz_session
        ->removeQuiz($quiz
        ->id());
      return [
        '#markup' => 'Question disappeared or invalid session. Start over.',
      ];
      drupal_goto("quiz/{$quiz->id()}");
    }

    // Added the progress info to the view.
    $quiz_result = $quiz_session
      ->getResult($quiz);
    $questions = [];
    $i = 0;
    $found_pages = 0;
    foreach ($quiz_result
      ->getLayout() as $idx => $question_relationship) {
      if (empty($question_relationship->qqr_pid)) {

        // Question has no parent. Show it in the jumper.
        $questions[$idx] = ++$i;
        $found_pages++;
      }
      if ($question
        ->id() == $question_relationship
        ->get('question_id')
        ->getString()) {

        // Found our question.
        $current_page = $found_pages;
      }
    }
    $content = [];
    $content['progress'] = [
      '#theme' => 'quiz_progress',
      '#total' => count($questions),
      '#current' => $current_page,
      '#weight' => -50,
    ];
    if (count($questions) < \Drupal::config('quiz.settings')
      ->get('pager_start', 100)) {
      $selectbox = \Drupal::formBuilder()
        ->getForm('\\Drupal\\quiz\\Form\\QuizJumperForm', $quiz_result, $current_page, count($questions));
      $content['jumper'] = [
        '#theme' => 'quiz_jumper',
        '#form' => $selectbox,
        '#total' => count($questions),
      ];
    }
    else {
      $siblings = \Drupal::config('quiz.settings')
        ->get('pager_siblings');
      $items[] = [
        '#wrapper_attributes' => [
          'class' => [
            'pager__item',
            'pager-first',
          ],
        ],
        'data' => Link::createFromRoute(t('first'), 'quiz.question.take', [
          'quiz' => $quiz
            ->id(),
          'question_number' => 1,
        ])
          ->toRenderable(),
      ];
      foreach (_quiz_pagination_helper(count($questions), 1, $current_page, $siblings) as $i) {
        if ($i == $current_page) {
          $items[] = [
            '#wrapper_attributes' => [
              'class' => [
                'pager__item',
                'pager-current',
              ],
            ],
            'data' => [
              '#markup' => $current_page,
            ],
          ];
        }
        else {
          $items[] = [
            '#wrapper_attributes' => [
              'class' => [
                'pager__item',
                'pager-item',
              ],
            ],
            'data' => Link::createFromRoute($i, 'quiz.question.take', [
              'quiz' => $quiz
                ->id(),
              'question_number' => $i,
            ])
              ->toRenderable(),
          ];
        }
      }
      $items[] = [
        '#wrapper_attributes' => [
          'class' => [
            'pager__item',
            'pager-last',
          ],
        ],
        'data' => Link::createFromRoute(t('last'), 'quiz.question.take', [
          'quiz' => $quiz
            ->id(),
          'question_number' => count($questions),
        ])
          ->toRenderable(),
      ];
      $content['pager'] = [
        '#type' => 'html_tag',
        '#tag' => 'nav',
        '#attributes' => [
          'class' => [
            'pager',
          ],
          'role' => 'navigation',
        ],
      ];
      $content['pager']['links'] = [
        '#theme' => 'item_list',
        '#items' => $items,
        '#attributes' => [
          'class' => [
            'pager__items',
          ],
        ],
      ];
    }
    if (function_exists('jquery_countdown_add') && \Drupal::config('quiz.settings')
      ->get('has_timer', 0) && $quiz->time_limit) {
      jquery_countdown_add('.countdown', [
        'until' => $quiz_result->time_start + $quiz->time_limit - \Drupal::time()
          ->getRequestTime(),
        'onExpiry' => 'quiz_finished',
        'compact' => FALSE,
        'layout' => t('Time left') . ': {hnn}{sep}{mnn}{sep}{snn}',
      ]);

      // These are the two button op values that are accepted for answering
      // questions.
      $button_op1 = drupal_json_encode(t('Finish'));
      $button_op2 = drupal_json_encode(t('Next'));
      $js = "\n            function quiz_finished() {\n              // Find all buttons with a name of 'op'.\n              var buttons = jQuery('input[type=submit][name=op], button[type=submit][name=op]');\n              // Filter out the ones that don't have the right op value.\n              buttons = buttons.filter(function() {\n                return this.value == {$button_op1} || this.value == {$button_op2};\n              });\n              if (buttons.length == 1) {\n                // Since only one button was found, this must be it.\n                buttons.click();\n              }\n              else {\n                // Zero, or more than one buttons were found; fall back on a page refresh.\n                window.location = window.location.href;\n              }\n            }\n          ";
      drupal_add_js($js, 'inline');

      // Add div to be used by jQuery countdown.
      $content['body']['countdown']['#markup'] = '<div class="countdown"></div>';
    }
    $form = Drupal::formBuilder()
      ->getForm(QuizQuestionAnsweringForm::class, $question, $quiz_session
      ->getResult($quiz));
    $content['body']['question'] = $form;
    return $content;
  }

  /**
   * Translate the numeric question index to a question result answer, and run
   * the "take" entity access check on it.
   *
   * @param Quiz $quiz
   * @param int $question_number
   */
  function checkAccess(Quiz $quiz, $question_number) {
    return $this
      ->checkEntityAccess('take', $quiz, $question_number);
  }

  /**
   * Translate the numeric question index to a question result answer, and run
   * the "feedback" entity access check on it.
   *
   * @param Quiz $quiz
   * @param int $question_number
   */
  function checkFeedbackAccess(Quiz $quiz, $question_number) {
    return $this
      ->checkEntityAccess('feedback', $quiz, $question_number);
  }

  /**
   * Translate the numeric question index to a question result answer, and run
   * the default entity access check on it.
   *
   * @param string $op
   *   An entity operation to check.
   * @param Quiz $quiz
   *   The quiz.
   * @param int $question_number
   *   The question number in the current result.
   */
  function checkEntityAccess($op, Quiz $quiz, $question_number) {
    $qra = $this
      ->numberToQuestionResultAnswer($quiz, $question_number);
    return $qra && $qra
      ->access($op) ? AccessResultAllowed::allowed() : AccessResultForbidden::forbidden();
  }

  /**
   * Translate the numeric question index to a question result answer.
   *
   * @param Quiz $quiz
   * @param int $question_number
   *
   * @return QuizResultAnswer
   *   The question result answer, or NULL if the current result does not exist
   * or does not contain this question.
   */
  function numberToQuestionResultAnswer(Quiz $quiz, $question_number) {
    if ($quiz_result = QuizUtil::resultOrTemp($quiz)) {
      return $quiz_result
        ->getLayout()[$question_number];
    }
    return NULL;
  }
  public static function getTitle(Quiz $quiz, $question_number) {
    return $quiz
      ->label();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityController::$entityRepository protected property The entity repository.
EntityController::$entityTypeBundleInfo protected property The entity type bundle info.
EntityController::$entityTypeManager protected property The entity type manager.
EntityController::$renderer protected property The renderer.
EntityController::addBundleTitle public function Provides a generic add title callback for entities with bundles.
EntityController::addPage public function Displays add links for the available bundles.
EntityController::addTitle public function Provides a generic add title callback for an entity type.
EntityController::create public static function Instantiates a new instance of this class. Overrides ContainerInjectionInterface::create
EntityController::deleteTitle public function Provides a generic delete title callback.
EntityController::doGetEntity protected function Determines the entity.
EntityController::editTitle public function Provides a generic edit title callback.
EntityController::loadBundleDescriptions protected function Expands the bundle information with descriptions, if known.
EntityController::redirect protected function Returns a redirect response object for the specified route.
EntityController::title public function Provides a generic title callback for a single entity.
EntityController::__construct public function Constructs a new EntityController.
QuizQuestionController::checkAccess function Translate the numeric question index to a question result answer, and run the "take" entity access check on it.
QuizQuestionController::checkEntityAccess function Translate the numeric question index to a question result answer, and run the default entity access check on it.
QuizQuestionController::checkFeedbackAccess function Translate the numeric question index to a question result answer, and run the "feedback" entity access check on it.
QuizQuestionController::feedback function Show feedback for a question or page.
QuizQuestionController::getTitle public static function
QuizQuestionController::numberToQuestionResultAnswer function Translate the numeric question index to a question result answer.
QuizQuestionController::take function Take a quiz questions.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.