ILIAS  trunk Revision v13.0_alpha-52-g21c366bbdd4
class.ilBookingPreferencesManager.php
Go to the documentation of this file.
1<?php
2
24{
25 public const BOOKINGS_PER_USER_DEFAULT = 1;
26
28 protected ?int $current_time;
29 protected int $bookings_per_user;
31
32 public function __construct(
35 ?int $current_time = null,
36 int $bookings_per_user = self::BOOKINGS_PER_USER_DEFAULT
37 ) {
38 $this->current_time = ($current_time > 0)
40 : time();
41 $this->pool = $pool;
42 $this->bookings_per_user = $bookings_per_user;
43 $this->book_repo = $book_repo;
44 }
45
49 public function isGivingPreferencesPossible(): bool
50 {
51 return $this->pool->getScheduleType() === ilObjBookingPool::TYPE_NO_SCHEDULE_PREFERENCES &&
52 $this->pool->getPreferenceDeadline() > $this->current_time;
53 }
54
58 public function isPreferenceDeadlineReached(): bool
59 {
60 return $this->pool->getScheduleType() === ilObjBookingPool::TYPE_NO_SCHEDULE_PREFERENCES &&
61 $this->pool->getPreferenceDeadline() < $this->current_time;
62 }
63
71 public function storeBookings(
72 ilBookingPreferences $preferences,
73 ?array $booking_object_ids = null
74 ): void {
75 $bookings = $this->calculateBookings($preferences, $booking_object_ids);
76 $this->book_repo->storeBookings($this->pool->getId(), $bookings);
77 }
78
82 public function readBookings(): array
83 {
84 $booking_object_ids = array_map(static function ($i) {
85 return $i["booking_object_id"];
86 }, ilBookingObject::getList($this->pool->getId()));
87 return $this->book_repo->getBookings($booking_object_ids);
88 }
89
95 public function calculateBookings(
96 ilBookingPreferences $preferences,
97 ?array $booking_object_ids = null,
98 ?array $availability = null
99 ): array {
100 $preferences = $preferences->getPreferences();
101
102 // we calculate if a) any preferences are given and b) the deadline is reached
103 /*if (!is_array($preferences) || count($preferences) == 0) {
104 throw new ilBookingCalculationException("No preferences given.");
105 }*/
106 if (!$this->isPreferenceDeadlineReached()) {
107 throw new ilBookingCalculationException("Preference deadline not reached.");
108 }
109
110 if ($booking_object_ids === null) {
111 $booking_object_ids = array_map(function ($i) {
112 return $i["booking_object_id"];
113 }, ilBookingObject::getList($this->pool->getId()));
114 }
115
116 if ($availability === null) {
117 $availability = [];
118 foreach ($booking_object_ids as $book_obj_id) {
119 $availability[$book_obj_id] = ilBookingReservation::getNumAvailablesNoSchedule($book_obj_id);
120 }
121 }
122
123 // remove all objects from the preferences
124 // that are already not available anymore
125 // see bug 30204 (a tutor booked an object already before and made it unavailable)
126 foreach ($availability as $book_obj_id => $cnt) {
127 if ($cnt == 0) {
128 $preferences = $this->removeObjectFromPreferences($book_obj_id, $preferences);
129 }
130 }
131
132 $bookings = [];
133
134 $end_phase_one = false;
135
136 // phase one: assign lowest popular items to random user
137 while (!$end_phase_one) {
138 $popularity = $this->calculatePopularity($booking_object_ids, $preferences);
139 $low_pop_book_obj_id = $this->getObjectWithLowestPopularity($popularity, $availability);
140 if ($low_pop_book_obj_id > 0) {
141 $user_ids = $this->getUsersForObject($preferences, $low_pop_book_obj_id);
142 if (count($user_ids) > 0) {
143 $user_id = $this->selectRandomEntry($user_ids);
144 $this->addBooking($bookings, $preferences, $availability, $user_id, $low_pop_book_obj_id);
145 }
146 } else {
147 $end_phase_one = true;
148 }
149 }
150
151 $end_phase_two = false;
152
153 // choose random user from and assign currently rarely assigned objects
154 while (!$end_phase_two) {
155 $random_user_id = $this->chooseRandomUserFromPreferences($preferences);
156 if ($random_user_id > 0) {
157 $rare_assigned_book_obj_id = $this->getMinimalAssignedEntryForUser($booking_object_ids, $bookings, $preferences[$random_user_id], $availability);
158 if ($rare_assigned_book_obj_id > 0) {
159 $this->addBooking($bookings, $preferences, $availability, $random_user_id, $rare_assigned_book_obj_id);
160 } else {
161 $preferences = $this->removeUserFromPreferences($random_user_id, $preferences);
162 }
163 } else {
164 $end_phase_two = true;
165 }
166 }
167 return $bookings;
168 }
169
170 protected function addBooking(
171 array &$bookings,
172 array &$preferences,
173 array &$availability,
174 int $user_id,
175 int $book_obj_id
176 ): void {
177 $bookings[$user_id][] = $book_obj_id;
178 $availability[$book_obj_id]--;
179 if (count($bookings[$user_id]) >= $this->bookings_per_user) {
180 $preferences = $this->removeUserFromPreferences($user_id, $preferences);
181 } else {
182 $preferences = $this->removePreference($user_id, $book_obj_id, $preferences);
183 }
184 if ($availability[$book_obj_id] <= 0) {
185 $preferences = $this->removeObjectFromPreferences($book_obj_id, $preferences);
186 }
187 }
188
193 protected function selectRandomEntry(array $items)
194 {
195 return $items[array_rand($items)];
196 }
197
198
203 protected function getUsersForObject(
204 array $preferences,
205 int $sel_obj_id
206 ): array {
207 $user_ids = [];
208 foreach ($preferences as $user_id => $obj_ids) {
209 foreach ($obj_ids as $obj_id) {
210 if ((int) $obj_id === $sel_obj_id) {
211 $user_ids[] = (int) $user_id;
212 }
213 }
214 }
215 return $user_ids;
216 }
217
218
222 protected function calculatePopularity(array $booking_object_ids, array $preferences): array
223 {
224 $popularity = [];
225 foreach ($booking_object_ids as $book_obj_id) {
226 $popularity[$book_obj_id] = 0;
227 }
228
229 foreach ($preferences as $bobj_ids) {
230 foreach ($bobj_ids as $bobj_id) {
231 if (!isset($popularity[$bobj_id])) {
232 continue;
233 }
234
235 ++$popularity[$bobj_id];
236 }
237 }
238
239 return $popularity;
240 }
241
242
247 array $popularity,
248 array $availability
249 ): int {
250 asort($popularity, SORT_NUMERIC);
251 foreach ($popularity as $obj_id => $pop) {
252 if ($pop > 0 && $availability[$obj_id] > 0) {
253 return (int) $obj_id;
254 }
255 }
256 return 0;
257 }
258
262 protected function removePreference(
263 int $user_id,
264 int $obj_id,
265 array $preferences
266 ): array {
267 if (is_array($preferences[$user_id])) {
268 $preferences[$user_id] = array_filter($preferences[$user_id], static function ($i) use ($obj_id) {
269 return ($i !== $obj_id);
270 });
271 }
272 return $preferences;
273 }
274
278 protected function removeObjectFromPreferences(
279 int $obj_id,
280 array $preferences
281 ): array {
282 $new_preferences = [];
283 foreach ($preferences as $user_id => $obj_ids) {
284 $new_preferences[$user_id] = array_filter($obj_ids, static function ($i) use ($obj_id) {
285 return ($i !== $obj_id);
286 });
287 }
288 return $new_preferences;
289 }
290
294 protected function removeUserFromPreferences(
295 int $user_id,
296 array $preferences
297 ): array {
298 if (is_array($preferences[$user_id])) {
299 unset($preferences[$user_id]);
300 }
301 return $preferences;
302 }
303
308 array $preferences
309 ): ?int {
310 if (count($preferences) === 0) {
311 return null;
312 }
313 $user_ids = array_keys($preferences);
314 return $this->selectRandomEntry($user_ids);
315 }
316
328 array $booking_object_ids,
329 array $bookings,
330 array $user_preferences,
331 array $availability
332 ): int {
333 // count the assignments per object
334 $count_assignments = [];
335 foreach ($booking_object_ids as $obj_id) {
336 $count_assignments[$obj_id] = 0;
337 }
338 foreach ($bookings as $user => $obj_ids) {
339 foreach ($obj_ids as $obj_id) {
340 $count_assignments[$obj_id]++;
341 }
342 }
343
344 // sort the objects by number of assignments, return the first one being found in the user preferences
345 asort($count_assignments, SORT_NUMERIC);
346 foreach ($count_assignments as $obj_id => $cnt) {
347 // if no preferences left for user, even assign object outside preferences
348 // otherwise choose object from preferences
349 if ($availability[$obj_id] > 0 && (count($user_preferences) === 0 || in_array($obj_id, $user_preferences))) {
350 return (int) $obj_id;
351 }
352 }
353 return 0;
354 }
355
356 public function hasRun(): bool
357 {
358 return $this->book_repo->hasRun($this->pool->getId());
359 }
360
361 public function resetRun(): void
362 {
363 $this->book_repo->resetRun($this->pool->getId());
364 }
365}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getList(int $a_pool_id, ?string $a_title=null)
Get list of booking objects.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
addBooking(array &$bookings, array &$preferences, array &$availability, int $user_id, int $book_obj_id)
getObjectWithLowestPopularity(array $popularity, array $availability)
Get an availabe object with lowest popularity > 0.
isPreferenceDeadlineReached()
Can participants hand in preferences.
removeUserFromPreferences(int $user_id, array $preferences)
Remove user from preference array.
__construct(ilObjBookingPool $pool, ilBookingPrefBasedBookGatewayRepository $book_repo, ?int $current_time=null, int $bookings_per_user=self::BOOKINGS_PER_USER_DEFAULT)
ilBookingPrefBasedBookGatewayRepository $book_repo
getMinimalAssignedEntryForUser(array $booking_object_ids, array $bookings, array $user_preferences, array $availability)
Get an available object within the preferences (if no preferences left, even outside of preferences) ...
calculatePopularity(array $booking_object_ids, array $preferences)
Calculate popularity (number of preferences each object got from users)
isGivingPreferencesPossible()
Can participants hand in preferences.
calculateBookings(ilBookingPreferences $preferences, ?array $booking_object_ids=null, ?array $availability=null)
Calculate bookings.
getUsersForObject(array $preferences, int $sel_obj_id)
Get users for object.
storeBookings(ilBookingPreferences $preferences, ?array $booking_object_ids=null)
Calculate and store bookings.
removePreference(int $user_id, int $obj_id, array $preferences)
Remove a preference from the preference array.
chooseRandomUserFromPreferences(array $preferences)
Choose random user from the preference array.
selectRandomEntry(array $items)
Select a random entry of an array.
removeObjectFromPreferences(int $obj_id, array $preferences)
Remove an object from the preference array.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getNumAvailablesNoSchedule(int $a_obj_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
if(!file_exists('../ilias.ini.php'))