Commit 76f2d894 authored by Marina Glancy's avatar Marina Glancy
Browse files

MDL-10965 course: search only courses with completion

it is quite often when we need to have an autocomplete element that searches courses that
have completion enabled. This commit adds an option for the 'course' form element, and also
changes two places where we search for courses with completion. This should fix MDL-58989
parent 2c8b8af4
......@@ -78,22 +78,10 @@ class award_criteria_courseset extends award_criteria {
require_once($CFG->dirroot . '/course/lib.php');
$buttonarray = array();
// Get courses with enabled completion.
$courses = $DB->get_records('course', array('enablecompletion' => COMPLETION_ENABLED));
if (!empty($courses)) {
$list = core_course_category::make_categories_list();
$select = array();
$selected = array();
foreach ($courses as $c) {
$select[$c->id] = $list[$c->category] . ' / ' . format_string($c->fullname, true, array('context' => context_course::instance($c->id)));
}
if ($this->id !== 0) {
$selected = array_keys($this->params);
}
$settings = array('multiple' => 'multiple', 'size' => 20, 'style' => 'width:300px');
$mform->addElement('select', 'courses', get_string('addcourse', 'badges'), $select, $settings);
$hasselectablecourses = core_course_category::search_courses(['onlywithcompletion' => true], ['limit' => 1]);
if ($hasselectablecourses) {
$settings = array('multiple' => 'multiple', 'onlywithcompletion' => 1);
$mform->addElement('course', 'courses', get_string('addcourse', 'badges'), $settings);
$mform->addRule('courses', get_string('requiredcourse', 'badges'), 'required');
$mform->addHelpButton('courses', 'addcourse', 'badges');
......@@ -104,6 +92,7 @@ class award_criteria_courseset extends award_criteria {
$mform->addElement('hidden', 'addcourse', 'addcourse');
$mform->setType('addcourse', PARAM_TEXT);
if ($this->id !== 0) {
$selected = array_keys($this->params);
$mform->setDefault('courses', $selected);
}
$mform->setType('agg', PARAM_INT);
......
......@@ -1494,6 +1494,7 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
* - blocklist - id of block (if we are searching for courses containing specific block0
* - modulelist - name of module (if we are searching for courses containing specific module
* - tagid - id of tag
* - onlywithcompletion - set to true if we only need courses with completion enabled
* @param array $options display options, same as in get_courses() except 'recursive' is ignored -
* search is always category-independent
* @param array $requiredcapabilities List of capabilities required to see return course.
......@@ -1550,8 +1551,13 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
if (empty($search['blocklist']) && empty($search['modulelist']) && empty($search['tagid'])) {
// Search courses that have specified words in their names/summaries.
$searchterms = preg_split('|\s+|', trim($search['search']), 0, PREG_SPLIT_NO_EMPTY);
$courselist = get_courses_search($searchterms, 'c.sortorder ASC', 0, 9999999, $totalcount, $requiredcapabilities);
$searchcond = $searchcondparams = [];
if (!empty($search['onlywithcompletion'])) {
$searchcond = ['c.enablecompletion = :p1'];
$searchcondparams = ['p1' => 1];
}
$courselist = get_courses_search($searchterms, 'c.sortorder ASC', 0, 9999999, $totalcount,
$requiredcapabilities, $searchcond, $searchcondparams);
self::sort_records($courselist, $sortfields);
$coursecatcache->set($cachekey, array_keys($courselist));
$coursecatcache->set($cntcachekey, $totalcount);
......
......@@ -128,57 +128,29 @@ class course_completion_form extends moodleform {
}
// Get applicable courses (prerequisites).
$courses = $DB->get_records_sql("
SELECT DISTINCT c.id, c.category, c.fullname, cc.id AS selected
FROM {course} c
LEFT JOIN {course_completion_criteria} cc ON cc.courseinstance = c.id AND cc.course = {$course->id}
INNER JOIN {course_completion_criteria} ccc ON ccc.course = c.id
WHERE c.enablecompletion = ".COMPLETION_ENABLED."
AND c.id <> {$course->id}");
if (!empty($courses)) {
// Get category list.
$list = core_course_category::make_categories_list();
// Get course list for select box.
$selectbox = array();
$selected = array();
foreach ($courses as $c) {
$selectbox[$c->id] = $list[$c->category] . ' / ' . format_string($c->fullname, true,
array('context' => context_course::instance($c->id)));
// If already selected ...
if ($c->selected) {
$selected[] = $c->id;
}
}
$selectedcourses = $DB->get_fieldset_sql("SELECT cc.courseinstance
FROM {course_completion_criteria} cc WHERE cc.course = ?", [$course->id]);
$hasselectablecourses = core_course_category::search_courses(['onlywithcompletion' => true], ['limit' => 2]);
unset($hasselectablecourses[$course->id]);
if ($hasselectablecourses) {
// Show multiselect box.
$mform->addElement('select', 'criteria_course', get_string('coursesavailable', 'completion'), $selectbox,
array('multiple' => 'multiple', 'size' => 6));
// Select current criteria.
$mform->setDefault('criteria_course', $selected);
// Explain list.
$mform->addElement('static', 'criteria_courses_explaination', '', get_string('coursesavailableexplaination', 'completion'));
$mform->addElement('course', 'criteria_course', get_string('coursesavailable', 'completion'),
array('multiple' => 'multiple', 'onlywithcompletion' => true, 'exclude' => $course->id));
$mform->setDefault('criteria_course', $selectedcourses);
if (count($courses) > 1) {
// Map aggregation methods to context-sensitive human readable dropdown menu.
$courseaggregationmenu = array();
foreach ($aggregation_methods as $methodcode => $methodname) {
if ($methodcode === COMPLETION_AGGREGATION_ALL) {
$courseaggregationmenu[COMPLETION_AGGREGATION_ALL] = get_string('courseaggregation_all', 'core_completion');
} else if ($methodcode === COMPLETION_AGGREGATION_ANY) {
$courseaggregationmenu[COMPLETION_AGGREGATION_ANY] = get_string('courseaggregation_any', 'core_completion');
} else {
$courseaggregationmenu[$methodcode] = $methodname;
}
// Map aggregation methods to context-sensitive human readable dropdown menu.
$courseaggregationmenu = array();
foreach ($aggregation_methods as $methodcode => $methodname) {
if ($methodcode === COMPLETION_AGGREGATION_ALL) {
$courseaggregationmenu[COMPLETION_AGGREGATION_ALL] = get_string('courseaggregation_all', 'core_completion');
} else if ($methodcode === COMPLETION_AGGREGATION_ANY) {
$courseaggregationmenu[COMPLETION_AGGREGATION_ANY] = get_string('courseaggregation_any', 'core_completion');
} else {
$courseaggregationmenu[$methodcode] = $methodname;
}
$mform->addElement('select', 'course_aggregation', get_string('courseaggregation', 'core_completion'), $courseaggregationmenu);
$mform->setDefault('course_aggregation', $completion->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE));
}
$mform->addElement('select', 'course_aggregation', get_string('courseaggregation', 'core_completion'), $courseaggregationmenu);
$mform->setDefault('course_aggregation', $completion->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE));
} else {
$mform->addElement('static', 'nocourses', '', get_string('err_nocourses', 'completion'));
}
......
......@@ -2373,6 +2373,8 @@ class core_course_external extends external_api {
'Optional list of required capabilities (used to filter the list)', VALUE_DEFAULT, array()
),
'limittoenrolled' => new external_value(PARAM_BOOL, 'limit to enrolled courses', VALUE_DEFAULT, 0),
'onlywithcompletion' => new external_value(PARAM_BOOL, 'limit to courses where completion is enabled',
VALUE_DEFAULT, 0),
)
);
}
......@@ -2469,6 +2471,7 @@ class core_course_external extends external_api {
* @param int $perpage Items per page
* @param array $requiredcapabilities Optional list of required capabilities (used to filter the list).
* @param int $limittoenrolled Limit to only enrolled courses
* @param int onlywithcompletion Limit to only courses where completion is enabled
* @return array of course objects and warnings
* @since Moodle 3.0
* @throws moodle_exception
......@@ -2478,7 +2481,8 @@ class core_course_external extends external_api {
$page=0,
$perpage=0,
$requiredcapabilities=array(),
$limittoenrolled=0) {
$limittoenrolled=0,
$onlywithcompletion=0) {
global $CFG;
$warnings = array();
......@@ -2488,7 +2492,9 @@ class core_course_external extends external_api {
'criteriavalue' => $criteriavalue,
'page' => $page,
'perpage' => $perpage,
'requiredcapabilities' => $requiredcapabilities
'requiredcapabilities' => $requiredcapabilities,
'limittoenrolled' => $limittoenrolled,
'onlywithcompletion' => $onlywithcompletion
);
$params = self::validate_parameters(self::search_courses_parameters(), $parameters);
self::validate_context(context_system::instance());
......@@ -2514,6 +2520,9 @@ class core_course_external extends external_api {
// Prepare the search API options.
$searchcriteria = array();
$searchcriteria[$params['criterianame']] = $params['criteriavalue'];
if ($params['onlywithcompletion']) {
$searchcriteria['onlywithcompletion'] = true;
}
$options = array();
if ($params['perpage'] != 0) {
......
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -54,6 +54,7 @@ define(['core/ajax', 'jquery'], function(ajax, $) {
var limittoenrolled = el.data('limittoenrolled');
var includefrontpage = el.data('includefrontpage');
var onlywithcompletion = el.data('onlywithcompletion');
// Build the query.
var promises = null;
......@@ -68,7 +69,8 @@ define(['core/ajax', 'jquery'], function(ajax, $) {
page: 0,
perpage: 100,
requiredcapabilities: requiredcapabilities,
limittoenrolled: limittoenrolled
limittoenrolled: limittoenrolled,
onlywithcompletion: onlywithcompletion
};
var calls = [{
......
......@@ -665,10 +665,12 @@ function get_courses($categoryid="all", $sort="c.sortorder ASC", $fields="c.*")
* @param int $recordsperpage The number of records per page
* @param int $totalcount Passed in by reference.
* @param array $requiredcapabilities Extra list of capabilities used to filter courses
* @param array $searchcond additional search conditions, for example ['c.enablecompletion = :p1']
* @param array $params named parameters for additional search conditions, for example ['p1' => 1]
* @return stdClass[] {@link $COURSE} records
*/
function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$totalcount,
$requiredcapabilities = array()) {
$requiredcapabilities = array(), $searchcond = [], $params = []) {
global $CFG, $DB;
if ($DB->sql_regex_supported()) {
......@@ -676,8 +678,6 @@ function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$total
$NOTREGEXP = $DB->sql_regex(false);
}
$searchcond = array();
$params = array();
$i = 0;
// Thanks Oracle for your non-ansi concat and type limits in coalesce. MDL-29912
......
......@@ -71,6 +71,7 @@ class MoodleQuickForm_course extends MoodleQuickForm_autocomplete {
* 'requiredcapabilities' - array of capabilities. Uses ANY to combine them.
* 'limittoenrolled' - boolean Limits to enrolled courses.
* 'includefrontpage' - boolean Enables the frontpage to be selected.
* 'onlywithcompletion' - only courses where completion is enabled
*/
public function __construct($elementname = null, $elementlabel = null, $options = array()) {
if (isset($options['multiple'])) {
......@@ -107,6 +108,9 @@ class MoodleQuickForm_course extends MoodleQuickForm_autocomplete {
if (!empty($options['includefrontpage'])) {
$validattributes['data-includefrontpage'] = SITEID;
}
if (!empty($options['onlywithcompletion'])) {
$validattributes['data-onlywithcompletion'] = 1;
}
parent::__construct($elementname, $elementlabel, array(), $validattributes);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment