PageRenderTime 23ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/calendar/classes/external/calendar_event_exporter.php

https://gitlab.com/unofficial-mirrors/moodle
PHP | 329 lines | 193 code | 38 blank | 98 comment | 39 complexity | a01e41270db962fd93cae559e03e7d35 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Contains event class for displaying a calendar event.
  18. *
  19. * @package core_calendar
  20. * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace core_calendar\external;
  24. defined('MOODLE_INTERNAL') || die();
  25. use \core_calendar\local\event\container;
  26. use \core_course\external\course_summary_exporter;
  27. use \renderer_base;
  28. require_once($CFG->dirroot . '/course/lib.php');
  29. /**
  30. * Class for displaying a calendar event.
  31. *
  32. * @package core_calendar
  33. * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
  34. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35. */
  36. class calendar_event_exporter extends event_exporter_base {
  37. /**
  38. * Return the list of additional properties.
  39. *
  40. * @return array
  41. */
  42. protected static function define_other_properties() {
  43. $values = parent::define_other_properties();
  44. $values['url'] = ['type' => PARAM_URL];
  45. $values['islastday'] = [
  46. 'type' => PARAM_BOOL,
  47. 'default' => false,
  48. ];
  49. $values['calendareventtype'] = [
  50. 'type' => PARAM_TEXT,
  51. ];
  52. $values['popupname'] = [
  53. 'type' => PARAM_RAW,
  54. ];
  55. $values['mindaytimestamp'] = [
  56. 'type' => PARAM_INT,
  57. 'optional' => true
  58. ];
  59. $values['mindayerror'] = [
  60. 'type' => PARAM_TEXT,
  61. 'optional' => true
  62. ];
  63. $values['maxdaytimestamp'] = [
  64. 'type' => PARAM_INT,
  65. 'optional' => true
  66. ];
  67. $values['maxdayerror'] = [
  68. 'type' => PARAM_TEXT,
  69. 'optional' => true
  70. ];
  71. $values['draggable'] = [
  72. 'type' => PARAM_BOOL,
  73. 'default' => false
  74. ];
  75. return $values;
  76. }
  77. /**
  78. * Get the additional values to inject while exporting.
  79. *
  80. * @param renderer_base $output The renderer.
  81. * @return array Keys are the property names, values are their values.
  82. */
  83. protected function get_other_values(renderer_base $output) {
  84. global $CFG;
  85. $values = parent::get_other_values($output);
  86. $event = $this->event;
  87. $course = $this->related['course'];
  88. $hascourse = !empty($course);
  89. // By default all events that can be edited are
  90. // draggable.
  91. $values['draggable'] = $values['canedit'];
  92. if ($moduleproxy = $event->get_course_module()) {
  93. $modulename = $moduleproxy->get('modname');
  94. $moduleid = $moduleproxy->get('id');
  95. $url = new \moodle_url(sprintf('/mod/%s/view.php', $modulename), ['id' => $moduleid]);
  96. // Build edit event url for action events.
  97. $params = array('update' => $moduleid, 'return' => true, 'sesskey' => sesskey());
  98. $editurl = new \moodle_url('/course/mod.php', $params);
  99. $values['editurl'] = $editurl->out(false);
  100. } else if ($event->get_type() == 'category') {
  101. $url = $event->get_category()->get_proxied_instance()->get_view_link();
  102. } else {
  103. // TODO MDL-58866 We do not have any way to find urls for events outside of course modules.
  104. $url = course_get_url($hascourse ? $course : SITEID);
  105. }
  106. $values['url'] = $url->out(false);
  107. $values['islastday'] = false;
  108. $today = $this->related['type']->timestamp_to_date_array($this->related['today']);
  109. $values['popupname'] = $this->event->get_name();
  110. $times = $this->event->get_times();
  111. if ($duration = $times->get_duration()) {
  112. $enddate = $this->related['type']->timestamp_to_date_array($times->get_end_time()->getTimestamp());
  113. $values['islastday'] = true;
  114. $values['islastday'] = $values['islastday'] && $enddate['year'] == $today['year'];
  115. $values['islastday'] = $values['islastday'] && $enddate['mon'] == $today['mon'];
  116. $values['islastday'] = $values['islastday'] && $enddate['mday'] == $today['mday'];
  117. }
  118. $subscription = $this->event->get_subscription();
  119. if ($subscription && !empty($subscription->get('id')) && $CFG->calendar_showicalsource) {
  120. $a = (object) [
  121. 'name' => $values['popupname'],
  122. 'source' => $subscription->get('name'),
  123. ];
  124. $values['popupname'] = get_string('namewithsource', 'calendar', $a);
  125. } else {
  126. if ($values['islastday']) {
  127. $startdate = $this->related['type']->timestamp_to_date_array($times->get_start_time()->getTimestamp());
  128. $samedate = true;
  129. $samedate = $samedate && $startdate['mon'] == $enddate['mon'];
  130. $samedate = $samedate && $startdate['year'] == $enddate['year'];
  131. $samedate = $samedate && $startdate['mday'] == $enddate['mday'];
  132. if (!$samedate) {
  133. $values['popupname'] = get_string('eventendtimewrapped', 'calendar', $values['popupname']);
  134. }
  135. }
  136. }
  137. // Include category name into the event name, if applicable.
  138. $proxy = $this->event->get_category();
  139. if ($proxy && $proxy->get('id')) {
  140. $category = $proxy->get_proxied_instance();
  141. $eventnameparams = (object) [
  142. 'name' => $values['popupname'],
  143. 'category' => $category->get_formatted_name(),
  144. ];
  145. $values['popupname'] = get_string('eventnameandcategory', 'calendar', $eventnameparams);
  146. }
  147. // Include course's shortname into the event name, if applicable.
  148. if ($hascourse && $course->id !== SITEID) {
  149. $eventnameparams = (object) [
  150. 'name' => $values['popupname'],
  151. 'course' => $values['course']->shortname,
  152. ];
  153. $values['popupname'] = get_string('eventnameandcourse', 'calendar', $eventnameparams);
  154. }
  155. $values['calendareventtype'] = $this->get_calendar_event_type();
  156. if ($event->get_course_module()) {
  157. $values = array_merge($values, $this->get_module_timestamp_limits($event));
  158. }
  159. return $values;
  160. }
  161. /**
  162. * Returns a list of objects that are related.
  163. *
  164. * @return array
  165. */
  166. protected static function define_related() {
  167. $related = parent::define_related();
  168. $related['daylink'] = \moodle_url::class;
  169. $related['type'] = '\core_calendar\type_base';
  170. $related['today'] = 'int';
  171. $related['moduleinstance'] = 'stdClass?';
  172. return $related;
  173. }
  174. /**
  175. * Return the normalised event type.
  176. * Activity events are normalised to be course events.
  177. *
  178. * @return string
  179. */
  180. public function get_calendar_event_type() {
  181. if ($this->event->get_course_module()) {
  182. return 'course';
  183. }
  184. return $this->event->get_type();
  185. }
  186. /**
  187. * Return the set of minimum and maximum date timestamp values
  188. * for the given event.
  189. *
  190. * @param event_interface $event
  191. * @return array
  192. */
  193. protected function get_module_timestamp_limits($event) {
  194. $values = [];
  195. $mapper = container::get_event_mapper();
  196. $starttime = $event->get_times()->get_start_time();
  197. $modname = $event->get_course_module()->get('modname');
  198. $moduleinstance = $this->related['moduleinstance'];
  199. list($min, $max) = component_callback(
  200. 'mod_' . $modname,
  201. 'core_calendar_get_valid_event_timestart_range',
  202. [$mapper->from_event_to_legacy_event($event), $moduleinstance],
  203. [false, false]
  204. );
  205. // The callback will return false for either of the
  206. // min or max cutoffs to indicate that there are no
  207. // valid timestart values. In which case the event is
  208. // not draggable.
  209. if ($min === false || $max === false) {
  210. return ['draggable' => false];
  211. }
  212. if ($min) {
  213. $values = array_merge($values, $this->get_module_timestamp_min_limit($starttime, $min));
  214. }
  215. if ($max) {
  216. $values = array_merge($values, $this->get_module_timestamp_max_limit($starttime, $max));
  217. }
  218. return $values;
  219. }
  220. /**
  221. * Get the correct minimum midnight day limit based on the event start time
  222. * and the module's minimum timestamp limit.
  223. *
  224. * @param DateTimeInterface $starttime The event start time
  225. * @param array $min The module's minimum limit for the event
  226. */
  227. protected function get_module_timestamp_min_limit(\DateTimeInterface $starttime, $min) {
  228. // We need to check that the minimum valid time is earlier in the
  229. // day than the current event time so that if the user drags and drops
  230. // the event to this day (which changes the date but not the time) it
  231. // will result in a valid time start for the event.
  232. //
  233. // For example:
  234. // An event that starts on 2017-01-10 08:00 with a minimum cutoff
  235. // of 2017-01-05 09:00 means that 2017-01-05 is not a valid start day
  236. // for the drag and drop because it would result in the event start time
  237. // being set to 2017-01-05 08:00, which is invalid. Instead the minimum
  238. // valid start day would be 2017-01-06.
  239. $values = [];
  240. $timestamp = $min[0];
  241. $errorstring = $min[1];
  242. $mindate = (new \DateTimeImmutable())->setTimestamp($timestamp);
  243. $minstart = $mindate->setTime(
  244. $starttime->format('H'),
  245. $starttime->format('i'),
  246. $starttime->format('s')
  247. );
  248. $midnight = usergetmidnight($timestamp);
  249. if ($mindate <= $minstart) {
  250. $values['mindaytimestamp'] = $midnight;
  251. } else {
  252. $tomorrow = (new \DateTime())->setTimestamp($midnight)->modify('+1 day');
  253. $values['mindaytimestamp'] = $tomorrow->getTimestamp();
  254. }
  255. // Get the human readable error message to display if the min day
  256. // timestamp is violated.
  257. $values['mindayerror'] = $errorstring;
  258. return $values;
  259. }
  260. /**
  261. * Get the correct maximum midnight day limit based on the event start time
  262. * and the module's maximum timestamp limit.
  263. *
  264. * @param DateTimeInterface $starttime The event start time
  265. * @param array $max The module's maximum limit for the event
  266. */
  267. protected function get_module_timestamp_max_limit(\DateTimeInterface $starttime, $max) {
  268. // We're doing a similar calculation here as we are for the minimum
  269. // day timestamp. See the explanation above.
  270. $values;
  271. $timestamp = $max[0];
  272. $errorstring = $max[1];
  273. $maxdate = (new \DateTimeImmutable())->setTimestamp($timestamp);
  274. $maxstart = $maxdate->setTime(
  275. $starttime->format('H'),
  276. $starttime->format('i'),
  277. $starttime->format('s')
  278. );
  279. $midnight = usergetmidnight($timestamp);
  280. if ($maxdate >= $maxstart) {
  281. $values['maxdaytimestamp'] = $midnight;
  282. } else {
  283. $yesterday = (new \DateTime())->setTimestamp($midnight)->modify('-1 day');
  284. $values['maxdaytimestamp'] = $yesterday->getTimestamp();
  285. }
  286. // Get the human readable error message to display if the max day
  287. // timestamp is violated.
  288. $values['maxdayerror'] = $errorstring;
  289. return $values;
  290. }
  291. }