Skip to content

Commit

Permalink
MDL-55356 core_search: Change existing search areas to new API
Browse files Browse the repository at this point in the history
This change considers all existing search areas in Moodle and makes
necessary changes.

Custom change to course search, supported by helper in base.php:

* course/classes/search/mycourse.php

Custom change to message search:

* message/classes/search/message_received.php
* message/classes/search/message_sent.php

Custom change to user search:

* user/classes/search/user.php

Custom changes to module areas, supported by helper in base_mod.php:

* mod/book/classes/search/chapter.php
* mod/data/classes/search/entry.php
* mod/forum/classes/search/post.php
* mod/glossary/classes/search/entry.php
* mod/survey/classes/search/activity.php
* mod/wiki/classes/search/collaborative_page.php

(Note: the unit tests do not exhaustively check every context type
for these, given that's mainly handled by the helper function
which was already tested in the base_activity test.)

Handled by block base class (no change):

* blocks/html/classes/search/content.php

Handled by activity base class (no change):

* mod/assign/classes/search/activity.php
* mod/book/classes/search/activity.php
* mod/chat/classes/search/activity.php
* mod/choice/classes/search/activity.php
* mod/data/classes/search/activity.php
* mod/feedback/classes/search/activity.php
* mod/folder/classes/search/activity.php
* mod/forum/classes/search/activity.php
* mod/glossary/classes/search/activity.php
* mod/imscp/classes/search/activity.php
* mod/label/classes/search/activity.php
* mod/lesson/classes/search/activity.php
* mod/lti/classes/search/activity.php
* mod/page/classes/search/activity.php
* mod/quiz/classes/search/activity.php
* mod/resource/classes/search/activity.php
* mod/scorm/classes/search/activity.php
* mod/url/classes/search/activity.php
* mod/wiki/classes/search/activity.php
* mod/workshop/classes/search/activity.php
  • Loading branch information
sammarshallou committed Oct 11, 2017
1 parent 81a9888 commit 66e3702
Show file tree
Hide file tree
Showing 21 changed files with 584 additions and 58 deletions.
19 changes: 16 additions & 3 deletions course/classes/search/mycourse.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,24 @@ class mycourse extends \core_search\base {
* Returns recordset containing required data for indexing courses.
*
* @param int $modifiedfrom timestamp
* @return \moodle_recordset
* @param \context|null $context Restriction context
* @return \moodle_recordset|null Recordset or null if no change possible
*/
public function get_recordset_by_timestamp($modifiedfrom = 0) {
public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
global $DB;
return $DB->get_recordset_select('course', 'timemodified >= ?', array($modifiedfrom), 'timemodified ASC');

list ($contextjoin, $contextparams) = $this->get_course_level_context_restriction_sql(
$context, 'c');
if ($contextjoin === null) {
return null;
}

return $DB->get_recordset_sql("
SELECT c.*
FROM {course} c
$contextjoin
WHERE c.timemodified >= ?
ORDER BY c.timemodified ASC", array_merge($contextparams, [$modifiedfrom]));
}

/**
Expand Down
79 changes: 79 additions & 0 deletions course/tests/search_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,85 @@ public function test_mycourses_indexing() {
$recordset->close();
}

/**
* Tests course indexing support for contexts.
*/
public function test_mycourses_indexing_contexts() {
global $DB, $USER, $SITE;

$searcharea = \core_search\manager::get_search_area($this->mycoursesareaid);

// Create some courses in categories, and a forum.
$generator = $this->getDataGenerator();
$cat1 = $generator->create_category();
$course1 = $generator->create_course(['category' => $cat1->id]);
$cat2 = $generator->create_category(['parent' => $cat1->id]);
$course2 = $generator->create_course(['category' => $cat2->id]);
$cat3 = $generator->create_category();
$course3 = $generator->create_course(['category' => $cat3->id]);
$forum = $generator->create_module('forum', ['course' => $course1->id]);
$DB->set_field('course', 'timemodified', 0, ['id' => $SITE->id]);
$DB->set_field('course', 'timemodified', 1, ['id' => $course1->id]);
$DB->set_field('course', 'timemodified', 2, ['id' => $course2->id]);
$DB->set_field('course', 'timemodified', 3, ['id' => $course3->id]);

// Find the first block to use for a block context.
$blockid = array_values($DB->get_records('block_instances', null, 'id', 'id', 0, 1))[0]->id;
$blockcontext = context_block::instance($blockid);

// Check with block context - should be null.
$this->assertNull($searcharea->get_document_recordset(0, $blockcontext));

// Check with user context - should be null.
$this->setAdminUser();
$usercontext = context_user::instance($USER->id);
$this->assertNull($searcharea->get_document_recordset(0, $usercontext));

// Check with module context - should be null.
$modcontext = context_module::instance($forum->cmid);
$this->assertNull($searcharea->get_document_recordset(0, $modcontext));

// Check with course context - should return specified course if timestamp allows.
$coursecontext = context_course::instance($course3->id);
$results = self::recordset_to_ids($searcharea->get_document_recordset(3, $coursecontext));
$this->assertEquals([$course3->id], $results);
$results = self::recordset_to_ids($searcharea->get_document_recordset(4, $coursecontext));
$this->assertEquals([], $results);

// Check with category context - should return course in categories and subcategories.
$catcontext = context_coursecat::instance($cat1->id);
$results = self::recordset_to_ids($searcharea->get_document_recordset(0, $catcontext));
$this->assertEquals([$course1->id, $course2->id], $results);
$results = self::recordset_to_ids($searcharea->get_document_recordset(2, $catcontext));
$this->assertEquals([$course2->id], $results);

// Check with system context and null - should return all these courses + site course.
$systemcontext = context_system::instance();
$results = self::recordset_to_ids($searcharea->get_document_recordset(0, $systemcontext));
$this->assertEquals([$SITE->id, $course1->id, $course2->id, $course3->id], $results);
$results = self::recordset_to_ids($searcharea->get_document_recordset(0, null));
$this->assertEquals([$SITE->id, $course1->id, $course2->id, $course3->id], $results);
$results = self::recordset_to_ids($searcharea->get_document_recordset(3, $systemcontext));
$this->assertEquals([$course3->id], $results);
$results = self::recordset_to_ids($searcharea->get_document_recordset(3, null));
$this->assertEquals([$course3->id], $results);
}

/**
* Utility function to convert recordset to array of IDs for testing.
*
* @param moodle_recordset $rs Recordset to convert (and close)
* @return array Array of IDs from records indexed by number (0, 1, 2, ...)
*/
protected static function recordset_to_ids(moodle_recordset $rs) {
$results = [];
foreach ($rs as $rec) {
$results[] = $rec->id;
}
$rs->close();
return $results;
}

/**
* Document contents.
*
Expand Down
49 changes: 49 additions & 0 deletions message/classes/search/base_message.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,53 @@ protected function get_current_other_users($doc) {
return $users;
}

/**
* Helper function to implement get_document_recordset for subclasses.
*
* @param int $modifiedfrom Modified from date
* @param \context|null $context Context or null
* @param string $userfield Name of user field (from or to) being considered
* @return \moodle_recordset|null Recordset or null if no results possible
* @throws \coding_exception If context invalid
*/
protected function get_document_recordset_helper($modifiedfrom, \context $context = null,
$userfield) {
global $DB;

// Set up basic query.
$where = $userfield . ' != :noreplyuser AND ' . $userfield .
' != :supportuser AND timecreated >= :modifiedfrom';
$params = [
'noreplyuser' => \core_user::NOREPLY_USER,
'supportuser' => \core_user::SUPPORT_USER,
'modifiedfrom' => $modifiedfrom
];

// Check context to see whether to add other restrictions.
if ($context === null) {
$context = \context_system::instance();
}
switch ($context->contextlevel) {
case CONTEXT_COURSECAT:
case CONTEXT_COURSE:
case CONTEXT_MODULE:
case CONTEXT_BLOCK:
// There are no messages in any of these contexts so nothing can be found.
return null;

case CONTEXT_USER:
// Add extra restriction to specific user context.
$where .= ' AND ' . $userfield . ' = :userid';
$params['userid'] = $context->instanceid;
break;

case CONTEXT_SYSTEM:
break;

default:
throw new \coding_exception('Unexpected contextlevel: ' . $context->contextlevel);
}

return $DB->get_recordset_select('message_read', $where, $params, 'timeread ASC');
}
}
17 changes: 6 additions & 11 deletions message/classes/search/message_received.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,14 @@
class message_received extends base_message {

/**
* Returns recordset containing message records.
* Returns a recordset with the messages for indexing.
*
* @param int $modifiedfrom timestamp
* @return \moodle_recordset
* @param int $modifiedfrom
* @param \context|null $context Optional context to restrict scope of returned results
* @return moodle_recordset|null Recordset (or null if no results)
*/
public function get_recordset_by_timestamp($modifiedfrom = 0) {
global $DB;

// We don't want to index messages received from noreply and support users.
$params = array('modifiedfrom' => $modifiedfrom, 'noreplyuser' => \core_user::NOREPLY_USER,
'supportuser' => \core_user::SUPPORT_USER);
return $DB->get_recordset_select('message_read', 'timeread >= :modifiedfrom AND
useridto != :noreplyuser AND useridto != :supportuser', $params, 'timeread ASC');
public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
return $this->get_document_recordset_helper($modifiedfrom, $context, 'useridto');
}

/**
Expand Down
17 changes: 6 additions & 11 deletions message/classes/search/message_sent.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,14 @@
class message_sent extends base_message {

/**
* Returns recordset containing message records.
* Returns a recordset with the messages for indexing.
*
* @param int $modifiedfrom timestamp
* @return \moodle_recordset
* @param int $modifiedfrom
* @param \context|null $context Optional context to restrict scope of returned results
* @return moodle_recordset|null Recordset (or null if no results)
*/
public function get_recordset_by_timestamp($modifiedfrom = 0) {
global $DB;

// We don't want to index messages sent by noreply and support users.
$params = array('modifiedfrom' => $modifiedfrom, 'noreplyuser' => \core_user::NOREPLY_USER,
'supportuser' => \core_user::SUPPORT_USER);
return $DB->get_recordset_select('message_read', 'timeread >= :modifiedfrom AND
useridfrom != :noreplyuser AND useridfrom != :supportuser', $params, 'timeread ASC');
public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
return $this->get_document_recordset_helper($modifiedfrom, $context, 'useridfrom');
}

/**
Expand Down
65 changes: 65 additions & 0 deletions message/tests/search_received_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,71 @@ public function test_message_received_indexing() {
$recordset->close();
}

/**
* Indexing messages, with restricted contexts.
*/
public function test_message_received_indexing_contexts() {
global $SITE;
require_once(__DIR__ . '/search_sent_test.php');

$searcharea = \core_search\manager::get_search_area($this->messagereceivedareaid);

$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();

$this->preventResetByRollback();
$sink = $this->redirectMessages();

// Send first message.
$message = new \core\message\message();
$message->courseid = SITEID;
$message->userfrom = $user1;
$message->userto = $user2;
$message->subject = 'Test1';
$message->smallmessage = 'Test small messsage';
$message->fullmessage = 'Test full messsage';
$message->fullmessageformat = 0;
$message->fullmessagehtml = null;
$message->notification = 0;
$message->component = 'moodle';
$message->name = 'instantmessage';
message_send($message);

// Ensure that ordering by timestamp will return in consistent order.
$this->waitForSecond();

// Send second message in opposite direction.
$message = new \core\message\message();
$message->courseid = SITEID;
$message->userfrom = $user2;
$message->userto = $user1;
$message->subject = 'Test2';
$message->smallmessage = 'Test small messsage';
$message->fullmessage = 'Test full messsage';
$message->fullmessageformat = 0;
$message->fullmessagehtml = null;
$message->notification = 0;
$message->component = 'moodle';
$message->name = 'instantmessage';
message_send($message);

// Test function with null context and system context (same).
$rs = $searcharea->get_document_recordset(0, null);
$this->assertEquals(['Test1', 'Test2'], message_sent_search_testcase::recordset_to_subjects($rs));
$rs = $searcharea->get_document_recordset(0, context_system::instance());
$this->assertEquals(['Test1', 'Test2'], message_sent_search_testcase::recordset_to_subjects($rs));

// Test with user context for each user.
$rs = $searcharea->get_document_recordset(0, \context_user::instance($user1->id));
$this->assertEquals(['Test2'], message_sent_search_testcase::recordset_to_subjects($rs));
$rs = $searcharea->get_document_recordset(0, \context_user::instance($user2->id));
$this->assertEquals(['Test1'], message_sent_search_testcase::recordset_to_subjects($rs));

// Test with a course context (should return null).
$this->assertNull($searcharea->get_document_recordset(0,
context_course::instance($SITE->id)));
}

/**
* Document contents.
*
Expand Down
81 changes: 80 additions & 1 deletion message/tests/search_sent_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,85 @@ public function test_message_sent_indexing() {
$recordset->close();
}

/**
* Indexing messages, with restricted contexts.
*/
public function test_message_sent_indexing_contexts() {
global $SITE;

$searcharea = \core_search\manager::get_search_area($this->messagesentareaid);

$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();

$this->preventResetByRollback();
$sink = $this->redirectMessages();

// Send first message.
$message = new \core\message\message();
$message->courseid = SITEID;
$message->userfrom = $user1;
$message->userto = $user2;
$message->subject = 'Test1';
$message->smallmessage = 'Test small messsage';
$message->fullmessage = 'Test full messsage';
$message->fullmessageformat = 0;
$message->fullmessagehtml = null;
$message->notification = 0;
$message->component = 'moodle';
$message->name = 'instantmessage';
message_send($message);

// Ensure that ordering by timestamp will return in consistent order.
$this->waitForSecond();

// Send second message in opposite direction.
$message = new \core\message\message();
$message->courseid = SITEID;
$message->userfrom = $user2;
$message->userto = $user1;
$message->subject = 'Test2';
$message->smallmessage = 'Test small messsage';
$message->fullmessage = 'Test full messsage';
$message->fullmessageformat = 0;
$message->fullmessagehtml = null;
$message->notification = 0;
$message->component = 'moodle';
$message->name = 'instantmessage';
message_send($message);

// Test function with null context and system context (same).
$rs = $searcharea->get_document_recordset(0, null);
$this->assertEquals(['Test1', 'Test2'], self::recordset_to_subjects($rs));
$rs = $searcharea->get_document_recordset(0, context_system::instance());
$this->assertEquals(['Test1', 'Test2'], self::recordset_to_subjects($rs));

// Test with user context for each user.
$rs = $searcharea->get_document_recordset(0, \context_user::instance($user1->id));
$this->assertEquals(['Test1'], self::recordset_to_subjects($rs));
$rs = $searcharea->get_document_recordset(0, \context_user::instance($user2->id));
$this->assertEquals(['Test2'], self::recordset_to_subjects($rs));

// Test with a course context (should return null).
$this->assertNull($searcharea->get_document_recordset(0,
context_course::instance($SITE->id)));
}

/**
* Utility function to convert recordset to array of message subjects for testing.
*
* @param moodle_recordset $rs Recordset to convert (and close)
* @return array Array of IDs from records indexed by number (0, 1, 2, ...)
*/
public static function recordset_to_subjects(moodle_recordset $rs) {
$results = [];
foreach ($rs as $rec) {
$results[] = $rec->subject;
}
$rs->close();
return $results;
}

/**
* Document contents.
*
Expand Down Expand Up @@ -272,4 +351,4 @@ public function test_message_sent_deleted_user() {
$this->assertFalse($doc);

}
}
}
Loading

0 comments on commit 66e3702

Please sign in to comment.