Part of MDL-55611 epic.
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains event class for displaying a calendar event's action.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core\external\exporter;
+use \core_calendar\local\interfaces\action_interface;
+
+/**
+ * Class for displaying a calendar event's action.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class event_action_exporter extends exporter {
+
+ /**
+ * Constructor.
+ *
+ * @param action_interface $action
+ */
+ public function __construct(action_interface $action, $related = []) {
+ $data = new \stdClass();
+ $data->name = $action->get_name();
+ $data->url = $action->get_url()->out(true);
+ $data->itemcount = $action->get_item_count();
+
+ parent::__construct($data, $related);
+ }
+
+ /**
+ * Return the list of properties.
+ *
+ * @return array
+ */
+ protected static function define_properties() {
+ return [
+ 'name' => ['type' => PARAM_TEXT],
+ 'url' => ['type' => PARAM_URL],
+ 'itemcount' => ['type' => PARAM_INT],
+ ];
+ }
+
+ /**
+ * Returns a list of objects that are related.
+ *
+ * @return array
+ */
+ protected static function define_related() {
+ return [
+ 'context' => 'context',
+ ];
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains event class for displaying a calendar event.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core\external\exporter;
+use \core_calendar\local\interfaces\event_interface;
+use \core_calendar\local\interfaces\action_event_interface;
+use \core_course\external\course_summary_exporter;
+use \renderer_base;
+
+/**
+ * Class for displaying a calendar event.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class event_exporter extends exporter {
+
+ /**
+ * @var event_interface $event
+ */
+ protected $event;
+
+ /**
+ * Constructor.
+ *
+ * @param event_interface $event
+ */
+ public function __construct(event_interface $event, $related = []) {
+ $this->event = $event;
+
+ $starttimestamp = $event->get_times()->get_start_time()->getTimestamp();
+ $endtimestamp = $event->get_times()->get_end_time()->getTimestamp();
+ $groupid = $event->get_group() ? $event->get_group()->get('id') : null;
+ $userid = $event->get_user() ? $event->get_user()->get('id') : null;
+
+ $data = new \stdClass();
+ $data->id = $event->get_id();
+ $data->name = $event->get_name();
+ $data->description = $event->get_description()->get_value();
+ $data->descriptionformat = $event->get_description()->get_format();
+ $data->groupid = $groupid;
+ $data->userid = $userid;
+ $data->eventtype = $event->get_type();
+ $data->timestart = $starttimestamp;
+ $data->timeduration = $endtimestamp - $starttimestamp;
+ $data->timesort = $event->get_times()->get_sort_time()->getTimestamp();
+ $data->visible = $event->is_visible();
+ $data->timemodified = $event->get_times()->get_modified_time()->getTimestamp();
+
+ if ($repeats = $event->get_repeats()) {
+ $data->repeatid = $repeats->get_id();
+ }
+
+ if ($cm = $event->get_course_module()) {
+ $data->modulename = $cm->get('modname');
+ $data->instance = $cm->get('id');
+ }
+
+ parent::__construct($data, $related);
+ }
+
+ /**
+ * Return the list of properties.
+ *
+ * @return array
+ */
+ protected static function define_properties() {
+ return [
+ 'id' => ['type' => PARAM_INT],
+ 'name' => ['type' => PARAM_TEXT],
+ 'description' => [
+ 'type' => PARAM_RAW,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'descriptionformat' => [
+ 'type' => PARAM_INT,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'groupid' => [
+ 'type' => PARAM_INT,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'userid' => [
+ 'type' => PARAM_INT,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'repeatid' => [
+ 'type' => PARAM_INT,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'modulename' => [
+ 'type' => PARAM_TEXT,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'instance' => [
+ 'type' => PARAM_INT,
+ 'optional' => true,
+ 'default' => null,
+ 'null' => NULL_ALLOWED
+ ],
+ 'eventtype' => ['type' => PARAM_TEXT],
+ 'timestart' => ['type' => PARAM_INT],
+ 'timeduration' => ['type' => PARAM_INT],
+ 'timesort' => ['type' => PARAM_INT],
+ 'visible' => ['type' => PARAM_INT],
+ 'timemodified' => ['type' => PARAM_INT],
+ ];
+ }
+
+ /**
+ * Return the list of additional properties.
+ *
+ * @return array
+ */
+ protected static function define_other_properties() {
+ return [
+ 'url' => ['type' => PARAM_URL],
+ 'enddate' => ['type' => PARAM_TEXT],
+ 'icon' => [
+ 'type' => event_icon_exporter::read_properties_definition(),
+ ],
+ 'action' => [
+ 'type' => event_action_exporter::read_properties_definition(),
+ 'optional' => true,
+ ],
+ 'course' => [
+ 'type' => course_summary_exporter::read_properties_definition(),
+ 'optional' => true,
+ ]
+ ];
+ }
+
+ /**
+ * Get the additional values to inject while exporting.
+ *
+ * @param renderer_base $output The renderer.
+ * @return array Keys are the property names, values are their values.
+ */
+ protected function get_other_values(renderer_base $output) {
+ $values = [];
+ $event = $this->event;
+ $context = $this->related['context'];
+ $modulename = $event->get_course_module()->get('modname');
+ $moduleid = $event->get_course_module()->get('id');
+ $timesort = $event->get_times()->get_sort_time()->getTimestamp();
+ $url = new \moodle_url(sprintf('/mod/%s/view.php', $modulename), ['id' => $moduleid]);
+ $iconexporter = new event_icon_exporter($event, ['context' => $context]);
+
+ $values['url'] = $url->out(false);
+ $values['enddate'] = userdate($timesort, get_string('strftimerecent'));
+ $values['icon'] = $iconexporter->export($output);
+
+ if ($event instanceof action_event_interface) {
+ $actionexporter = new event_action_exporter($event->get_action(),
+ ['context' => $context]);
+ $values['action'] = $actionexporter->export($output);
+ }
+
+ if ($course = $this->related['course']) {
+ $coursesummaryexporter = new course_summary_exporter($course, ['context' => $context]);
+ $values['course'] = $coursesummaryexporter->export($output);
+ }
+
+ return $values;
+ }
+
+ /**
+ * Returns a list of objects that are related.
+ *
+ * @return array
+ */
+ protected static function define_related() {
+ return [
+ 'context' => 'context',
+ 'course' => 'stdClass?',
+ ];
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains event class for displaying a calendar event's icon.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core\external\exporter;
+use \core_calendar\local\interfaces\event_interface;
+
+/**
+ * Class for displaying a calendar event's icon.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class event_icon_exporter extends exporter {
+
+ /**
+ * Constructor.
+ *
+ * @param event_interface $event
+ */
+ public function __construct(event_interface $event, $related = []) {
+ $coursemodule = $event->get_course_module();
+ $course = $event->get_course();
+ $courseid = $course ? $course->get('id') : null;
+ $group = $event->get_group();
+ $groupid = $group ? $group->get('id') : null;
+ $user = $event->get_user();
+ $userid = $user ? $user->get('id') : null;
+ $isactivityevent = !empty($coursemodule);
+ $isglobalevent = ($course && $courseid == SITEID);
+ $iscourseevent = ($course && !empty($courseid) && $courseid != SITEID && $group && empty($groupid));
+ $isgroupevent = ($group && !empty($groupid));
+ $isuserevent = ($user && !empty($userid));
+
+ if ($isactivityevent) {
+ $key = 'icon';
+ $component = $coursemodule->get('modname');
+
+ if (get_string_manager()->string_exists($event->get_type(), $component)) {
+ $alttext = get_string($event->get_type(), $component);
+ } else {
+ $alttext = get_string('activityevent', 'calendar');
+ }
+ } else if ($isglobalevent) {
+ $key = 'i/siteevent';
+ $component = 'core';
+ $alttext = get_string('globalevent', 'calendar');
+ } else if ($iscourseevent) {
+ $key = 'i/courseevent';
+ $component = 'core';
+ $alttext = get_string('courseevent', 'calendar');
+ } else if ($isgroupevent) {
+ $key = 'i/groupevent';
+ $component = 'core';
+ $alttext = get_string('groupevent', 'calendar');
+ } else if ($isuserevent) {
+ $key = 'i/userevent';
+ $component = 'core';
+ $alttext = get_string('userevent', 'calendar');
+ } else {
+ // Default to site event icon?
+ $key = 'i/siteevent';
+ $component = 'core';
+ $alttext = get_string('globalevent', 'calendar');
+ }
+
+ $data = new \stdClass();
+ $data->key = $key;
+ $data->component = $component;
+ $data->alttext = $alttext;
+
+ parent::__construct($data, $related);
+ }
+
+ /**
+ * Return the list of properties.
+ *
+ * @return array
+ */
+ protected static function define_properties() {
+ return [
+ 'key' => ['type' => PARAM_TEXT],
+ 'component' => ['type' => PARAM_TEXT],
+ 'alttext' => ['type' => PARAM_TEXT],
+ ];
+ }
+
+ /**
+ * Returns a list of objects that are related.
+ *
+ * @return array
+ */
+ protected static function define_related() {
+ return [
+ 'context' => 'context',
+ ];
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains event class for displaying a list of calendar events.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core\external\exporter;
+use \renderer_base;
+
+/**
+ * Class for displaying a list of calendar events.
+ *
+ * This class uses the events relateds cache in order to get the related
+ * data for exporting an event without having to naively hit the database
+ * for each event.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class events_exporter extends exporter {
+
+ /**
+ * @var array $events An array of event_interface objects.
+ */
+ protected $events;
+
+ /**
+ * Constructor.
+ *
+ * @param array $events An array of event_interface objects
+ * @param array $related An array of related objects
+ */
+ public function __construct(array $events, $related = []) {
+ $this->events = $events;
+ parent::__construct([], $related);
+ }
+
+ /**
+ * Return the list of additional properties.
+ *
+ * @return array
+ */
+ protected static function define_other_properties() {
+ return [
+ 'events' => [
+ 'type' => event_exporter::read_properties_definition(),
+ 'multiple' => true,
+ ],
+ 'firstid' => [
+ 'type' => PARAM_INT,
+ 'null' => NULL_ALLOWED,
+ 'default' => null,
+ ],
+ 'lastid' => [
+ 'type' => PARAM_INT,
+ 'null' => NULL_ALLOWED,
+ 'default' => null,
+ ],
+ ];
+ }
+
+ /**
+ * Get the additional values to inject while exporting.
+ *
+ * @param renderer_base $output The renderer.
+ * @return array Keys are the property names, values are their values.
+ */
+ protected function get_other_values(renderer_base $output) {
+ $return = [];
+ $cache = $this->related['cache'];
+
+ $return['events'] = array_map(function($event) use ($cache, $output) {
+ $context = $cache->get_context($event);
+ $course = $cache->get_course($event);
+ $exporter = new event_exporter($event, ['context' => $context, 'course' => $course]);
+
+ return $exporter->export($output);
+ }, $this->events);
+
+ if ($count = count($return['events'])) {
+ $return['firstid'] = $return['events'][0]->id;
+ $return['lastid'] = $return['events'][$count - 1]->id;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Returns a list of objects that are related.
+ *
+ * @return array
+ */
+ protected static function define_related() {
+ return [
+ 'cache' => 'core_calendar\external\events_related_objects_cache',
+ ];
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains event class for providing the related objects when exporting
+ * a list of calendar events.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_calendar\local\interfaces\event_interface;
+
+/**
+ * Class to providing the related objects when exporting
+ * a list of calendar events.
+ *
+ * This class is only meant for use with exporters. It attempts to bulk load
+ * the related objects for a list of events and cache them to avoid having
+ * to query the database when exporting each individual event.
+ *
+ * @package core_calendar
+ * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class events_related_objects_cache {
+
+ /**
+ * @var array $events The events for which we need related objects.
+ */
+ protected $events;
+
+ /**
+ * @var array $courses The related courses.
+ */
+ protected $courses = null;
+
+ /**
+ * @var array $events The related groups.
+ */
+ protected $groups = null;
+
+ /**
+ * @var array $events The related course modules.
+ */
+ protected $coursemodules = [];
+
+ /**
+ * Constructor.
+ *
+ * @param array $event Array of event_interface events
+ */
+ public function __construct(array $events) {
+ $this->events = $events;
+ }
+
+ /**
+ * Get the related course object for a given event.
+ *
+ * @param event_interface $event.
+ * @return stdClass|null
+ */
+ public function get_course(event_interface $event) {
+ if (is_null($this->courses)) {
+ $this->load_courses();
+ }
+
+ if ($course = $event->get_course()) {
+ $courseid = $course->get('id');
+ return isset($this->courses[$courseid]) ? $this->courses[$courseid] : null;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the related context for a given event.
+ *
+ * @param event_interface $event.
+ * @return context|null
+ */
+ public function get_context(event_interface $event) {
+ global $USER;
+
+ $courseid = $event->get_course() ? $event->get_course()->get('id') : null;
+ $groupid = $event->get_group() ? $event->get_group()->get('id') : null;
+ $userid = $event->get_user() ? $event->get_user()->get('id') : null;
+ $moduleid = $event->get_course_module() ? $event->get_course_module()->get('id') : null;
+
+ if (!empty($courseid)) {
+ return \context_course::instance($event->get_course()->get('id'));
+ } else if (!empty($groupid)) {
+ $group = $this->get_group($event);
+ return \context_course::instance($group->courseid);
+ } else if (!empty($userid) && $userid == $USER->id) {
+ return \context_user::instance($userid);
+ } else if (!empty($userid) && $userid != $USER->id && $moduleid && $moduleid > 0) {
+ $cm = $this->get_course_module($event);
+ return \context_course::instance($cm->course);
+ } else {
+ return \context_user::instance($userid);
+ }
+ }
+
+ /**
+ * Get the related group object for a given event.
+ *
+ * @param event_interface $event.
+ * @return stdClass|null
+ */
+ public function get_group(event_interface $event) {
+ if (is_null($this->groups)) {
+ $this->load_groups();
+ }
+
+ if ($group = $event->get_group()) {
+ $groupid = $group->get('id');
+ return isset($this->groups[$groupid]) ? $this->groups[$groupid] : null;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the related course module for a given event.
+ *
+ * @param event_interface $event.
+ * @return stdClass|null
+ */
+ public function get_course_module(event_interface $event) {
+ if (!$event->get_course_module()) {
+ return null;
+ }
+
+ $id = $event->get_course_module()->get('id');
+ $name = $event->get_course_module()->get('modname');
+ $key = $name . '_' . $id;
+
+ if (!isset($this->coursemodules[$key])) {
+ $this->coursemodules[$key] = get_coursemodule_from_instance($name, $id, 0, false, MUST_EXIST);
+ }
+
+ return $this->coursemodules[$key];
+ }
+
+ /**
+ * Load the list of all of the distinct courses required for the
+ * list of provided events and save the result in memory.
+ */
+ protected function load_courses() {
+ global $DB;
+
+ $courseids = [];
+ foreach ($this->events as $event) {
+ if ($course = $event->get_course()) {
+ $id = $course->get('id');
+ $courseids[$id] = true;
+ }
+ }
+
+ if (empty($courseids)) {
+ $this->courses = [];
+ return;
+ }
+
+ list($idsql, $params) = $DB->get_in_or_equal(array_keys($courseids));
+ $sql = "SELECT * FROM {course} WHERE id {$idsql}";
+
+ $this->courses = $DB->get_records_sql($sql, $params);
+ }
+
+ /**
+ * Load the list of all of the distinct groups required for the
+ * list of provided events and save the result in memory.
+ */
+ protected function load_groups() {
+ global $DB;
+
+ $groupids = [];
+ foreach ($this->events as $event) {
+ if ($group = $event->get_group()) {
+ $id = $group->get('id');
+ $groupids[$id] = true;
+ }
+ }
+
+ if (empty($groupids)) {
+ $this->groups = [];
+ return;
+ }
+
+ list($idsql, $params) = $DB->get_in_or_equal(array_keys($groupids));
+ $sql = "SELECT * FROM {groups} WHERE id {$idsql}";
+
+ $this->groups = $DB->get_records_sql($sql, $params);
+ }
+}
$string['allday'] = 'All day';
$string['addevent'] = 'Add events';
$string['annually'] = 'Annually';
+$string['activityevent'] = 'Activity event';
$string['calendar'] = 'Calendar';
$string['calendarheading'] = '{$a} Calendar';
$string['calendarpreferences'] = 'Calendar preferences';