Skip to content

Commit

Permalink
MDL-56020 search: Adapt code to new style and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyva committed Aug 28, 2023
1 parent 49e5894 commit f94e1ef
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 314 deletions.
9 changes: 4 additions & 5 deletions lib/db/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -1707,12 +1707,11 @@
'ajax' => true
),
'core_search_get_results' => array(
'classname' => 'core_search_external',
'methodname' => 'get_results',
'classpath' => 'search/classes/external.php',
'description' => 'Search contents.',
'classname' => '\core_search\external\get_results',
'description' => 'Get search results.',
'type' => 'read',
'capabilities' => 'moodle/search:query'
'capabilities' => 'moodle/search:query',
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE],
),
'core_tag_get_tagindex' => array(
'classname' => 'core_tag_external',
Expand Down
37 changes: 10 additions & 27 deletions search/classes/document.php
Original file line number Diff line number Diff line change
Expand Up @@ -392,18 +392,6 @@ public static function get_default_fields_definition() {
return static::$requiredfields + static::$optionalfields + static::$enginefields;
}

/**
* Returns whether a field is required or not.
*
* Considers engine fields to be optional.
*
* @param string $fieldname
* @return bool
*/
public static function field_is_required(string $fieldname): bool {
return (!empty(static::$requiredfields[$fieldname]));
}

/**
* Formats the timestamp preparing the time fields to be inserted into the search engine.
*
Expand Down Expand Up @@ -618,10 +606,10 @@ protected function apply_defaults() {
* Just delegates all the processing to export_doc_info, also used by external functions.
* Adding more info than the required one as people might be interested in extending the template.
*
* @param renderer_base $output The renderer.
* @param \renderer_base $output The renderer.
* @return array
*/
public function export_for_template(\renderer_base $output) {
public function export_for_template(\renderer_base $output): array {
$docdata = $this->export_doc($output);
return $docdata;
}
Expand All @@ -637,10 +625,12 @@ public function export_for_template(\renderer_base $output) {
* SECURITY NOTE: It is the responsibility of the document to properly escape any text to be displayed.
* The renderer will output the content without any further cleaning.
*
* @param \renderer_base $output The renderer.
* @return array
*/
public function export_doc(\renderer_base $output) {
global $USER;
public function export_doc(\renderer_base $output): array {
global $USER, $CFG;
require_once($CFG->dirroot . '/course/lib.php');

list($componentname, $areaname) = \core_search\manager::extract_areaid_parts($this->get('areaid'));
$context = context::instance_by_id($this->get('contextid'));
Expand Down Expand Up @@ -684,28 +674,21 @@ public function export_doc(\renderer_base $output) {
if ($this->get('userid') == $USER->id ||
(has_capability('moodle/user:viewdetails', $context) &&
has_capability('moodle/course:viewparticipants', $context))) {
$data['userurl'] = new \moodle_url(
$data['userurl'] = (new \moodle_url(
'/user/view.php',
['id' => $this->get('userid'), 'course' => $this->get('courseid')]
);
))->out(false);
$data['userfullname'] = format_string($this->get('userfullname'), true, ['context' => $context->id]);
$data['userid'] = $this->get('userid');
}
}

if ($docicon = $this->get_doc_icon()) {
$data['icon'] = $output->image_url($docicon->get_name(), $docicon->get_component());
$data['iconurl'] = $data['icon']->out(false);
}
$data['textformat'] = $this->get_text_format();

// We need to return the text formatting used for ws stuff.
$settings = \core_external\external_settings::get_instance();
if ($settings->get_raw()) {
// If this is called by a ws client and requests raw text we return the format specified by the search engine.
$data['textformat'] = $this->get_text_format();
} else {
// We convert texts to HTML by default.
$data['textformat'] = FORMAT_HTML;
}
return $data;
}

Expand Down
164 changes: 0 additions & 164 deletions search/classes/external.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,168 +120,4 @@ public static function get_relevant_users($query, $courseid) {
}
return $result;
}

/**
* get_results parameters.
*
* @since Moodle 3.2
* @return external_function_parameters
*/
public static function get_results_parameters() {
return new external_function_parameters(
array(
'q' => new external_value(PARAM_NOTAGS, 'the search query'),
'filters' => new external_single_structure(
array(
'title' => new external_value(PARAM_NOTAGS, 'result title', VALUE_OPTIONAL),
'areaids' => new external_multiple_structure(
new external_value(PARAM_RAW, 'areaid'), 'restrict results to these areas', VALUE_DEFAULT, []
),
'courseids' => new external_multiple_structure(
new external_value(PARAM_INT, 'courseid'), 'restrict results to these courses', VALUE_DEFAULT, []
),
'contextids' => new external_multiple_structure(
new external_value(PARAM_INT, 'contextid'), 'restrict results to these context', VALUE_DEFAULT, []
),
'userids' => new external_multiple_structure(
new external_value(PARAM_INT, 'userid'), 'restrict results to these users', VALUE_DEFAULT, []
),
'groupids' => new external_multiple_structure(
new external_value(PARAM_INT, 'groupid'), 'restrict results to these groups', VALUE_DEFAULT, []
),
'mycoursesonly' => new external_value(PARAM_BOOL, 'result title', VALUE_OPTIONAL),
'order' => new external_value(PARAM_ALPHA, 'result title', VALUE_OPTIONAL),
'timestart' => new external_value(PARAM_INT, 'result title', VALUE_DEFAULT, 0),
'timeend' => new external_value(PARAM_INT, 'result title', VALUE_DEFAULT, 0)
), 'filters to apply', VALUE_OPTIONAL
),
'page' => new external_value(PARAM_INT, 'results page number starting from 0, defaults to the first page',
VALUE_DEFAULT)
)
);
}


/*
* Gets global search results based on the provided query and filters.
*
* @param string $q
* @param array $filters
* @param int $page
* @return array
*/
public static function get_results($q, $filters = [], $page = 0) {
global $PAGE;

$params = self::validate_parameters(self::get_results_parameters(), array(
'q' => $q,
'filters' => $filters,
'page' => $page)
);

$system = \context_system::instance();
\external_api::validate_context($system);

require_capability('moodle/search:query', $system);

if (\core_search\manager::is_global_search_enabled() === false) {
throw new \moodle_exception('globalsearchdisabled', 'search');
}

$search = \core_search\manager::instance();

$data = new \stdClass();
$data->q = $params['q'];

if (!empty($params['filters']['title'])) {
$data->title = $params['filters']['title'];
}

if (!empty($params['filters']['areaids'])) {
$data->areaids = $params['filters']['areaids'];
}

if (!empty($params['filters']['courseids'])) {
$data->courseids = $params['filters']['courseids'];
}

if (!empty($params['filters']['contextids'])) {
$data->contextids = $params['filters']['contextids'];
}

if (!empty($params['filters']['userids'])) {
$data->userids = $params['filters']['userids'];
}

if (!empty($params['filters']['groupids'])) {
$data->groupids = $params['filters']['groupids'];
}

if (!empty($params['filters']['timestart'])) {
$data->timestart = $params['filters']['timestart'];
}
if (!empty($params['filters']['timeend'])) {
$data->timeend = $params['filters']['timeend'];
}

$docs = $search->paged_search($data, $page);

$return = [
'totalcount' => $docs->totalcount,
'warnings' => [],
'results' => []
];

// Convert results to simple data structures.
if ($docs) {
foreach ($docs->results as $doc) {
$return['results'][] = $doc->export_doc($PAGE->get_renderer('core'));
}
}
return $return;
}

/**
* Returns description of method get_results.
*
* @return external_single_structure
*/
public static function get_results_returns() {

return new external_single_structure(
array(
'totalcount' => new external_value(PARAM_INT, 'Total number of results'),
'results' => new external_multiple_structure(
new external_single_structure(
array(
'itemid' => new external_value(PARAM_INT, 'unique id in the search area scope'),
'componentname' => new external_value(PARAM_ALPHANUMEXT, 'component name'),
'areaname' => new external_value(PARAM_ALPHANUMEXT, 'search area name'),
'courseurl' => new external_value(PARAM_URL, 'result course url'),
'coursefullname' => new external_value(PARAM_RAW, 'result course fullname'),
'timemodified' => new external_value(PARAM_INT, 'result modified time'),
'title' => new external_value(PARAM_RAW, 'result title'),
'docurl' => new external_value(PARAM_URL, 'result url'),
'content' => new external_value(PARAM_RAW, 'result contents', VALUE_OPTIONAL),
'contextid' => new external_value(PARAM_INT, 'result context id'),
'contexturl' => new external_value(PARAM_URL, 'result context url'),
'description1' => new external_value(PARAM_RAW, 'extra result contents, depends on the search area', VALUE_OPTIONAL),
'description2' => new external_value(PARAM_RAW, 'extra result contents, depends on the search area', VALUE_OPTIONAL),
'multiplefiles' => new external_value(PARAM_INT, 'whether multiple files are returned or not', VALUE_OPTIONAL),
'filenames' => new external_multiple_structure(
new external_value(PARAM_RAW, 'result file name', VALUE_OPTIONAL)
, 'result file names if present',
VALUE_OPTIONAL
),
'filename' => new external_value(PARAM_RAW, 'result file name if present', VALUE_OPTIONAL),
'userid' => new external_value(PARAM_INT, 'user id', VALUE_OPTIONAL),
'userurl' => new external_value(PARAM_URL, 'user url', VALUE_OPTIONAL),
'userfullname' => new external_value(PARAM_RAW, 'user fullname', VALUE_OPTIONAL),
'textformat' => new external_value(PARAM_INT, 'text fields format, it is the same for all of them')
), 'Search result'
), 'Search results', VALUE_OPTIONAL
)
)
);
}
}
Loading

0 comments on commit f94e1ef

Please sign in to comment.