mirrored from git://git.moodle.org/moodle.git
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDL-61135 question: add tag filter condition
- Loading branch information
1 parent
73d16fc
commit 031a275
Showing
6 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
<?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/>. | ||
|
||
/** | ||
* A condition for adding filtering by tag to the question bank. | ||
* | ||
* @package core_question | ||
* @copyright 2018 Ryan Wyllie <ryan@moodle.com> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
namespace core_question\bank\search; | ||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
/** | ||
* Question bank search class to allow searching/filtering by tags on a question. | ||
* | ||
* @copyright 2018 Ryan Wyllie <ryan@moodle.com> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class tag_condition extends condition { | ||
/** @var string SQL fragment to add to the where clause. */ | ||
protected $where; | ||
/** @var string SQL fragment to add to the where clause. */ | ||
protected $contexts; | ||
/** @var array List of IDs for tags that have been selected in the form. */ | ||
protected $selectedtagids; | ||
|
||
/** | ||
* Constructor. | ||
* @param context[] $contexts List of contexts to show tags from | ||
* @param int[] $selectedtagids List of IDs for tags to filter by. | ||
*/ | ||
public function __construct(array $contexts, array $selectedtagids = []) { | ||
global $DB; | ||
|
||
$this->contexts = $contexts; | ||
|
||
// 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. | ||
list($tagsql, $tagparams) = $DB->get_in_or_equal($selectedtagids, SQL_PARAMS_NAMED); | ||
$tagparams['tagcount'] = count($selectedtagids); | ||
$this->selectedtagids = $selectedtagids; | ||
$this->params = $tagparams; | ||
$this->where = "q.id IN (SELECT ti.itemid | ||
FROM {tag_instance} ti | ||
WHERE ti.tagid {$tagsql} | ||
GROUP BY ti.itemid | ||
HAVING COUNT(itemid) = :tagcount)"; | ||
|
||
} else { | ||
$this->selectedtagids = []; | ||
$this->params = []; | ||
$this->where = ''; | ||
} | ||
} | ||
|
||
/** | ||
* Get the SQL WHERE snippet to be used in the SQL to retrieve the | ||
* list of questions. This SQL snippet will add the logic for the | ||
* tag condition. | ||
* | ||
* @return string | ||
*/ | ||
public function where() { | ||
return $this->where; | ||
} | ||
|
||
/** | ||
* Named SQL params to be used with the SQL WHERE snippet. | ||
* | ||
* @return array | ||
*/ | ||
public function params() { | ||
return $this->params; | ||
} | ||
|
||
/** | ||
* Print HTML to display the list of tags to filter by. | ||
*/ | ||
public function display_options() { | ||
global $OUTPUT; | ||
|
||
$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 | ||
]; | ||
|
||
echo $OUTPUT->render_from_template('core_question/tag_condition', $context); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
{{! | ||
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/>. | ||
}} | ||
{{! | ||
@template core_question/tag_condition | ||
An auto-complete select box containing a list of available tags to | ||
filter the quesiton bank questions by. | ||
Classes required for JS: | ||
* none | ||
Data attributes required for JS: | ||
* none | ||
Context variables required for this template: | ||
* tagoptions A list of available tags | ||
Example context (json): | ||
{ | ||
"tagoptions": [ | ||
{ | ||
"id": 1, | ||
"name": "foo", | ||
"selected": true | ||
}, | ||
{ | ||
"id": 2, | ||
"name": "bar", | ||
"selected": false | ||
} | ||
] | ||
} | ||
}} | ||
<div class="tag-condition-container" data-region="tag-condition-container-{{uniqid}}"> | ||
<div class="form-group"> | ||
<select multiple name="qtagids[]" class="form-control invisible" size="3" data-region="tag-select"> | ||
{{#tagoptions}} | ||
<option {{#selected}}selected{{/selected}} value="{{id}}">{{name}}</option> | ||
{{/tagoptions}} | ||
</select> | ||
{{< core/overlay_loading }} | ||
{{$hiddenclass}}{{/hiddenclass}} | ||
{{/ core/overlay_loading }} | ||
</div> | ||
</div> | ||
{{#js}} | ||
require( | ||
[ | ||
'jquery', | ||
'core/form-autocomplete' | ||
], | ||
function( | ||
$, | ||
AutoComplete | ||
) { | ||
var root = $('[data-region="tag-condition-container-{{uniqid}}"]'); | ||
var selectElement = root.find('[data-region="tag-select"]'); | ||
var loadingContainer = root.find('[data-region="overlay-icon-container"]'); | ||
var placeholderText = '{{#str}} filterbytags, core_question {{/str}}'; | ||
var noSelectionText = '{{#str}} notagfiltersapplied, core_question {{/str}}'; | ||
AutoComplete.enhance( | ||
selectElement, // Element to enhance. | ||
false, // Don't allow support for creating new tags. | ||
false, // Don't allow AMD module to handle loading new tags. | ||
placeholderText, // Placeholder text. | ||
false, // Make search case insensitive. | ||
true, // Show suggestions for tags. | ||
noSelectionText // Text when no tags are selected. | ||
).always(function() { | ||
// Hide the loading icon once the autocomplete has initialised. | ||
loadingContainer.addClass('hidden'); | ||
}); | ||
|
||
// We need to trigger a form submission because of how the question bank | ||
// page handles reloading the questions when an option changes. | ||
selectElement.on('change', function() { | ||
selectElement.closest('form').submit(); | ||
}); | ||
}); | ||
{{/js}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters