Czego się nauczysz?
- Pracy z datami i formatowaniem w PHP
- Walidacji ograniczonego zestawu wartości (statusy)
- Zliczania i agregowania danych
- Generowania raportów i statystyk
- Tworzenia podsumowań per osoba/dzień
This content is not available in your language yet.
Stworzysz Rejestr obecności - aplikację do prowadzenia ewidencji obecności uczniów na zajęciach. System pozwala dodawać wpisy z datą i statusem, generować podsumowania i eksportować raporty.
Czego się nauczysz?
W prawdziwej pracy...
Systemy ewidencji obecności są niezbędne w każdej organizacji - od szkół i uczelni, przez firmy, po wydarzenia i konferencje. Umiejętność projektowania systemów z walidacją statusów, agregacją danych i raportowaniem jest fundamentem dla każdego programisty aplikacji HR i administracyjnych.
Formularz dodawania obecności Użytkownik wybiera datę, ucznia i status obecności (obecny, nieobecny, spóźniony).
Walidacja danych System sprawdza poprawność wprowadzonych danych - czy status jest z dozwolonej listy, czy data jest prawidłowa.
Lista obecności Wszystkie wpisy są wyświetlane w formie tabeli, posortowane chronologicznie.
Podgląd szczegółów Użytkownik może zobaczyć szczegóły obecności konkretnego ucznia lub dnia.
Przykładowa struktura pliku JSON:
{ "attendance": [ { "id": 1, "date": "2026-02-10", "student": "Jan Kowalski", "student_id": "1A01", "status": "present", "notes": "", "recorded_by": "Nauczyciel", "created_at": "2026-02-10 08:15:00" }, { "id": 2, "date": "2026-02-10", "student": "Anna Nowak", "student_id": "1A02", "status": "late", "notes": "Spóźnienie 10 min", "recorded_by": "Nauczyciel", "created_at": "2026-02-10 08:20:00" }, { "id": 3, "date": "2026-02-10", "student": "Piotr Wiśniewski", "student_id": "1A03", "status": "absent", "notes": "Choroba - zwolnienie lekarskie", "recorded_by": "Nauczyciel", "created_at": "2026-02-10 08:00:00" } ]}Wymagane funkcje:
Przykładowy scenariusz:
Ocena: 3.0Nauczyciel wchodzi na stronę i widzi formularz. Wybiera datę 10.02.2026, ucznia “Jan Kowalski” i status “obecny”. Po zapisie widzi wpis na liście z zielonym znacznikiem.
Wszystko z wariantu A, plus:
htmlspecialchars() przy wyświetlaniuPrzykładowy scenariusz:
Ocena: 4.0-5.0Nauczyciel klika na ucznia “Jan Kowalski” i widzi jego statystyki: “Obecności: 18, Nieobecności: 2, Spóźnienia: 1, Frekwencja: 90%”. Może też sprawdzić frekwencję całej klasy w danym dniu.
Wszystko z wariantu B, plus:
Przykładowy scenariusz:
Ocena: 5.0-6.0Admin eksportuje raport obecności za luty 2026 do pliku HTML. Raport zawiera tabelę z uczniami, liczbą obecności/nieobecności i procentową frekwencją. Może też edytować błędnie wprowadzony wpis.
Walidacja statusu obecności:
$date = $_POST['date'] ?? '';$student = trim($_POST['student'] ?? '');$status = $_POST['status'] ?? '';
$validStatuses = ['present', 'absent', 'late', 'excused'];
if (empty($date)) { $errors[] = "Data jest wymagana";}
if (empty($student)) { $errors[] = "Wybierz ucznia";}
if (!in_array($status, $validStatuses)) { $errors[] = "Nieprawidłowy status obecności";}
// Walidacja formatu datyif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { $errors[] = "Nieprawidłowy format daty (YYYY-MM-DD)";}
// Data nie może być z przyszłościif ($date > date('Y-m-d')) { $errors[] = "Data nie może być z przyszłości";}Statusy z etykietami i kolorami:
function getStatuses(): array { return [ 'present' => ['label' => 'Obecny', 'icon' => '✅', 'color' => '#27ae60'], 'absent' => ['label' => 'Nieobecny', 'icon' => '❌', 'color' => '#e74c3c'], 'late' => ['label' => 'Spóźniony', 'icon' => '⏰', 'color' => '#f39c12'], 'excused' => ['label' => 'Usprawiedliwiony', 'icon' => '📋', 'color' => '#3498db'], ];}
function getStatusLabel(string $status): string { $statuses = getStatuses(); return $statuses[$status]['label'] ?? 'Nieznany';}
function getStatusColor(string $status): string { $statuses = getStatuses(); return $statuses[$status]['color'] ?? '#95a5a6';}Dodawanie wpisu obecności:
function addAttendance(array &$attendance, array $data): int { $newId = empty($attendance) ? 1 : max(array_column($attendance, 'id')) + 1;
$newEntry = [ 'id' => $newId, 'date' => $data['date'], 'student' => $data['student'], 'student_id' => $data['student_id'] ?? '', 'status' => $data['status'], 'notes' => $data['notes'] ?? '', 'recorded_by' => $data['recorded_by'] ?? 'System', 'created_at' => date('Y-m-d H:i:s'), ];
$attendance[] = $newEntry; return $newId;}Podsumowanie obecności ucznia:
function getStudentSummary(array $attendance, string $student): array { $studentRecords = array_filter($attendance, fn($a) => $a['student'] === $student);
$counts = [ 'present' => 0, 'absent' => 0, 'late' => 0, 'excused' => 0, ];
foreach ($studentRecords as $record) { $status = $record['status']; if (isset($counts[$status])) { $counts[$status]++; } }
$total = count($studentRecords); $attended = $counts['present'] + $counts['late']; $frequency = $total > 0 ? round(($attended / $total) * 100, 1) : 0;
return [ 'student' => $student, 'total' => $total, 'counts' => $counts, 'frequency' => $frequency, ];}Podsumowanie dnia (frekwencja klasy):
function getDaySummary(array $attendance, string $date): array { $dayRecords = array_filter($attendance, fn($a) => $a['date'] === $date);
$statusCounts = array_count_values(array_column($dayRecords, 'status'));
$total = count($dayRecords); $present = ($statusCounts['present'] ?? 0) + ($statusCounts['late'] ?? 0); $frequency = $total > 0 ? round(($present / $total) * 100, 1) : 0;
return [ 'date' => $date, 'total' => $total, 'present' => $statusCounts['present'] ?? 0, 'absent' => $statusCounts['absent'] ?? 0, 'late' => $statusCounts['late'] ?? 0, 'excused' => $statusCounts['excused'] ?? 0, 'frequency' => $frequency, ];}Filtrowanie i sortowanie:
function filterByDate(array $attendance, string $date): array { return array_filter($attendance, fn($a) => $a['date'] === $date);}
function filterByStudent(array $attendance, string $student): array { return array_filter($attendance, fn($a) => $a['student'] === $student);}
function filterByStatus(array $attendance, string $status): array { return array_filter($attendance, fn($a) => $a['status'] === $status);}
function sortByDate(array $attendance, string $order = 'desc'): array { usort($attendance, function($a, $b) use ($order) { $result = strcmp($a['date'], $b['date']); return $order === 'desc' ? -$result : $result; });
return $attendance;}Generowanie raportu HTML (wariant C):
function generateReport(array $attendance, string $dateFrom, string $dateTo): string { $filtered = array_filter($attendance, function($a) use ($dateFrom, $dateTo) { return $a['date'] >= $dateFrom && $a['date'] <= $dateTo; });
$students = array_unique(array_column($filtered, 'student')); sort($students);
$html = '<!DOCTYPE html><html><head><meta charset="UTF-8">'; $html .= '<title>Raport obecności ' . $dateFrom . ' - ' . $dateTo . '</title>'; $html .= '<style>table { border-collapse: collapse; width: 100%; }'; $html .= 'th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }'; $html .= 'th { background: #333; color: white; }</style></head><body>'; $html .= '<h1>Raport obecności</h1>'; $html .= '<p>Okres: ' . $dateFrom . ' - ' . $dateTo . '</p>'; $html .= '<table><tr><th>Uczeń</th><th>Obecny</th><th>Nieobecny</th><th>Spóźniony</th><th>Frekwencja</th></tr>';
foreach ($students as $student) { $summary = getStudentSummary($filtered, $student); $html .= '<tr>'; $html .= '<td>' . htmlspecialchars($student) . '</td>'; $html .= '<td>' . $summary['counts']['present'] . '</td>'; $html .= '<td>' . $summary['counts']['absent'] . '</td>'; $html .= '<td>' . $summary['counts']['late'] . '</td>'; $html .= '<td>' . $summary['frequency'] . '%</td>'; $html .= '</tr>'; }
$html .= '</table></body></html>'; return $html;}Wykorzystaj lekcje!
Cotygodniowe spotkania podczas lekcji to idealny moment, by:
Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!