diff options
Diffstat (limited to 'lib/models/ConsultationSlot.php')
| -rw-r--r-- | lib/models/ConsultationSlot.php | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/lib/models/ConsultationSlot.php b/lib/models/ConsultationSlot.php index 0da02df..c46e47c 100644 --- a/lib/models/ConsultationSlot.php +++ b/lib/models/ConsultationSlot.php @@ -9,6 +9,7 @@ * @property int $id alias column for slot_id * @property int $slot_id database column * @property int $block_id database column + * @property int $previous_slot_id database column * @property int $start_time database column * @property int $end_time database column * @property string $note database column @@ -17,6 +18,7 @@ * @property SimpleORMapCollection|ConsultationBooking[] $bookings has_many ConsultationBooking * @property SimpleORMapCollection|ConsultationEvent[] $events has_many ConsultationEvent * @property ConsultationBlock $block belongs_to ConsultationBlock + * @property ConsultationSlot|null $previous_slot has_one ConsultationSlot * @property-read mixed $has_bookings additional field * @property-read mixed $is_expired additional field */ @@ -45,15 +47,36 @@ class ConsultationSlot extends SimpleORMap 'assoc_foreign_key' => 'slot_id', 'on_delete' => 'delete', ]; + $config['has_one']['previous_slot'] = [ + 'class_name' => ConsultationSlot::class, + 'foreign_key' => 'previous_slot_id', + ]; $config['registered_callbacks']['before_create'][] = function (ConsultationSlot $slot) { $slot->updateEvents(); }; + $config['registered_callbacks']['before_store'][] = function (ConsultationSlot $slot) { + $previous = static::findOneBySQL( + "block_id = ? AND start_time < ? ORDER BY start_time DESC", + [$slot->block_id, $slot->start_time] + ); + $slot->previous_slot_id = $previous?->id; + }; $config['registered_callbacks']['after_delete'][] = function ($slot) { $block = $slot->block; if ($block && count($block->slots) === 0) { $block->delete(); } + + // Close gap + self::findEachBySQL( + function (ConsultationSlot $s) use ($slot) { + $s->previous_slot_id = $slot->previous_slot_id; + $s->store(); + }, + 'previous_slot_id = ?', + [$slot->id] + ); }; $config['additional_fields']['has_bookings']['get'] = function ($slot): bool { @@ -139,10 +162,6 @@ class ConsultationSlot extends SimpleORMap /** * Returns whether this slot is occupied (by a given user). - * - * @param mixed $user_id Id of the user (optional) - * @return boolean indicating whether the slot is occupied (by the given - * user) */ public function isOccupied($user_id = null) { @@ -154,7 +173,6 @@ class ConsultationSlot extends SimpleORMap /** * Returns whether the slot is locked for bookings. * - * @return bool */ public function isLocked(): bool { @@ -163,6 +181,20 @@ class ConsultationSlot extends SimpleORMap } /** + * Returns whether the slot is bookable for the given user_id + */ + public function isBookable(?string $user_id = null): bool + { + return !$this->isOccupied($user_id) + && !$this->isLocked() + && !( + $this->block->consecutive + && $this->previous_slot + && !$this->previous_slot->isOccupied() + ); + } + + /** * Creates a Stud.IP calendar event relating to the slot. * * @param User $user User object to create the event for @@ -306,8 +338,7 @@ class ConsultationSlot extends SimpleORMap $user = $user ?? User::findCurrent(); return ConsultationBooking::userMayCreateBookingForRange($this->block->range, $user) - && !$this->isOccupied() - && !$this->isLocked(); + && $this->isBookable($user->id); } |
