Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 400 and 401] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace qbank_history;
  18  
  19  use core_question\local\bank\question_edit_contexts;
  20  use core_question\local\bank\view;
  21  use moodle_url;
  22  use stdClass;
  23  
  24  /**
  25   * Custom view class for the history page.
  26   *
  27   * @package    qbank_history
  28   * @copyright  2022 Catalyst IT Australia Pty Ltd
  29   * @author     Safat Shahin <safatshahin@catalyst-au.net>
  30   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   */
  32  class question_history_view extends view {
  33  
  34      /**
  35       * Entry id to get the versions
  36       *
  37       * @var int $entryid
  38       */
  39      protected $entryid;
  40  
  41      /**
  42       * Base url for the return.
  43       *
  44       * @var \moodle_url $basereturnurl
  45       */
  46      protected $basereturnurl;
  47  
  48      /**
  49       * Constructor for the history.
  50       * @param question_edit_contexts $contexts the contexts of api call
  51       * @param moodle_url $pageurl url of the page
  52       * @param stdClass $course course settings
  53       * @param int $entryid quiz settings
  54       * @param string $returnurl url to return to
  55       */
  56      public function __construct(question_edit_contexts $contexts, moodle_url $pageurl, stdClass $course, int $entryid,
  57                                  string $returnurl) {
  58          parent::__construct($contexts, $pageurl, $course);
  59          $this->entryid = $entryid;
  60          $this->basereturnurl = new \moodle_url($returnurl);
  61      }
  62  
  63      protected function wanted_columns(): array {
  64          $this->requiredcolumns = [];
  65          $excludefeatures = [
  66              'question_usage_column',
  67              'history_action_column'
  68          ];
  69          $questionbankcolumns = $this->get_question_bank_plugins();
  70          foreach ($questionbankcolumns as $classobject) {
  71              if (empty($classobject) || in_array($classobject->get_column_name(), $excludefeatures)) {
  72                  continue;
  73              }
  74              $this->requiredcolumns[$classobject->get_column_name()] = $classobject;
  75          }
  76  
  77          return $this->requiredcolumns;
  78      }
  79  
  80      public function wanted_filters($cat, $tagids, $showhidden, $recurse, $editcontexts, $showquestiontext): void {
  81          $categorydata = explode(',', $cat);
  82          $contextid = $categorydata[1];
  83          $catcontext = \context::instance_by_id($contextid);
  84          $thiscontext = $this->get_most_specific_context();
  85          $this->display_question_bank_header();
  86  
  87          // Display tag filter if usetags setting is enabled/enablefilters is true.
  88          if ($this->enablefilters) {
  89              if (is_array($this->customfilterobjects)) {
  90                  foreach ($this->customfilterobjects as $filterobjects) {
  91                      $this->searchconditions[] = $filterobjects;
  92                  }
  93              } else {
  94                  if (get_config('core', 'usetags')) {
  95                      array_unshift($this->searchconditions,
  96                              new \core_question\bank\search\tag_condition([$catcontext, $thiscontext], $tagids));
  97                  }
  98  
  99                  array_unshift($this->searchconditions, new \core_question\bank\search\hidden_condition(!$showhidden));
 100              }
 101          }
 102          $this->display_options_form($showquestiontext);
 103      }
 104  
 105      protected function display_advanced_search_form($advancedsearch): void {
 106          foreach ($advancedsearch as $searchcondition) {
 107              echo $searchcondition->display_options_adv();
 108          }
 109      }
 110  
 111      protected function create_new_question_form($category, $canadd): void {
 112          // As we dont want to create questions in this page.
 113      }
 114  
 115      /**
 116       * Default sort for question data.
 117       * @return array
 118       */
 119      protected function default_sort(): array {
 120          $defaultsort = [];
 121          if (class_exists('\\qbank_viewcreator\\creator_name_column')) {
 122              $sort = 'qbank_viewcreator\creator_name_column-timecreated';
 123          }
 124          $defaultsort[$sort] = 1;
 125  
 126          return $defaultsort;
 127      }
 128  
 129      protected function build_query(): void {
 130          // Get the required tables and fields.
 131          $joins = [];
 132          $fields = ['qv.status', 'qv.version', 'qv.id as versionid', 'qbe.id as questionbankentryid'];
 133          if (!empty($this->requiredcolumns)) {
 134              foreach ($this->requiredcolumns as $column) {
 135                  $extrajoins = $column->get_extra_joins();
 136                  foreach ($extrajoins as $prefix => $join) {
 137                      if (isset($joins[$prefix]) && $joins[$prefix] != $join) {
 138                          throw new \coding_exception('Join ' . $join . ' conflicts with previous join ' . $joins[$prefix]);
 139                      }
 140                      $joins[$prefix] = $join;
 141                  }
 142                  $fields = array_merge($fields, $column->get_required_fields());
 143              }
 144          }
 145          $fields = array_unique($fields);
 146  
 147          // Build the order by clause.
 148          $sorts = [];
 149          foreach ($this->sort as $sort => $order) {
 150              list($colname, $subsort) = $this->parse_subsort($sort);
 151              $sorts[] = $this->requiredcolumns[$colname]->sort_expression($order < 0, $subsort);
 152          }
 153  
 154          // Build the where clause.
 155          $entryid = "qbe.id = $this->entryid";
 156          // Changes done here to get the questions only for the passed entryid.
 157          $tests = ['q.parent = 0', $entryid];
 158          $this->sqlparams = [];
 159          foreach ($this->searchconditions as $searchcondition) {
 160              if ($searchcondition->where()) {
 161                  $tests[] = '((' . $searchcondition->where() .'))';
 162              }
 163              if ($searchcondition->params()) {
 164                  $this->sqlparams = array_merge($this->sqlparams, $searchcondition->params());
 165              }
 166          }
 167          // Build the SQL.
 168          $sql = ' FROM {question} q ' . implode(' ', $joins);
 169          $sql .= ' WHERE ' . implode(' AND ', $tests);
 170          $this->countsql = 'SELECT count(1)' . $sql;
 171          $this->loadsql = 'SELECT ' . implode(', ', $fields) . $sql . ' ORDER BY ' . implode(', ', $sorts);
 172      }
 173  
 174      /**
 175       * Display the header for the question bank in the history page to include question name and type.
 176       */
 177      public function display_question_bank_header(): void {
 178          global $PAGE, $DB, $OUTPUT;
 179          $sql = 'SELECT q.*
 180                   FROM {question} q
 181                   JOIN {question_versions} qv ON qv.questionid = q.id
 182                   JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
 183                  WHERE qv.version  = (SELECT MAX(v.version)
 184                                         FROM {question_versions} v
 185                                         JOIN {question_bank_entries} be
 186                                           ON be.id = v.questionbankentryid
 187                                        WHERE be.id = qbe.id)
 188                    AND qbe.id = ?';
 189          $latestquestiondata = $DB->get_record_sql($sql, [$this->entryid]);
 190          if ($latestquestiondata) {
 191              $historydata = [
 192                  'questionname' => $latestquestiondata->name,
 193                  'returnurl' => $this->basereturnurl,
 194                  'questionicon' => print_question_icon($latestquestiondata)
 195              ];
 196              // Header for the page before the actual form from the api.
 197              echo $PAGE->get_renderer('qbank_history')->render_history_header($historydata);
 198          } else {
 199              // Continue when all the question versions are deleted.
 200              echo $OUTPUT->notification(get_string('allquestionversionsdeleted', 'qbank_history'), 'notifysuccess');
 201              echo $OUTPUT->continue_button($this->basereturnurl);
 202          }
 203      }
 204  
 205      public function is_listing_specific_versions(): bool {
 206          return true;
 207      }
 208  
 209  }