Skip to main content

ReservationSlot Model

The ReservationSlot model manages time slots (bloques de horario) for room reservations. It handles the creation of time slots, conflict detection, and availability checking to ensure rooms are not double-booked.

Constructor

public function __construct()
Initializes the ReservationSlot model and establishes a PDO database connection.

Methods

create()

Creates a new time slot for a reservation.
public function create(
    int $reservationId,
    string $date,
    string $startTime,
    string $endTime
): bool
reservationId
int
required
The ID of the reservation this slot belongs to
date
string
required
Date for the time slot in YYYY-MM-DD format
startTime
string
required
Start time in HH:MM:SS format
endTime
string
required
End time in HH:MM:SS format
Returns: bool - true if the slot was created successfully SQL Query:
INSERT INTO reservation_slots (reservation_id, date, start_time, end_time)
VALUES (:reservation_id, :date, :start_time, :end_time)
This method does not automatically check for conflicts. Use hasConflict() before creating a slot to ensure the room is available.
Example:
$slot = new ReservationSlot();

// Create a time slot for December 15, 2024 from 9:00 AM to 11:00 AM
$success = $slot->create(
    reservationId: 15,
    date: '2024-12-15',
    startTime: '09:00:00',
    endTime: '11:00:00'
);

if ($success) {
    echo "Time slot created successfully";
}

getByReservation()

Retrieves all time slots associated with a specific reservation.
public function getByReservation(int $reservationId): array
reservationId
int
required
The ID of the reservation
Returns: array - Array of associative arrays containing slot data, ordered by date and start time
date
string
Date of the time slot (YYYY-MM-DD)
start_time
string
Start time of the slot (HH:MM:SS)
end_time
string
End time of the slot (HH:MM:SS)
SQL Query:
SELECT date, start_time, end_time
FROM reservation_slots
WHERE reservation_id = :reservation_id
ORDER BY date, start_time
Example:
$slot = new ReservationSlot();
$slots = $slot->getByReservation(15);

foreach ($slots as $s) {
    echo "Date: {$s['date']}\n";
    echo "Time: {$s['start_time']} - {$s['end_time']}\n";
    echo "---\n";
}

hasConflict()

Checks if there is a scheduling conflict for a room at a specific date and time.
public function hasConflict(
    int $roomId,
    string $date,
    string $startTime,
    string $endTime
): bool
roomId
int
required
The ID of the room to check
date
string
required
Date to check in YYYY-MM-DD format
startTime
string
required
Proposed start time in HH:MM:SS format
endTime
string
required
Proposed end time in HH:MM:SS format
Returns: bool - true if there is a conflict (room is already booked), false if available SQL Query:
SELECT 1
FROM reservation_slots rs
JOIN reservations r ON r.id = rs.reservation_id
WHERE r.room_id = :room_id
  AND rs.date = :date
  AND (rs.start_time < :end_time AND rs.end_time > :start_time)
LIMIT 1
The conflict detection uses an overlap formula: (rs.start_time < :end_time AND rs.end_time > :start_time) to determine if two time ranges overlap.
Example:
$slot = new ReservationSlot();

// Check if Room 3 is available on Dec 15 from 9:00 AM to 11:00 AM
$hasConflict = $slot->hasConflict(
    roomId: 3,
    date: '2024-12-15',
    startTime: '09:00:00',
    endTime: '11:00:00'
);

if ($hasConflict) {
    echo "Room is not available during this time";
} else {
    echo "Room is available";
}
Conflict Detection Logic: Two time slots conflict if they overlap. The overlap occurs when:
  • The new slot starts before an existing slot ends, AND
  • The new slot ends after an existing slot starts
Examples:
// Existing slot: 09:00 - 11:00
// New slot: 10:00 - 12:00 → CONFLICT (overlaps)
// New slot: 11:00 - 13:00 → NO CONFLICT (starts exactly when existing ends)
// New slot: 08:00 - 09:00 → NO CONFLICT (ends exactly when existing starts)
// New slot: 14:00 - 16:00 → NO CONFLICT (completely separate)

getOccupiedSlots()

Retrieves all occupied time slots for a specific room on a given date. Useful for displaying availability.
public function getOccupiedSlots(int $roomId, string $date): array
roomId
int
required
The ID of the room
date
string
required
Date to check in YYYY-MM-DD format
Returns: array - Array of occupied time slots, ordered by start time
start_time
string
Start time of the occupied slot (HH:MM:SS)
end_time
string
End time of the occupied slot (HH:MM:SS)
SQL Query:
SELECT rs.start_time, rs.end_time
FROM reservation_slots rs
JOIN reservations r ON r.id = rs.reservation_id
WHERE r.room_id = :room_id
  AND rs.date = :date
ORDER BY rs.start_time
Example:
$slot = new ReservationSlot();
$occupied = $slot->getOccupiedSlots(
    roomId: 3,
    date: '2024-12-15'
);

echo "Occupied time slots for Room 3 on December 15:\n";
foreach ($occupied as $o) {
    echo "- {$o['start_time']} to {$o['end_time']}\n";
}

// Output:
// Occupied time slots for Room 3 on December 15:
// - 09:00:00 to 11:00:00
// - 14:00:00 to 16:00:00
// - 18:00:00 to 20:00:00
Use Case - Display Available Times:
$slot = new ReservationSlot();
$occupied = $slot->getOccupiedSlots(3, '2024-12-15');

// Define business hours
$businessStart = '08:00:00';
$businessEnd = '22:00:00';

// Calculate available slots by finding gaps between occupied slots
echo "Available times:\n";
$lastEnd = $businessStart;

foreach ($occupied as $o) {
    if ($lastEnd < $o['start_time']) {
        echo "- {$lastEnd} to {$o['start_time']}\n";
    }
    $lastEnd = $o['end_time'];
}

// Check if there's time after the last reservation
if ($lastEnd < $businessEnd) {
    echo "- {$lastEnd} to {$businessEnd}\n";
}

Database Schema

The ReservationSlot model interacts with the following database tables:
  • reservation_slots - Main time slot records
    • id - Primary key
    • reservation_id - Foreign key to reservations table
    • date - Date of the slot (DATE)
    • start_time - Start time (TIME)
    • end_time - End time (TIME)
  • reservations - Parent reservation records
    • Used to join with rooms table for conflict detection

Best Practices

Always Check for Conflicts

Before creating a new time slot, always check for conflicts:
$slot = new ReservationSlot();

if ($slot->hasConflict($roomId, $date, $startTime, $endTime)) {
    throw new Exception('Time slot conflict detected');
}

$slot->create($reservationId, $date, $startTime, $endTime);

Validate Time Ranges

Ensure end time is after start time before creating slots:
if (strtotime($endTime) <= strtotime($startTime)) {
    throw new Exception('End time must be after start time');
}

Handle Multiple Slots

When creating reservations with multiple time slots, validate all slots for conflicts first:
$slot = new ReservationSlot();
$slotsToCreate = [
    ['date' => '2024-12-15', 'start' => '09:00:00', 'end' => '11:00:00'],
    ['date' => '2024-12-15', 'start' => '14:00:00', 'end' => '16:00:00'],
];

// First, check all for conflicts
foreach ($slotsToCreate as $s) {
    if ($slot->hasConflict($roomId, $s['date'], $s['start'], $s['end'])) {
        throw new Exception("Conflict on {$s['date']} at {$s['start']}");
    }
}

// If no conflicts, create all slots
foreach ($slotsToCreate as $s) {
    $slot->create($reservationId, $s['date'], $s['start'], $s['end']);
}

Build docs developers (and LLMs) love