Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Calendar API: Difference between revisions

From MoodleDocs
Line 69: Line 69:


For integer and non-null event priorities, the lower the value, the higher the priority is. Meaning, user overrides always have a higher priority than group overrides. Group override priorities are currently being determined in two ways in core activities:
For integer and non-null event priorities, the lower the value, the higher the priority is. Meaning, user overrides always have a higher priority than group overrides. Group override priorities are currently being determined in two ways in core activities:
# In the assignment module, the event priorities for group overrides are being determined from the 'sortorder' column.
# In the assignment module, the event priorities for group overrides are being determined from the 'sortorder' column in the 'assign_overrides' table.
# In the lesson and quiz modules, the event priorities for group overrides are being calculated using the functions lesson_get_group_override_priorities($lessonid) and quiz_get_group_override_priorities($quizid).
# In the lesson and quiz modules, the event priorities for group overrides are being calculated using the functions lesson_get_group_override_priorities($lessonid) and quiz_get_group_override_priorities($quizid).



Revision as of 05:23, 12 May 2017

Moodle 3.3


This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see Calendar_API_old.

The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users' dashboard.

Overview

The Moodle Calendar collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.

The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.

Creating an event

Creating a new calendar event.

require_once($CFG->dirroot.'/calendar/lib.php');

$event = new stdClass(); $event->eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event. $event->type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview. $event->name = get_string('calendarstart', 'scorm', $scorm->name); $event->description = format_module_intro('scorm', $scorm, $cmid); $event->courseid = $scorm->course; $event->groupid = 0; $event->userid = 0; $event->modulename = 'scorm'; $event->instance = $scorm->id; $event->timestart = $scorm->timeopen; $event->visible = instance_is_visible('scorm', $scorm); $event->timeduration = 0;

calendar_event::create($event);

Updating an event

You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user's capability to edit/add events. By default the $checkcapability parameter is set to true.

$eventid = required_param('id', PARAM_INT); $event = calendar_event::load($eventid);

$data = $mform->get_data(); $event->update($data);

Deleting an event

You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event's editor context.

$eventid = required_param('id', PARAM_INT); $event = calendar_event::load($eventid); $event->delete($repeats);

Event priority

There might be cases that an activity event will have user and/or group overrides. Therefore we need a way to show only the relevant event on the user's calendar. This is where the 'priority' field comes in.

The event priority is set to the following:

  • NULL for non-override events.

$event->priority = null;

  • 0 for user override events.

$event->priority = CALENDAR_EVENT_USER_OVERRIDE_PRIORITY;

  • A positive integer for group events.

For integer and non-null event priorities, the lower the value, the higher the priority is. Meaning, user overrides always have a higher priority than group overrides. Group override priorities are currently being determined in two ways in core activities:

  1. In the assignment module, the event priorities for group overrides are being determined from the 'sortorder' column in the 'assign_overrides' table.
  2. In the lesson and quiz modules, the event priorities for group overrides are being calculated using the functions lesson_get_group_override_priorities($lessonid) and quiz_get_group_override_priorities($quizid).

Should you ever decide to sort out group override priorities by implementing *_get_group_override_priorities(), the recommended return structure would be something like [

   'youreventtype1' => $prioritiesforeventtype1, 
   ...

] where '$prioritiesforeventtype1' is an associative array that has the timestamp of the group override event as key and the calculated priority as value. For more details, please see the implementation for the lesson module below: /**

* Calculates the priorities of timeopen and timeclose values for group overrides for a lesson.
*
* @param int $lessonid The lesson ID.
* @return array|null Array of group override priorities for open and close times. Null if there are no group overrides.
*/

function lesson_get_group_override_priorities($lessonid) {

   global $DB;
   // Fetch group overrides.
   $where = 'lessonid = :lessonid AND groupid IS NOT NULL';
   $params = ['lessonid' => $lessonid];
   $overrides = $DB->get_records_select('lesson_overrides', $where, $params, , 'id, groupid, available, deadline');
   if (!$overrides) {
       return null;
   }
   $grouptimeopen = [];
   $grouptimeclose = [];
   foreach ($overrides as $override) {
       if ($override->available !== null && !in_array($override->available, $grouptimeopen)) {
           $grouptimeopen[] = $override->available;
       }
       if ($override->deadline !== null && !in_array($override->deadline, $grouptimeclose)) {
           $grouptimeclose[] = $override->deadline;
       }
   }
   // Sort open times in ascending manner. The earlier open time gets higher priority.
   sort($grouptimeopen);
   // Set priorities.
   $opengrouppriorities = [];
   $openpriority = 1;
   foreach ($grouptimeopen as $timeopen) {
       $opengrouppriorities[$timeopen] = $openpriority++;
   }
   // Sort close times in descending manner. The later close time gets higher priority.
   rsort($grouptimeclose);
   // Set priorities.
   $closegrouppriorities = [];
   $closepriority = 1;
   foreach ($grouptimeclose as $timeclose) {
       $closegrouppriorities[$timeclose] = $closepriority++;
   }
   return [
       'open' => $opengrouppriorities,
       'close' => $closegrouppriorities
   ];

}

Action events

Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users' dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the 'timesort' field (unixtime) for the event.

Example of the changes to the above code would be to change the 'type' and to specify the 'timesort' value.

$event->type = CALENDAR_EVENT_TYPE_ACTION; $event->timesort = $scorm->timeclose;

my overview sam student.png

The callbacks

There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.

mod_xyz_core_calendar_is_event_visible()

This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.

/**

* Is the event visible?
*
* This is used to determine global visibility of an event in all places throughout Moodle. For example,
* the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and
* ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.
*
* @param calendar_event $event
* @return bool Returns true if the event is visible to the current user, false otherwise.
*/

function mod_assign_core_calendar_is_event_visible(calendar_event $event) {

   global $CFG, $USER;
   require_once($CFG->dirroot . '/mod/assign/locallib.php');
   $cm = get_fast_modinfo($event->courseid)->instances['assign'][$event->instance];
   $context = context_module::instance($cm->id);
   $assign = new assign($context, $cm, null);
   if ($event->eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {
       return $assign->can_grade();
   } else {
       return !$assign->can_grade() && $assign->can_view_submission($USER->id);
   }

}

mod_xyz_core_calendar_provide_event_action()

This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.

Eg. function mod_scorm_core_calendar_provide_event_action(calendar_event $event,

       \core_calendar\action_factory $factory) {
   global $CFG;
   require_once($CFG->dirroot . '/mod/scorm/locallib.php');
   $cm = get_fast_modinfo($event->courseid)->instances['scorm'][$event->instance];
   if (!empty($cm->customdata['timeclose']) && $cm->customdata['timeclose'] < time()) {
       // The scorm has closed so the user can no longer submit anything.
       return null;
   }
   // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.
   $customdata = $cm->customdata ?: [];
   $customdata['id'] = $cm->instance;
   $scorm = (object)($customdata + ['timeclose' => 0, 'timeopen' => 0]);
   // Check that the SCORM activity is open.
   list($actionable, $warnings) = scorm_get_availability_status($scorm);
   return $factory->create_instance(
       get_string('enter', 'scorm'),
       new \moodle_url('/mod/scorm/view.php', array('id' => $cm->id)),
       1,
       $actionable
   );

}
The variables to pass to create_instance() are -

  1. $name String The name of the event, eg. get_string('dosomething', 'mod_xyz').
  2. $url \moodle_url The URL the user visits in order to perform this action.
  3. $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.
  4. $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.

mod_xyz_core_calendar_event_action_shows_item_count()

This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of '1' (eg. Submitting an assignment) and there is no need display the item count.

Eg.

/**

* Callback function that determines whether an action event should be showing its item count
* based on the event type and the item count.
*
* @param calendar_event $event The calendar event.
* @param int $itemcount The item count associated with the action event.
* @return bool
*/

function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {

   // List of event types where the action event's item count should be shown.
   $eventtypesshowingitemcount = [
       ASSIGN_EVENT_TYPE_GRADINGDUE
   ];
   // For mod_assign, item count should be shown if the event type is 'gradingdue' and there is one or more item count.
   return in_array($event->eventtype, $eventtypesshowingitemcount) && $itemcount > 0;

}

Refreshing calendar events of activity modules

A new ad-hoc task 'refresh_mod_calendar_events_task' has been created. This task basically loops through all of the activity modules that implement the '*_refresh_events()' hook.

Sample usage: // Create the instance. $refreshtask = new refresh_mod_calendar_events_task();

// Add custom data. $customdata = [

   'plugins' => ['assign', 'lesson', 'quiz'] // Optional. If not specified, it will refresh the events of all of the activity modules.

]; $refreshtask->set_custom_data($customdata);

// Queue it. \core\task\manager::queue_adhoc_task($refreshtask);

Changes to Behat

The "And I follow "Course1"" Behat step won't work from the Dashboard anymore and has been replaced with "And I am on "Course 1" course homepage" where 'Course 1' is the fullname of the course.