Files
Reservair/includes/Services/RsvTimetableService.php
2026-06-14 10:01:24 +02:00

111 lines
3.9 KiB
PHP

<?php
use Reservair\Logger\Logger;
class RsvTimetableService {
private RsvTimetableRepository $repo;
public function __construct() {
$this->repo = new RsvTimetableRepository();
}
public function get_all(?int $limit = null, int $skip = 0): array {
return $this->repo->get_all($limit, $skip);
}
public function count_all(): int {
return $this->repo->count_all();
}
public function get(int $id): ?RsvTimetable {
return $this->repo->get($id);
}
public function create(RsvTimetable $timetable): int {
return $this->repo->create($timetable);
}
public function update(int $id, RsvTimetable $timetable): int {
return $this->repo->update($id, $timetable);
}
public function get_all_maintainer_emails(): array {
return $this->repo->get_all_maintainer_emails();
}
public function set_google_calendar_id(int $id, ?string $calendar_id): void {
$this->repo->set_google_calendar_id($id, $calendar_id);
}
public function delete(int $id): int {
Logger::info('Deleting timetable: ' . $id);
return $this->repo->delete($id);
}
private function datetime_to_minutes(DateTime $dt): int {
$d = $dt->setTimezone(wp_timezone());
return (int) $d->format('G') * 60 + (int) $d->format('i');
}
/**
* @return array<int,RsvTimetableAvailability> Availability on date
*/
public function get_availability_on_date(int $timetable_id, int $block_length, DateTime $date) : array {
/**
* Get available seats for the given date
* Keeps two stacks: capacities & reservations
*
* Goes from left to right in reservations and pushes to stack
*/
$capacities = (new RsvTimetableCapacityRepository())->get_capacities_for_date($timetable_id, $date);
$reservations = (new RsvTimetableReservationService())->get_reservations_on_date($timetable_id, $date);
$capacity_stack = [];
$reservation_stack = [];
$capacity_index = 0;
$reservation_index = 0;
$blocks_count = 24 * 60 / $block_length;
$blocks = array_fill(0, $blocks_count, 0);
$availabilities = [];
$availability_idx = 0;
for($i = 0; $i < $blocks_count; $i++) {
$reservation_stack = array_filter($reservation_stack, fn($reservation) =>
$this->datetime_to_minutes($reservation->end_utc) > $i * $block_length
);
$capacity_stack = array_filter($capacity_stack, fn($capacity) =>
$capacity->end_time > $i * $block_length
);
while($reservation_index < count($reservations) && $this->datetime_to_minutes($reservations[$reservation_index]->start_utc) <= $i * $block_length) {
$reservation_stack[] = $reservations[$reservation_index];
$reservation_index++;
}
while($capacity_index < count($capacities) && $capacities[$capacity_index]->start_time <= $i * $block_length) {
$capacity_stack[] = $capacities[$capacity_index];
$capacity_index++;
}
$total_capacity = array_sum(array_map(fn($x) => $x->capacity, $capacity_stack));
if ($total_capacity > 0) {
if(count($availabilities) === $availability_idx) {
$availabilities[] = new RsvTimetableAvailability($i * $block_length, ($i + 1) * $block_length, $block_length, []);
}
$max_lead_time = empty($capacity_stack) ? 0 : max(array_map(fn($x) => $x->min_lead_time_minutes, $capacity_stack));
$availabilities[$availability_idx]->push_block($total_capacity - count($reservation_stack), $max_lead_time);
} else if($total_capacity === 0 && count($availabilities) !== $availability_idx) {
$availability_idx++;
}
}
return $availabilities;
}
}