MDL-57730 core_calendar: Action interface aware of actionability
[moodle.git] / calendar / classes / local / event / data_access / event_vault.php
CommitLineData
84d865d6
RW
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/**
18 * Event vault class
19 *
20 * @package core_calendar
21 * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25namespace core_calendar\local\event\data_access;
26
27use core_calendar\local\event\exceptions\limit_invalid_parameter_exception;
28use core_calendar\local\event\exceptions\timesort_invalid_parameter_exception;
29use core_calendar\local\interfaces\action_event_interface;
30use core_calendar\local\interfaces\event_interface;
31use core_calendar\local\interfaces\event_factory_interface;
32use core_calendar\local\interfaces\event_vault_interface;
33
34/**
35 * This class will handle interacting with the database layer to retrieve
36 * the records. This is required to house the complex logic required for
37 * pagination because it's not a one-to-one mapping between database records
38 * and users.
39 *
40 * This is a repository. It's called a vault to reduce confusion because
41 * Moodle has already taken the name repository. Vault is cooler anyway.
42 *
43 * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 */
46class event_vault implements event_vault_interface {
47
48 private $factory;
49
50 /**
51 * Create an event vault.
52 *
53 * @param event_factory_interface $factory An event factory
54 */
55 public function __construct(event_factory_interface $factory) {
56 $this->factory = $factory;
57 }
58
59 /**
60 * Retrieve an event for the given id.
61 *
62 * @param in $id The event id
63 * @return event_interface
64 */
65 public function get_event_by_id(int $id) {
66 global $DB;
67
68 if ($record = $DB->get_record('event', ['id' => $id])) {
69 return $this->transform_from_database_record($record);
70 } else {
71 return false;
72 }
73 }
74
75 /**
76 * Retrieve an array of events for the given user and time constraints.
77 *
78 * @param \stdClass $user The user for whom the events belong
79 * @param int|null $timesortfrom Events with timesort from this value (inclusive)
80 * @param int|null $timesortto Events with timesort until this value (inclusive)
81 * @param event_interface|null $afterevent Only return events after this one
82 * @param int $limitnum Return at most this number of events
83 * @return action_event_interface
84 */
85 public function get_action_events_by_timesort(
86 \stdClass $user,
87 int $timesortfrom = null,
88 int $timesortto = null,
89 event_interface $afterevent = null,
90 int $limitnum = 20
91 ) {
92 global $DB;
93
94 if (is_null($timesortfrom) && is_null($timesortto)) {
95 throw new timesort_invalid_parameter_exception("Must provide a timesort to and/or from value");
96 }
97
98 if ($limitnum < 1 || $limitnum > 50) {
99 throw new limit_invalid_parameter_exception("Limit must be between 1 and 50 (inclusive)");
100 }
101
102 $params = ['type' => CALENDAR_EVENT_TYPE_ACTION];
103 $where = ['type = :type'];
104
105 if ($timesortfrom) {
106 $where[] = 'timesort >= :timesortfrom';
107 $params['timesortfrom'] = $timesortfrom;
108 }
109
110 if ($timesortto) {
111 $where[] = 'timesort <= :timesortto';
112 $params['timesortto'] = $timesortto;
113 }
114
115 if (!is_null($afterevent)) {
116 $where[] = 'id > :id';
117 $params['id'] = $afterevent->get_id();
118 }
119
120 $sql = sprintf("SELECT * FROM {event} WHERE %s ORDER BY timesort ASC, id ASC",
121 implode(' AND ', $where));
122
123 $offset = 0;
124 $events = [];
125 // We need to continue to pull records from the database until we reach
126 // the requested amount of events because not all records in the database
127 // will be visible for the current user.
128 while ($records = array_values($DB->get_records_sql($sql, $params, $offset, $limitnum))) {
129 foreach ($records as $record) {
130 if ($event = $this->transform_from_database_record($record)) {
131 if ($event instanceof action_event_interface) {
132 $events[] = $event;
133 }
134
135 if (count($events) == $limitnum) {
136 // We've got all of the events so break both loops.
137 break 2;
138 }
139 }
140 }
141
142 $offset += $limitnum;
143 }
144
145 return $events;
146 }
147
148 /**
149 * Create an event from a database record.
150 *
151 * @param \stdClass $record The database record
152 * @return event_interface|false
153 */
154 private function transform_from_database_record(\stdClass $record) {
155 return $this->factory->create_instance($record);
156 }
157
158 /**
159 * Create an array of events from an array of database records.
160 *
161 * @param array $records The database records
162 * @return array
163 */
164 private function transform_from_database_records(array $records) {
165 $events = [];
166 foreach ($records as $record) {
167 if ($event = $this->transform_from_database_record($record)) {
168 $events[] = $event;
169 }
170 }
171
172 return $events;
173 }
174}