mirror of
https://github.com/moodle/moodle.git
synced 2025-08-07 01:46:45 +02:00
MDL-63058 block_myoverview: starring and storing preferences
This commit is contained in:
parent
b81722e22f
commit
3cfff88516
39 changed files with 1403 additions and 101 deletions
|
@ -35,12 +35,26 @@ use moodle_url;
|
|||
*/
|
||||
class course_summary_exporter extends \core\external\exporter {
|
||||
|
||||
/**
|
||||
* Constructor - saves the persistent object, and the related objects.
|
||||
*
|
||||
* @param mixed $data - Either an stdClass or an array of values.
|
||||
* @param array $related - An optional list of pre-loaded objects related to this object.
|
||||
*/
|
||||
public function __construct($data, $related = array()) {
|
||||
if (!array_key_exists('isfavourite', $related)) {
|
||||
$related['isfavourite'] = false;
|
||||
}
|
||||
parent::__construct($data, $related);
|
||||
}
|
||||
|
||||
protected static function define_related() {
|
||||
// We cache the context so it does not need to be retrieved from the course.
|
||||
return array('context' => '\\context');
|
||||
return array('context' => '\\context', 'isfavourite' => 'bool?');
|
||||
}
|
||||
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
|
||||
$courseimage = self::get_course_image($this->data);
|
||||
if (!$courseimage) {
|
||||
$courseimage = self::get_course_pattern($this->data);
|
||||
|
@ -56,7 +70,8 @@ class course_summary_exporter extends \core\external\exporter {
|
|||
'viewurl' => (new moodle_url('/course/view.php', array('id' => $this->data->id)))->out(false),
|
||||
'courseimage' => $courseimage,
|
||||
'progress' => $progress,
|
||||
'hasprogress' => $hasprogress
|
||||
'hasprogress' => $hasprogress,
|
||||
'isfavourite' => $this->related['isfavourite']
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -119,6 +134,9 @@ class course_summary_exporter extends \core\external\exporter {
|
|||
),
|
||||
'hasprogress' => array(
|
||||
'type' => PARAM_BOOL
|
||||
),
|
||||
'isfavourite' => array(
|
||||
'type' => PARAM_BOOL
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3663,6 +3663,8 @@ class core_course_external extends external_api {
|
|||
break;
|
||||
case COURSE_TIMELINE_FUTURE:
|
||||
break;
|
||||
case COURSE_FAVOURITES:
|
||||
break;
|
||||
default:
|
||||
throw new invalid_parameter_exception('Invalid classification');
|
||||
}
|
||||
|
@ -3672,17 +3674,42 @@ class core_course_external extends external_api {
|
|||
$requiredproperties = course_summary_exporter::define_properties();
|
||||
$fields = join(',', array_keys($requiredproperties));
|
||||
$courses = course_get_enrolled_courses_for_logged_in_user(0, $offset, $sort, $fields);
|
||||
list($filteredcourses, $processedcount) = course_filter_courses_by_timeline_classification(
|
||||
$courses,
|
||||
$classification,
|
||||
$limit
|
||||
);
|
||||
|
||||
$favouritecourseids = [];
|
||||
$ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($USER->id));
|
||||
$favourites = $ufservice->find_favourites_by_type('core_course', 'courses');
|
||||
|
||||
if ($favourites) {
|
||||
$favouritecourseids = array_map(
|
||||
function($favourite) {
|
||||
return $favourite->itemid;
|
||||
}, $favourites);
|
||||
}
|
||||
|
||||
if ($classification == COURSE_FAVOURITES) {
|
||||
list($filteredcourses, $processedcount) = course_filter_courses_by_favourites(
|
||||
$courses,
|
||||
$favouritecourseids,
|
||||
$limit
|
||||
);
|
||||
|
||||
} else {
|
||||
list($filteredcourses, $processedcount) = course_filter_courses_by_timeline_classification(
|
||||
$courses,
|
||||
$classification,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$formattedcourses = array_map(function($course) use ($renderer) {
|
||||
$formattedcourses = array_map(function($course) use ($renderer, $favouritecourseids) {
|
||||
context_helper::preload_from_record($course);
|
||||
$context = context_course::instance($course->id);
|
||||
$exporter = new course_summary_exporter($course, ['context' => $context]);
|
||||
$isfavourite = false;
|
||||
if (in_array($course->id, $favouritecourseids)) {
|
||||
$isfavourite = true;
|
||||
}
|
||||
$exporter = new course_summary_exporter($course, ['context' => $context, 'isfavourite' => $isfavourite]);
|
||||
return $exporter->export($renderer);
|
||||
}, $filteredcourses);
|
||||
|
||||
|
@ -3705,4 +3732,114 @@ class core_course_external extends external_api {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function set_favourite_courses_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'courses' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'id' => new external_value(PARAM_INT, 'course ID'),
|
||||
'favourite' => new external_value(PARAM_BOOL, 'favourite status')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the course favourite status for an array of courses.
|
||||
*
|
||||
* @param array $courses List with course id's and favourite status.
|
||||
* @return array Array with an array of favourite courses.
|
||||
*/
|
||||
public static function set_favourite_courses(
|
||||
array $courses
|
||||
) {
|
||||
global $USER;
|
||||
|
||||
$params = self::validate_parameters(self::set_favourite_courses_parameters(),
|
||||
array(
|
||||
'courses' => $courses
|
||||
)
|
||||
);
|
||||
|
||||
$warnings = [];
|
||||
|
||||
$ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($USER->id));
|
||||
|
||||
foreach ($params['courses'] as $course) {
|
||||
|
||||
$warning = [];
|
||||
|
||||
$favouriteexists = $ufservice->favourite_exists('core_course', 'courses', $course['id'], \context_system::instance());
|
||||
|
||||
if ($course['favourite']) {
|
||||
if (!$favouriteexists) {
|
||||
try {
|
||||
$ufservice->create_favourite('core_course', 'courses', $course['id'], \context_system::instance());
|
||||
} catch (Exception $e) {
|
||||
$warning['courseid'] = $course['id'];
|
||||
if ($e instanceof moodle_exception) {
|
||||
$warning['warningcode'] = $e->errorcode;
|
||||
} else {
|
||||
$warning['warningcode'] = $e->getCode();
|
||||
}
|
||||
$warning['message'] = $e->getMessage();
|
||||
$warnings[] = $warning;
|
||||
$warnings[] = $warning;
|
||||
}
|
||||
} else {
|
||||
$warning['courseid'] = $course['id'];
|
||||
$warning['warningcode'] = 'coursealreadyfavourited';
|
||||
$warning['message'] = 'Course already favourited';
|
||||
$warnings[] = $warning;
|
||||
}
|
||||
} else {
|
||||
if ($favouriteexists) {
|
||||
try {
|
||||
$ufservice->delete_favourite('core_course', 'courses', $course['id'], \context_system::instance());
|
||||
} catch (Exception $e) {
|
||||
$warning['courseid'] = $course['id'];
|
||||
if ($e instanceof moodle_exception) {
|
||||
$warning['warningcode'] = $e->errorcode;
|
||||
} else {
|
||||
$warning['warningcode'] = $e->getCode();
|
||||
}
|
||||
$warning['message'] = $e->getMessage();
|
||||
$warnings[] = $warning;
|
||||
$warnings[] = $warning;
|
||||
}
|
||||
} else {
|
||||
$warning['courseid'] = $course['id'];
|
||||
$warning['warningcode'] = 'cannotdeletefavourite';
|
||||
$warning['message'] = 'Could not delete favourite status for course';
|
||||
$warnings[] = $warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value
|
||||
*
|
||||
* @return external_description
|
||||
*/
|
||||
public static function set_favourite_courses_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'warnings' => new external_warnings()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ define('COURSE_TIMELINE_ALL', 'all');
|
|||
define('COURSE_TIMELINE_PAST', 'past');
|
||||
define('COURSE_TIMELINE_INPROGRESS', 'inprogress');
|
||||
define('COURSE_TIMELINE_FUTURE', 'future');
|
||||
define('COURSE_FAVOURITES', 'favourites');
|
||||
define('COURSE_DB_QUERY_LIMIT', 1000);
|
||||
|
||||
function make_log_url($module, $url) {
|
||||
|
@ -4271,6 +4272,51 @@ function course_filter_courses_by_timeline_classification(
|
|||
return [$filteredcourses, $numberofcoursesprocessed];
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the given $courses for any that match the given $classification up to the specified
|
||||
* $limit.
|
||||
*
|
||||
* This function will return the subset of courses that are favourites as well as the
|
||||
* number of courses it had to process to build that subset.
|
||||
*
|
||||
* It is recommended that for larger sets of courses this function is given a Generator that loads
|
||||
* the courses from the database in chunks.
|
||||
*
|
||||
* @param array|Traversable $courses List of courses to process
|
||||
* @param array $favouritecourseids Array of favourite courses.
|
||||
* @param int $limit Limit the number of results to this amount
|
||||
* @return array First value is the filtered courses, second value is the number of courses processed
|
||||
*/
|
||||
function course_filter_courses_by_favourites(
|
||||
$courses,
|
||||
$favouritecourseids,
|
||||
int $limit = 0
|
||||
) : array {
|
||||
|
||||
$filteredcourses = [];
|
||||
$numberofcoursesprocessed = 0;
|
||||
$filtermatches = 0;
|
||||
|
||||
foreach ($courses as $course) {
|
||||
$numberofcoursesprocessed++;
|
||||
|
||||
if (in_array($course->id, $favouritecourseids)) {
|
||||
$filteredcourses[] = $course;
|
||||
$filtermatches++;
|
||||
}
|
||||
|
||||
if ($limit && $filtermatches >= $limit) {
|
||||
// We've found the number of requested courses. No need to continue searching.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the number of filtered courses as well as the number of courses that were searched
|
||||
// in order to find the matching courses. This allows the calling code to do some kind of
|
||||
// pagination.
|
||||
return [$filteredcourses, $numberofcoursesprocessed];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check module updates since a given time.
|
||||
* This function checks for updates in the module config, file areas, completion, grades, comments and ratings.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue