Exemplo n.º 1
0
 /**
  * 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 '';
 }
Exemplo n.º 2
0
 /**
  * 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);
 }
Exemplo n.º 3
0
 /**
  * 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));
 }
Exemplo n.º 5
0
 /**
  * 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);
 }
Exemplo n.º 6
0
Arquivo: api.php Projeto: dg711/moodle
 /**
  * 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);
 }
Exemplo n.º 7
0
    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()));
    }