AutorÃa | Ultima modificación | Ver Log |
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace qbank_tagquestion;
use core\output\datafilter;
use core_question\local\bank\condition;
/**
* Question bank search class to allow searching/filtering by tags on a question.
*
* @package qbank_tagquestion
* @copyright 2018 Ryan Wyllie <ryan@moodle.com>
* @author 2021 Safat Shahin <safatshahin@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tag_condition extends condition {
/** @var int The default filter type */
const JOINTYPE_DEFAULT = datafilter::JOINTYPE_ALL;
/** @var array Contexts to be used. */
protected $contexts = [];
/** @var array List of IDs for tags that have been selected in the form. */
protected $selectedtagids = [];
/**
* Tag condition constructor. It uses the qbank object and initialises all the its required information
* to be passed as a part of condition to get the questions.
*
* @param null $qbank qbank view
*/
public function __construct($qbank = null) {
if (is_null($qbank)) {
return;
}
parent::__construct($qbank);
$cat = $qbank->get_pagevars('cat');
if (is_array($cat)) {
foreach ($cat as $value) {
[, $contextid] = explode(',', $value);
$catcontext = \context::instance_by_id($contextid);
$this->contexts[] = $catcontext;
}
} else {
[, $contextid] = explode(',', $qbank->get_pagevars('cat'));
$catcontext = \context::instance_by_id($contextid);
$this->contexts[] = $catcontext;
}
$thiscontext = $qbank->get_most_specific_context();
$this->contexts[] = $thiscontext;
$this->selectedtagids = $this->filter->values ?? [];
}
public static function get_condition_key() {
return 'qtagids';
}
/**
* Print HTML to display the list of tags to filter by.
*/
public function display_options() {
global $PAGE;
$tags = \core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $this->contexts);
$tagoptions = array_map(function($tag) {
return [
'id' => $tag->id,
'name' => $tag->name,
'selected' => in_array($tag->id, $this->selectedtagids)
];
}, array_values($tags));
$context = [
'tagoptions' => $tagoptions
];
return $PAGE->get_renderer('qbank_tagquestion')->render_tag_condition($context);
}
/**
* Build query from filter value
*
* @param array $filter filter properties
* @return array where sql and params
*/
public static function build_query_from_filter(array $filter): array {
global $DB;
// Remove empty string.
$filter['values'] = array_filter($filter['values']);
$selectedtagids = $filter['values'] ?? [];
$params = [];
$where = '';
$jointype = $filter['jointype'] ?? self::JOINTYPE_DEFAULT;
// If some tags have been selected then we need to filter
// the question list by the selected tags.
if ($selectedtagids) {
// We treat each additional tag as an AND condition rather than
// an OR condition.
//
// For example, if the user filters by the tags "foo" and "bar" then
// we reduce the question list to questions that are tagged with both
// "foo" AND "bar". Any question that does not have ALL of the specified
// tags will be omitted.
$equal = !($jointype === datafilter::JOINTYPE_NONE);
[$tagsql, $tagparams] = $DB->get_in_or_equal($selectedtagids, SQL_PARAMS_NAMED, 'param', $equal);
$tagparams['tagcount'] = count($selectedtagids);
$tagparams['questionitemtype'] = 'question';
$tagparams['questioncomponent'] = 'core_question';
$params = $tagparams;
$where = "q.id IN (SELECT ti.itemid
FROM {tag_instance} ti
WHERE ti.itemtype = :questionitemtype
AND ti.component = :questioncomponent
AND ti.tagid {$tagsql}
GROUP BY ti.itemid ";
if ($jointype === datafilter::JOINTYPE_ALL) {
$where .= "HAVING COUNT(itemid) = :tagcount ";
}
$where .= ") ";
}
return [$where, $params];
}
public function get_title() {
return get_string('tag', 'tag');
}
public function get_filter_class() {
return null;
}
public function allow_custom() {
return false;
}
public function get_initial_values() {
$tags = \core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $this->contexts);
$values = [];
foreach ($tags as $tag) {
$values[] = [
'value' => $tag->id,
'title' => html_entity_decode($tag->name),
'selected' => in_array($tag->id, $this->selectedtagids)
];
}
return $values;
}
}