/** * Renders html to print list of courses tagged with particular tag * * @param int $tagid id of the tag * @param bool $exclusivemode if set to true it means that no other entities tagged with this tag * are displayed on the page and the per-page limit may be bigger * @param int $fromctx context id where the link was displayed, may be used by callbacks * to display items in the same context first * @param int $ctx context id where to search for records * @param bool $rec search in subcontexts as well * @param array $displayoptions * @return string empty string if no courses are marked with this tag or rendered list of courses */ public function tagged_courses($tagid, $exclusivemode = true, $ctx = 0, $rec = true, $displayoptions = null) { global $CFG; require_once $CFG->libdir . '/coursecatlib.php'; if (empty($displayoptions)) { $displayoptions = array(); } $showcategories = coursecat::count_all() > 1; $displayoptions += array('limit' => $CFG->coursesperpage, 'offset' => 0); $chelper = new coursecat_helper(); $searchcriteria = array('tagid' => $tagid, 'ctx' => $ctx, 'rec' => $rec); $chelper->set_show_courses($showcategories ? self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT : self::COURSECAT_SHOW_COURSES_EXPANDED)->set_search_criteria($searchcriteria)->set_courses_display_options($displayoptions)->set_attributes(array('class' => 'course-search-result course-search-result-tagid')); // (we set the same css class as in search results by tagid) if ($totalcount = coursecat::search_courses_count($searchcriteria)) { $courses = coursecat::search_courses($searchcriteria, $chelper->get_courses_display_options()); if ($exclusivemode) { return $this->coursecat_courses($chelper, $courses, $totalcount); } else { $tagfeed = new core_tag\output\tagfeed(); $img = $this->output->pix_icon('i/course', ''); foreach ($courses as $course) { $url = course_get_url($course); $imgwithlink = html_writer::link($url, $img); $coursename = html_writer::link($url, $course->get_formatted_name()); $details = ''; if ($showcategories && ($cat = coursecat::get($course->category, IGNORE_MISSING))) { $details = get_string('category') . ': ' . html_writer::link(new moodle_url('/course/index.php', array('categoryid' => $cat->id)), $cat->get_formatted_name(), array('class' => $cat->visible ? '' : 'dimmed')); } $tagfeed->add($imgwithlink, $coursename, $details); } return $this->output->render_from_template('core_tag/tagfeed', $tagfeed->export_for_template($this->output)); } } return ''; }
/** * Search courses following the specified criteria. * * @param string $criterianame Criteria name (search, modulelist (only admins), blocklist (only admins), tagid) * @param string $criteriavalue Criteria value * @param int $page Page number (for pagination) * @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 * @return array of course objects and warnings * @since Moodle 3.0 * @throws moodle_exception */ public static function search_courses($criterianame, $criteriavalue, $page = 0, $perpage = 0, $requiredcapabilities = array(), $limittoenrolled = 0) { global $CFG; require_once $CFG->libdir . '/coursecatlib.php'; $warnings = array(); $parameters = array('criterianame' => $criterianame, 'criteriavalue' => $criteriavalue, 'page' => $page, 'perpage' => $perpage, 'requiredcapabilities' => $requiredcapabilities); $params = self::validate_parameters(self::search_courses_parameters(), $parameters); self::validate_context(context_system::instance()); $allowedcriterianames = array('search', 'modulelist', 'blocklist', 'tagid'); if (!in_array($params['criterianame'], $allowedcriterianames)) { throw new invalid_parameter_exception('Invalid value for criterianame parameter (value: ' . $params['criterianame'] . '),' . 'allowed values are: ' . implode(',', $allowedcriterianames)); } if ($params['criterianame'] == 'modulelist' or $params['criterianame'] == 'blocklist') { require_capability('moodle/site:config', context_system::instance()); } $paramtype = array('search' => PARAM_RAW, 'modulelist' => PARAM_PLUGIN, 'blocklist' => PARAM_INT, 'tagid' => PARAM_INT); $params['criteriavalue'] = clean_param($params['criteriavalue'], $paramtype[$params['criterianame']]); // Prepare the search API options. $searchcriteria = array(); $searchcriteria[$params['criterianame']] = $params['criteriavalue']; $options = array(); if ($params['perpage'] != 0) { $offset = $params['page'] * $params['perpage']; $options = array('offset' => $offset, 'limit' => $params['perpage']); } // Search the courses. $courses = coursecat::search_courses($searchcriteria, $options, $params['requiredcapabilities']); $totalcount = coursecat::search_courses_count($searchcriteria, $options, $params['requiredcapabilities']); if (!empty($limittoenrolled)) { // Get the courses where the current user has access. $enrolled = enrol_get_my_courses(array('id', 'cacherev')); } $finalcourses = array(); $categoriescache = array(); foreach ($courses as $course) { if (!empty($limittoenrolled)) { // Filter out not enrolled courses. if (!isset($enrolled[$course->id])) { $totalcount--; continue; } } $coursecontext = context_course::instance($course->id); $finalcourses[] = self::get_course_public_information($course, $coursecontext); } return array('total' => $totalcount, 'courses' => $finalcourses, 'warnings' => $warnings); }
/** * Renders html to print list of courses tagged with particular tag * * @param int $tagid id of the tag * @return string empty string if no courses are marked with this tag or rendered list of courses */ public function tagged_courses($tagid) { global $CFG; require_once $CFG->libdir . '/coursecatlib.php'; $displayoptions = array('limit' => $CFG->coursesperpage); $displayoptions['viewmoreurl'] = new moodle_url('/course/search.php', array('tagid' => $tagid, 'page' => 1, 'perpage' => $CFG->coursesperpage)); $displayoptions['viewmoretext'] = new lang_string('findmorecourses'); $chelper = new coursecat_helper(); $searchcriteria = array('tagid' => $tagid); $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT)->set_search_criteria(array('tagid' => $tagid))->set_courses_display_options($displayoptions)->set_attributes(array('class' => 'course-search-result course-search-result-tagid')); // (we set the same css class as in search results by tagid) $courses = coursecat::search_courses($searchcriteria, $chelper->get_courses_display_options()); $totalcount = coursecat::search_courses_count($searchcriteria); $content = $this->coursecat_courses($chelper, $courses, $totalcount); if ($totalcount) { require_once $CFG->dirroot . '/tag/lib.php'; $heading = get_string('courses') . ' ' . get_string('taggedwith', 'tag', tag_get_name($tagid)) . ': ' . $totalcount; return $this->heading($heading, 3) . $content; } return ''; }
public function test_get_search_courses() { $cat1 = coursecat::create(array('name' => 'Cat1')); $cat2 = coursecat::create(array('name' => 'Cat2', 'parent' => $cat1->id)); $c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3', 'summary' => ' ', 'idnumber' => 'ID3')); $c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 1', 'summary' => ' ', 'visible' => 0)); $c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Математика', 'summary' => ' Test ')); $c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 4', 'summary' => ' ', 'idnumber' => 'ID4')); $c5 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 5', 'summary' => ' ')); $c6 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Дискретная Математика', 'summary' => ' ')); $c7 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 7', 'summary' => ' ', 'visible' => 0)); $c8 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 8', 'summary' => ' ')); // Get courses in category 1 (returned visible only because user is not enrolled). $res = $cat1->get_courses(array('sortorder' => 1)); $this->assertEquals(array($c4->id, $c3->id, $c1->id), array_keys($res)); // Courses are added in reverse order. $this->assertEquals(3, $cat1->get_courses_count()); // Get courses in category 1 recursively (returned visible only because user is not enrolled). $res = $cat1->get_courses(array('recursive' => 1)); $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c6->id, $c5->id), array_keys($res)); $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1))); // Get courses sorted by fullname. $res = $cat1->get_courses(array('sort' => array('fullname' => 1))); $this->assertEquals(array($c1->id, $c4->id, $c3->id), array_keys($res)); $this->assertEquals(3, $cat1->get_courses_count(array('sort' => array('fullname' => 1)))); // Get courses sorted by fullname recursively. $res = $cat1->get_courses(array('recursive' => 1, 'sort' => array('fullname' => 1))); $this->assertEquals(array($c1->id, $c4->id, $c5->id, $c8->id, $c6->id, $c3->id), array_keys($res)); $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'sort' => array('fullname' => 1)))); // Get courses sorted by fullname recursively, use offset and limit. $res = $cat1->get_courses(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => -1))); $this->assertEquals(array($c6->id, $c8->id), array_keys($res)); // Offset and limit do not affect get_courses_count(). $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => 1)))); // Calling get_courses_count without prior call to get_courses(). $this->assertEquals(3, $cat2->get_courses_count(array('recursive' => 1, 'sort' => array('idnumber' => 1)))); // Search courses. // Search by text. $res = coursecat::search_courses(array('search' => 'Test')); $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res)); $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'Test'))); // Search by text with specified offset and limit. $options = array('sort' => array('fullname' => 1), 'offset' => 1, 'limit' => 2); $res = coursecat::search_courses(array('search' => 'Test'), $options); $this->assertEquals(array($c4->id, $c5->id), array_keys($res)); $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'Test'), $options)); // IMPORTANT: the tests below may fail on some databases // case-insensitive search. $res = coursecat::search_courses(array('search' => 'test')); $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res)); $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'test'))); // Non-latin language search. $res = coursecat::search_courses(array('search' => 'Математика')); $this->assertEquals(array($c3->id, $c6->id), array_keys($res)); $this->assertEquals(2, coursecat::search_courses_count(array('search' => 'Математика'), array())); $this->setUser($this->getDataGenerator()->create_user()); // Add necessary capabilities. $this->assign_capability('moodle/course:create', CAP_ALLOW, context_coursecat::instance($cat2->id)); // Do another search with restricted capabilities. $reqcaps = array('moodle/course:create'); $res = coursecat::search_courses(array('search' => 'test'), array(), $reqcaps); $this->assertEquals(array($c8->id, $c5->id), array_keys($res)); $this->assertEquals(2, coursecat::search_courses_count(array('search' => 'test'), array(), $reqcaps)); }
/** * Search courses following the specified criteria. * * @param string $criterianame Criteria name (search, modulelist (only admins), blocklist (only admins), tagid) * @param string $criteriavalue Criteria value * @param int $page Page number (for pagination) * @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 * @return array of course objects and warnings * @since Moodle 3.0 * @throws moodle_exception */ public static function search_courses($criterianame, $criteriavalue, $page = 0, $perpage = 0, $requiredcapabilities = array(), $limittoenrolled = 0) { global $CFG; require_once $CFG->libdir . '/coursecatlib.php'; $warnings = array(); $parameters = array('criterianame' => $criterianame, 'criteriavalue' => $criteriavalue, 'page' => $page, 'perpage' => $perpage, 'requiredcapabilities' => $requiredcapabilities); $params = self::validate_parameters(self::search_courses_parameters(), $parameters); self::validate_context(context_system::instance()); $allowedcriterianames = array('search', 'modulelist', 'blocklist', 'tagid'); if (!in_array($params['criterianame'], $allowedcriterianames)) { throw new invalid_parameter_exception('Invalid value for criterianame parameter (value: ' . $params['criterianame'] . '),' . 'allowed values are: ' . implode(',', $allowedcriterianames)); } if ($params['criterianame'] == 'modulelist' or $params['criterianame'] == 'blocklist') { require_capability('moodle/site:config', context_system::instance()); } $paramtype = array('search' => PARAM_RAW, 'modulelist' => PARAM_PLUGIN, 'blocklist' => PARAM_INT, 'tagid' => PARAM_INT); $params['criteriavalue'] = clean_param($params['criteriavalue'], $paramtype[$params['criterianame']]); // Prepare the search API options. $searchcriteria = array(); $searchcriteria[$params['criterianame']] = $params['criteriavalue']; $options = array(); if ($params['perpage'] != 0) { $offset = $params['page'] * $params['perpage']; $options = array('offset' => $offset, 'limit' => $params['perpage']); } // Search the courses. $courses = coursecat::search_courses($searchcriteria, $options, $params['requiredcapabilities']); $totalcount = coursecat::search_courses_count($searchcriteria, $options, $params['requiredcapabilities']); if (!empty($limittoenrolled)) { // Get the courses where the current user has access. $enrolled = enrol_get_my_courses(array('id', 'cacherev')); } $finalcourses = array(); $categoriescache = array(); foreach ($courses as $course) { if (!empty($limittoenrolled)) { // Filter out not enrolled courses. if (!isset($enrolled[$course->id])) { $totalcount--; continue; } } $coursecontext = context_course::instance($course->id); // Category information. if (!isset($categoriescache[$course->category])) { $categoriescache[$course->category] = coursecat::get($course->category); } $category = $categoriescache[$course->category]; // Retrieve course overfiew used files. $files = array(); foreach ($course->get_course_overviewfiles() as $file) { $fileurl = moodle_url::make_webservice_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), null, $file->get_filepath(), $file->get_filename())->out(false); $files[] = array('filename' => $file->get_filename(), 'fileurl' => $fileurl, 'filesize' => $file->get_filesize()); } // Retrieve the course contacts, // we need here the users fullname since if we are not enrolled can be difficult to obtain them via other Web Services. $coursecontacts = array(); foreach ($course->get_course_contacts() as $contact) { $coursecontacts[] = array('id' => $contact['user']->id, 'fullname' => $contact['username']); } // Allowed enrolment methods (maybe we can self-enrol). $enroltypes = array(); $instances = enrol_get_instances($course->id, true); foreach ($instances as $instance) { $enroltypes[] = $instance->enrol; } // Format summary. list($summary, $summaryformat) = external_format_text($course->summary, $course->summaryformat, $coursecontext->id, 'course', 'summary', null); $displayname = get_course_display_name_for_list($course); $coursereturns = array(); $coursereturns['id'] = $course->id; $coursereturns['fullname'] = external_format_string($course->fullname, $coursecontext->id); $coursereturns['displayname'] = external_format_string($displayname, $coursecontext->id); $coursereturns['shortname'] = external_format_string($course->shortname, $coursecontext->id); $coursereturns['categoryid'] = $course->category; $coursereturns['categoryname'] = $category->name; $coursereturns['summary'] = $summary; $coursereturns['summaryformat'] = $summaryformat; $coursereturns['overviewfiles'] = $files; $coursereturns['contacts'] = $coursecontacts; $coursereturns['enrollmentmethods'] = $enroltypes; $finalcourses[] = $coursereturns; } return array('total' => $totalcount, 'courses' => $finalcourses, 'warnings' => $warnings); }
/** * Handles searching for user in the message area. * * @param int $userid The user id doing the searching * @param string $search The string the user is searching * @param int $limitnum * @return array */ public static function search_users($userid, $search, $limitnum = 0) { global $CFG, $DB; require_once $CFG->dirroot . '/lib/coursecatlib.php'; // Used to search for contacts. $fullname = $DB->sql_fullname(); $ufields = \user_picture::fields('u', array('lastaccess')); // Users not to include. $excludeusers = array($userid, $CFG->siteguest); list($exclude, $excludeparams) = $DB->get_in_or_equal($excludeusers, SQL_PARAMS_NAMED, 'param', false); // Ok, let's search for contacts first. $contacts = array(); $sql = "SELECT {$ufields}, mc.blocked\n FROM {user} u\n JOIN {message_contacts} mc\n ON u.id = mc.contactid\n WHERE mc.userid = :userid\n AND u.deleted = 0\n AND u.confirmed = 1\n AND " . $DB->sql_like($fullname, ':search', false) . "\n AND u.id {$exclude}\n ORDER BY " . $DB->sql_fullname(); if ($users = $DB->get_records_sql($sql, array('userid' => $userid, 'search' => '%' . $search . '%') + $excludeparams, 0, $limitnum)) { foreach ($users as $user) { $contacts[] = helper::create_contact($user); } } // Now, let's get the courses. $courses = array(); if ($arrcourses = \coursecat::search_courses(array('search' => $search), array('limit' => $limitnum))) { foreach ($arrcourses as $course) { $data = new \stdClass(); $data->id = $course->id; $data->shortname = $course->shortname; $data->fullname = $course->fullname; $courses[] = $data; } } // Let's get those non-contacts. Toast them gears boi. // Note - you can only block contacts, so these users will not be blocked, so no need to get that // extra detail from the database. $noncontacts = array(); $sql = "SELECT {$ufields}\n FROM {user} u\n WHERE u.deleted = 0\n AND u.confirmed = 1\n AND " . $DB->sql_like($fullname, ':search', false) . "\n AND u.id {$exclude}\n AND u.id NOT IN (SELECT contactid\n FROM {message_contacts}\n WHERE userid = :userid)\n ORDER BY " . $DB->sql_fullname(); if ($users = $DB->get_records_sql($sql, array('userid' => $userid, 'search' => '%' . $search . '%') + $excludeparams, 0, $limitnum)) { foreach ($users as $user) { $noncontacts[] = helper::create_contact($user); } } return array($contacts, $courses, $noncontacts); }
public function test_get_search_courses() { $cat1 = coursecat::create(array('name' => 'Cat1')); $cat2 = coursecat::create(array('name' => 'Cat2', 'parent' => $cat1->id)); $c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3', 'summary' => ' ', 'idnumber' => 'ID3')); $c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 1', 'summary' => ' ', 'visible' => 0)); $c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Математика', 'summary' => ' Test ')); $c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 4', 'summary' => ' ', 'idnumber' => 'ID4')); $c5 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 5', 'summary' => ' ')); $c6 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Дискретная Математика', 'summary' => ' ')); $c7 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 7', 'summary' => ' ', 'visible' => 0)); $c8 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 8', 'summary' => ' ')); // get courses in category 1 (returned visible only because user is not enrolled) global $DB; $res = $cat1->get_courses(array('sortorder' => 1)); $this->assertEquals(array($c4->id, $c3->id, $c1->id), array_keys($res)); // courses are added in reverse order $this->assertEquals(3, $cat1->get_courses_count()); // get courses in category 1 recursively (returned visible only because user is not enrolled) $res = $cat1->get_courses(array('recursive' => 1)); $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c6->id, $c5->id), array_keys($res)); $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1))); // get courses sorted by fullname $res = $cat1->get_courses(array('sort' => array('fullname' => 1))); $this->assertEquals(array($c1->id, $c4->id, $c3->id), array_keys($res)); $this->assertEquals(3, $cat1->get_courses_count(array('sort' => array('fullname' => 1)))); // get courses sorted by fullname recursively $res = $cat1->get_courses(array('recursive' => 1, 'sort' => array('fullname' => 1))); $this->assertEquals(array($c1->id, $c4->id, $c5->id, $c8->id, $c6->id, $c3->id), array_keys($res)); $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'sort' => array('fullname' => 1)))); // get courses sorted by fullname recursively, use offset and limit $res = $cat1->get_courses(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => -1))); $this->assertEquals(array($c6->id, $c8->id), array_keys($res)); // offset and limit do not affect get_courses_count() $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => 1)))); // calling get_courses_count without prior call to get_courses() $this->assertEquals(3, $cat2->get_courses_count(array('recursive' => 1, 'sort' => array('idnumber' => 1)))); // search courses // search by text $res = coursecat::search_courses(array('search' => 'Test')); $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res)); $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'Test'))); // search by text with specified offset and limit $options = array('sort' => array('fullname' => 1), 'offset' => 1, 'limit' => 2); $res = coursecat::search_courses(array('search' => 'Test'), $options); $this->assertEquals(array($c4->id, $c5->id), array_keys($res)); $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'Test'), $options)); // IMPORTANT: the tests below may fail on some databases // case-insensitive search $res = coursecat::search_courses(array('search' => 'test')); $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res)); $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'test'))); // non-latin language search $res = coursecat::search_courses(array('search' => 'Математика')); $this->assertEquals(array($c3->id, $c6->id), array_keys($res)); $this->assertEquals(2, coursecat::search_courses_count(array('search' => 'Математика'), array())); }