Czego się nauczysz?
- Pracy z formularzami wielopolowymi
- Zarządzania priorytetami i statusami
- Walidacji danych z predefiniowanych list
- Filtrowania i sortowania zgłoszeń
- Tworzenia prostych raportów
Stworzysz System zgłoszeń problemów - uproszczoną wersję helpdesku, gdzie użytkownicy mogą zgłaszać problemy techniczne. Każde zgłoszenie ma priorytet i status, który można zmieniać w miarę rozwiązywania problemu.
Czego się nauczysz?
W prawdziwej pracy...
Systemy zgłoszeń (ticketowe) są podstawą obsługi klienta w każdej firmie IT. Jira, Zendesk, ServiceNow - wszystkie działają na podobnej zasadzie. Umiejętność projektowania systemów z przepływem pracy (workflow), priorytetami i statusami jest niezbędna dla każdego programisty aplikacji biznesowych.
Formularz zgłoszenia Użytkownik opisuje problem: tytuł, szczegółowy opis i wybiera priorytet (niski, średni, wysoki).
Walidacja danych System sprawdza poprawność wprowadzonych danych - czy tytuł nie jest pusty, czy priorytet jest z dozwolonej listy.
Lista zgłoszeń Wszystkie zgłoszenia są wyświetlane z priorytetami i statusami, posortowane od najnowszego.
Zmiana statusu Administrator może zmieniać status zgłoszenia (otwarte → w realizacji → zamknięte).
Przykładowa struktura pliku JSON:
{ "issues": [ { "id": 1, "title": "Nie działa drukarka w pokoju 203", "description": "Drukarka HP nie reaguje na polecenia drukowania. Świeci się czerwona kontrolka.", "priority": "high", "status": "in_progress", "reporter": "Jan Kowalski", "created_at": "2026-02-10 09:30:00", "updated_at": "2026-02-10 11:00:00" }, { "id": 2, "title": "Prośba o instalację programu", "description": "Potrzebuję Microsoft Excel na stanowisku roboczym.", "priority": "low", "status": "open", "reporter": "Anna Nowak", "created_at": "2026-02-11 14:20:00", "updated_at": "2026-02-11 14:20:00" }, { "id": 3, "title": "Brak dostępu do sieci WiFi", "description": "Nie mogę połączyć się z siecią firmową. Hasło jest poprawne.", "priority": "high", "status": "closed", "reporter": "Piotr Wiśniewski", "created_at": "2026-02-09 08:15:00", "updated_at": "2026-02-09 16:30:00" } ]}Wymagane funkcje:
Przykładowy scenariusz:
Ocena: 3.0Użytkownik wypełnia formularz: tytuł “Nie działa drukarka”, opis problemu, priorytet “wysoki”. Po zapisie widzi zgłoszenie na liście z czerwonym znacznikiem priorytetu. Może kliknąć “Zamknij” gdy problem rozwiązany.
Wszystko z wariantu A, plus:
Przykładowy scenariusz:
Ocena: 4.0-5.0Administrator filtruje: “tylko wysokie priorytety” i widzi 3 pilne zgłoszenia. Zmienia status z “otwarte” na “w realizacji” - zgłoszenie zmienia kolor na żółty. Po rozwiązaniu zamyka je.
Wszystko z wariantu B, plus:
Przykładowy scenariusz:
Ocena: 5.0-6.0Administrator widzi dashboard: “Otwarte: 5, W realizacji: 3, Zamknięte: 12”. Statystyki: “Średni czas rozwiązania: 4h, Najczęstszy priorytet: średni (45%)”. Może wyszukać “drukarka” i znaleźć powiązane zgłoszenia.
Walidacja danych wejściowych:
$title = trim($_POST['title'] ?? '');$description = trim($_POST['description'] ?? '');$priority = $_POST['priority'] ?? '';$reporter = trim($_POST['reporter'] ?? '');
if (empty($title)) { $errors[] = "Tytuł jest wymagany";}
if (strlen($title) < 5) { $errors[] = "Tytuł musi mieć minimum 5 znaków";}
$validPriorities = ['low', 'medium', 'high'];if (!in_array($priority, $validPriorities)) { $errors[] = "Wybierz poprawny priorytet";}Dodawanie zgłoszenia:
function addIssue(array &$issues, array $data): int { $newId = empty($issues) ? 1 : max(array_column($issues, 'id')) + 1; $now = date('Y-m-d H:i:s');
$newIssue = [ 'id' => $newId, 'title' => $data['title'], 'description' => $data['description'] ?? '', 'priority' => $data['priority'], 'status' => 'open', 'reporter' => $data['reporter'] ?? 'Anonim', 'created_at' => $now, 'updated_at' => $now, ];
$issues[] = $newIssue; return $newId;}Zmiana statusu:
function changeIssueStatus(array &$issues, int $issueId, string $newStatus): bool { $validStatuses = ['open', 'in_progress', 'closed'];
if (!in_array($newStatus, $validStatuses)) { return false; }
foreach ($issues as &$issue) { if ($issue['id'] === $issueId) { $issue['status'] = $newStatus; $issue['updated_at'] = date('Y-m-d H:i:s'); return true; } }
return false;}
// Workflow: określ dozwolone przejściafunction getNextStatus(string $currentStatus): array { $transitions = [ 'open' => ['in_progress', 'closed'], 'in_progress' => ['closed', 'open'], 'closed' => ['open'], ];
return $transitions[$currentStatus] ?? [];}Filtrowanie zgłoszeń:
function filterIssues(array $issues, ?string $status = null, ?string $priority = null): array { return array_filter($issues, function($issue) use ($status, $priority) { if ($status !== null && $issue['status'] !== $status) { return false; } if ($priority !== null && $issue['priority'] !== $priority) { return false; } return true; });}Kolorowanie priorytetów i statusów:
function getPriorityInfo(string $priority): array { $priorities = [ 'low' => ['label' => 'Niski', 'color' => '#27ae60', 'icon' => '🟢'], 'medium' => ['label' => 'Średni', 'color' => '#f39c12', 'icon' => '🟡'], 'high' => ['label' => 'Wysoki', 'color' => '#e74c3c', 'icon' => '🔴'], ];
return $priorities[$priority] ?? $priorities['medium'];}
function getStatusInfo(string $status): array { $statuses = [ 'open' => ['label' => 'Otwarte', 'color' => '#e74c3c', 'icon' => '📬'], 'in_progress' => ['label' => 'W realizacji', 'color' => '#f39c12', 'icon' => '⚙️'], 'closed' => ['label' => 'Zamknięte', 'color' => '#27ae60', 'icon' => '✅'], ];
return $statuses[$status] ?? $statuses['open'];}Raport statystyk (wariant C):
function getIssueStatistics(array $issues): array { $total = count($issues);
// Liczba według statusu $byStatus = [ 'open' => 0, 'in_progress' => 0, 'closed' => 0, ];
// Liczba według priorytetu $byPriority = [ 'low' => 0, 'medium' => 0, 'high' => 0, ];
// Czas rozwiązania dla zamkniętych $resolutionTimes = [];
foreach ($issues as $issue) { $byStatus[$issue['status']]++; $byPriority[$issue['priority']]++;
if ($issue['status'] === 'closed') { $created = strtotime($issue['created_at']); $updated = strtotime($issue['updated_at']); $resolutionTimes[] = ($updated - $created) / 3600; // w godzinach } }
$avgResolution = !empty($resolutionTimes) ? round(array_sum($resolutionTimes) / count($resolutionTimes), 1) : 0;
return [ 'total' => $total, 'by_status' => $byStatus, 'by_priority' => $byPriority, 'avg_resolution_hours' => $avgResolution, ];}Wyszukiwanie:
function searchIssues(array $issues, string $query): array { if (empty($query)) { return $issues; }
$queryLower = mb_strtolower($query);
return array_filter($issues, function($issue) use ($queryLower) { $titleLower = mb_strtolower($issue['title']); $descLower = mb_strtolower($issue['description'] ?? '');
return strpos($titleLower, $queryLower) !== false || strpos($descLower, $queryLower) !== false; });}Wykorzystaj lekcje!
Cotygodniowe spotkania podczas lekcji to idealny moment, by:
Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!