Czego się nauczysz?
- Pracy z datami i godzinami w PHP
- Walidacji terminów (nie w przeszłości, format godziny)
- Wykrywania konfliktów (zajęte terminy)
- Tworzenia harmonogramów i kalendarzy
- Implementacji prostego systemu rezerwacji
Stworzysz System rejestracji wizyt - aplikację do rezerwowania terminów (np. u lekarza, konsultacji, serwisu). System pozwala wybierać datę i godzinę, sprawdza dostępność terminów i wyświetla harmonogram zaplanowanych wizyt.
Czego się nauczysz?
W prawdziwej pracy...
Systemy rezerwacji są podstawą wielu branż - od gabinetów lekarskich, przez salony fryzjerskie, po rezerwacje restauracji i hoteli. Umiejętność projektowania systemów z dostępnością czasową, konfliktami terminów i harmonogramami jest fundamentem dla każdego programisty aplikacji usługowych.
Formularz rezerwacji Użytkownik podaje swoje dane (imię, kontakt), wybiera usługę, datę i godzinę wizyty.
Walidacja danych System sprawdza poprawność wprowadzonych danych - czy data nie jest z przeszłości, czy godzina jest w dozwolonym zakresie.
Lista wizyt (harmonogram) Wszystkie zarezerwowane wizyty są wyświetlane w formie harmonogramu, posortowane chronologicznie.
Podgląd szczegółów Użytkownik może zobaczyć szczegóły konkretnej wizyty.
Przykładowa struktura pliku JSON:
{ "appointments": [ { "id": 1, "person_name": "Jan Kowalski", "contact": "jan.kowalski@email.pl", "phone": "123456789", "service": "konsultacja", "date": "2026-02-15", "time": "10:00", "notes": "Pierwsza wizyta", "status": "confirmed", "created_at": "2026-02-10 14:30:00" }, { "id": 2, "person_name": "Anna Nowak", "contact": "anna.nowak@email.pl", "phone": "987654321", "service": "badanie", "date": "2026-02-15", "time": "11:00", "notes": "", "status": "pending", "created_at": "2026-02-11 09:15:00" } ]}Wymagane funkcje:
Przykładowy scenariusz:
Ocena: 3.0Użytkownik wchodzi na stronę i widzi formularz rezerwacji. Wpisuje dane, wybiera usługę “Konsultacja”, datę 15.02.2026 i godzinę 10:00. Po zapisie widzi potwierdzenie: “Wizyta zarezerwowana: 15.02.2026 o 10:00”.
Wszystko z wariantu A, plus:
htmlspecialchars() przy wyświetlaniuPrzykładowy scenariusz:
Ocena: 4.0-5.0Operator filtruje wizyty: “pokaż tylko 15 lutego” i widzi 5 wizyt. Może zmienić status wizyty na “potwierdzona”. Użytkownik po rezerwacji widzi status “oczekująca”.
Wszystko z wariantu B, plus:
Przykładowy scenariusz:
Ocena: 5.0-6.0Użytkownik próbuje zarezerwować termin 15.02 o 10:00, ale system informuje: “Ten termin jest już zajęty. Dostępne godziny: 11:00, 12:00, 14:00”. Admin widzi wszystkie wizyty i może je edytować lub usuwać.
Walidacja daty i godziny:
$date = $_POST['date'] ?? '';$time = $_POST['time'] ?? '';$today = date('Y-m-d');
// Data nie może być z przeszłościif ($date < $today) { $errors[] = "Data nie może być z przeszłości";}
// Walidacja formatu godziny (HH:MM)if (!preg_match('/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/', $time)) { $errors[] = "Nieprawidłowy format godziny (użyj HH:MM)";}
// Godziny pracy (np. 8:00 - 18:00)$hour = (int) explode(':', $time)[0];if ($hour < 8 || $hour >= 18) { $errors[] = "Wizyty możliwe tylko w godzinach 8:00 - 18:00";}Wykrywanie konfliktów terminów:
function isTimeSlotAvailable(array $appointments, string $date, string $time, int $duration = 60): bool { $requestedStart = strtotime("$date $time"); $requestedEnd = $requestedStart + ($duration * 60);
foreach ($appointments as $appointment) { if ($appointment['date'] !== $date) { continue; }
$existingStart = strtotime("{$appointment['date']} {$appointment['time']}"); $existingEnd = $existingStart + ($duration * 60);
// Sprawdź czy terminy się nakładają if ($requestedStart < $existingEnd && $requestedEnd > $existingStart) { return false; } }
return true;}
// Znajdź dostępne godzinyfunction getAvailableSlots(array $appointments, string $date, int $startHour = 8, int $endHour = 18): array { $available = [];
for ($hour = $startHour; $hour < $endHour; $hour++) { $time = sprintf('%02d:00', $hour); if (isTimeSlotAvailable($appointments, $date, $time)) { $available[] = $time; } }
return $available;}Dodawanie wizyty:
function addAppointment(array &$appointments, array $data): int { $newId = empty($appointments) ? 1 : max(array_column($appointments, 'id')) + 1;
$newAppointment = [ 'id' => $newId, 'person_name' => $data['person_name'], 'contact' => $data['contact'], 'phone' => $data['phone'] ?? '', 'service' => $data['service'], 'date' => $data['date'], 'time' => $data['time'], 'notes' => $data['notes'] ?? '', 'status' => 'pending', 'created_at' => date('Y-m-d H:i:s'), ];
$appointments[] = $newAppointment; return $newId;}Filtrowanie wizyt:
function filterByDate(array $appointments, string $date): array { return array_filter($appointments, fn($a) => $a['date'] === $date);}
function filterByDateRange(array $appointments, string $from, string $to): array { return array_filter($appointments, function($a) use ($from, $to) { return $a['date'] >= $from && $a['date'] <= $to; });}
function filterByStatus(array $appointments, string $status): array { return array_filter($appointments, fn($a) => $a['status'] === $status);}Sortowanie harmonogramu:
function sortAppointments(array $appointments): array { usort($appointments, function($a, $b) { $dateCompare = strcmp($a['date'], $b['date']); if ($dateCompare !== 0) { return $dateCompare; } return strcmp($a['time'], $b['time']); });
return $appointments;}Dostępne usługi:
function getServices(): array { return [ 'konsultacja' => ['label' => 'Konsultacja', 'duration' => 30, 'price' => 100], 'badanie' => ['label' => 'Badanie', 'duration' => 60, 'price' => 200], 'zabieg' => ['label' => 'Zabieg', 'duration' => 90, 'price' => 350], 'kontrola' => ['label' => 'Wizyta kontrolna', 'duration' => 15, 'price' => 50], ];}JavaScript - walidacja formularza:
function validateAppointmentForm() { const name = document.getElementById('person_name').value.trim(); const contact = document.getElementById('contact').value.trim(); const date = document.getElementById('date').value; const time = document.getElementById('time').value; const errors = [];
if (name.length < 2) { errors.push('Podaj imię i nazwisko'); }
if (!contact.includes('@')) { errors.push('Podaj poprawny email'); }
const today = new Date().toISOString().split('T')[0]; if (date < today) { errors.push('Data nie może być z przeszłości'); }
if (!time) { errors.push('Wybierz godzinę'); }
if (errors.length > 0) { alert(errors.join('\n')); return false; }
return true;}Wykorzystaj lekcje!
Cotygodniowe spotkania podczas lekcji to idealny moment, by:
Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!