Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

   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  /**
  18   * A condition for adding filtering by tag to the question bank.
  19   *
  20   * @package   core_question
  21   * @copyright 2018 Ryan Wyllie <ryan@moodle.com>
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_question\bank\search;
  26  
  27  /**
  28   * Question bank search class to allow searching/filtering by tags on a question.
  29   *
  30   * @copyright 2018 Ryan Wyllie <ryan@moodle.com>
  31   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32   */
  33  class tag_condition extends condition {
  34  
  35      /** @var string SQL fragment to add to the where clause. */
  36      protected $where;
  37  
  38      /** @var array Named SQL params to be used with the SQL WHERE snippet. */
  39      protected $params;
  40  
  41      /** @var array List of contexts to show tags from. */
  42      protected $contexts;
  43  
  44      /** @var array List of IDs for tags that have been selected in the form. */
  45      protected $selectedtagids;
  46  
  47      /**
  48       * Constructor.
  49       *
  50       * @param array $contexts List of contexts to show tags from
  51       * @param int[] $selectedtagids List of IDs for tags to filter by.
  52       * @throws \coding_exception
  53       * @throws \dml_exception
  54       */
  55      public function __construct(array $contexts, array $selectedtagids = []) {
  56          global $DB;
  57  
  58          $this->contexts = $contexts;
  59  
  60          // If some tags have been selected then we need to filter
  61          // the question list by the selected tags.
  62          if ($selectedtagids) {
  63              // We treat each additional tag as an AND condition rather than
  64              // an OR condition.
  65              //
  66              // For example, if the user filters by the tags "foo" and "bar" then
  67              // we reduce the question list to questions that are tagged with both
  68              // "foo" AND "bar". Any question that does not have ALL of the specified
  69              // tags will be omitted.
  70              list($tagsql, $tagparams) = $DB->get_in_or_equal($selectedtagids, SQL_PARAMS_NAMED);
  71              $tagparams['tagcount'] = count($selectedtagids);
  72              $tagparams['questionitemtype'] = 'question';
  73              $tagparams['questioncomponent'] = 'core_question';
  74              $this->selectedtagids = $selectedtagids;
  75              $this->params = $tagparams;
  76              $this->where = "q.id IN (SELECT ti.itemid
  77                                         FROM {tag_instance} ti
  78                                        WHERE ti.itemtype = :questionitemtype
  79                                              AND ti.component = :questioncomponent
  80                                              AND ti.tagid {$tagsql}
  81                                     GROUP BY ti.itemid
  82                                       HAVING COUNT(itemid) = :tagcount)";
  83  
  84          } else {
  85              $this->selectedtagids = [];
  86              $this->params = [];
  87              $this->where = '';
  88          }
  89      }
  90  
  91      /**
  92       * Get the SQL WHERE snippet to be used in the SQL to retrieve the
  93       * list of questions. This SQL snippet will add the logic for the
  94       * tag condition.
  95       *
  96       * @return string
  97       */
  98      public function where() {
  99          return $this->where;
 100      }
 101  
 102      /**
 103       * Named SQL params to be used with the SQL WHERE snippet.
 104       *
 105       * @return array
 106       */
 107      public function params() {
 108          return $this->params;
 109      }
 110  
 111      /**
 112       * Print HTML to display the list of tags to filter by.
 113       */
 114      public function display_options() {
 115          global $OUTPUT;
 116  
 117          $tags = \core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $this->contexts);
 118          $tagoptions = array_map(function($tag) {
 119              return [
 120                  'id' => $tag->id,
 121                  'name' => $tag->name,
 122                  'selected' => in_array($tag->id, $this->selectedtagids)
 123              ];
 124          }, array_values($tags));
 125          $context = [
 126              'tagoptions' => $tagoptions
 127          ];
 128  
 129          return $OUTPUT->render_from_template('core_question/tag_condition', $context);
 130      }
 131  }