Przejdź do głównej zawartości

Rejestr książek

Stworzysz Rejestr książek - aplikację do zarządzania osobistą biblioteką. Użytkownik może dodawać książki, oznaczać je jako przeczytane/nieprzeczytane, filtrować listę i śledzić swoje postępy czytelnicze.

Czego się nauczysz?

  • Tworzenia formularzy CRUD (Create, Read, Update, Delete)
  • Pracy że statusami i ich zmianą
  • Filtrowania i sortowania danych
  • Wyszukiwania tekstowego
  • Tworzenia statystyk i podsumowań

W prawdziwej pracy...

Rejestry i listy z możliwością zmiany statusu to podstawa wielu aplikacji - od list zadań (todo), przez systemy CRM, po aplikacje do śledzenia nawyków. Umiejętność projektowania interfejsów do zarządzania danymi że statusami jest fundamentem dla każdego programisty aplikacji biznesowych.

  1. Formularz dodawania książki Użytkownik podaje tytuł i autora książki. Opcjonalnie może dodać gatunek, rok wydania lub ocenę.

  2. Walidacja danych System sprawdza poprawność wprowadzonych danych - czy tytuł i autor nie są puste, czy nie ma duplikatów.

  3. Lista książek Wszystkie książki są wyświetlane w formie listy lub tabeli z informacjami o statusie.

  4. Zmiana statusu Użytkownik może oznaczyć książkę jako przeczytaną lub nieprzeczytaną jednym kliknięciem.

Przykładowa struktura pliku JSON:

{
"books": [
{
"id": 1,
"title": "Władca Pierścieni",
"author": "J.R.R. Tolkien",
"genre": "fantasy",
"year": 1954,
"status": "read",
"rating": 5,
"added_at": "2026-01-15",
"read_at": "2026-02-10"
},
{
"id": 2,
"title": "1984",
"author": "George Orwell",
"genre": "dystopia",
"year": 1949,
"status": "unread",
"rating": null,
"added_at": "2026-02-01",
"read_at": null
},
{
"id": 3,
"title": "Wiedźmin: Ostatnie życzenie",
"author": "Andrzej Sapkowski",
"genre": "fantasy",
"year": 1993,
"status": "reading",
"rating": null,
"added_at": "2026-02-05",
"read_at": null
}
]
}

Wymagane funkcje:

  • Formularz z polami: tytuł, autor
  • Walidacja danych w PHP (wymagane pola)
  • Lista wszystkich książek
  • Zmiana statusu (przeczytana/nieprzeczytana)
  • Prosty interfejs CSS (kolorowanie statusów)

Przykładowy scenariusz:

Użytkownik wpisuje “Władca Pierścieni” i “J.R.R. Tolkien”. Po kliknięciu “Dodaj” książka pojawia się na liście jako “nieprzeczytana” (szare tło). Klika przycisk “Przeczytane” i status zmienia się na zielony.

Ocena: 3.0

Walidacja danych wejściowych:

$title = trim($_POST['title'] ?? '');
$author = trim($_POST['author'] ?? '');
$genre = trim($_POST['genre'] ?? '');
if (empty($title)) {
$errors[] = "Tytuł jest wymagany";
}
if (empty($author)) {
$errors[] = "Autor jest wymagany";
}
if (strlen($title) > 200) {
$errors[] = "Tytuł jest zbyt długi (max 200 znaków)";
}

Dodawanie książki:

function addBook(array &$books, string $title, string $author, string $genre = ''): int {
$newId = empty($books) ? 1 : max(array_column($books, 'id')) + 1;
$newBook = [
'id' => $newId,
'title' => $title,
'author' => $author,
'genre' => $genre,
'status' => 'unread',
'rating' => null,
'added_at' => date('Y-m-d'),
'read_at' => null,
];
$books[] = $newBook;
return $newId;
}

Zmiana statusu:

function changeStatus(array &$books, int $bookId, string $newStatus): bool {
$validStatuses = ['unread', 'reading', 'read'];
if (!in_array($newStatus, $validStatuses)) {
return false;
}
foreach ($books as &$book) {
if ($book['id'] === $bookId) {
$book['status'] = $newStatus;
// Ustaw datę przeczytania
if ($newStatus === 'read' && $book['read_at'] === null) {
$book['read_at'] = date('Y-m-d');
}
return true;
}
}
return false;
}

Filtrowanie książek:

function filterBooks(array $books, ?string $status = null, ?string $genre = null): array {
return array_filter($books, function($book) use ($status, $genre) {
if ($status !== null && $book['status'] !== $status) {
return false;
}
if ($genre !== null && ($book['genre'] ?? '') !== $genre) {
return false;
}
return true;
});
}

Wyszukiwanie:

function searchBooks(array $books, string $query): array {
if (empty($query)) {
return $books;
}
$queryLower = mb_strtolower($query);
return array_filter($books, function($book) use ($queryLower) {
$titleLower = mb_strtolower($book['title']);
$authorLower = mb_strtolower($book['author']);
return strpos($titleLower, $queryLower) !== false
|| strpos($authorLower, $queryLower) !== false;
});
}

Sortowanie:

function sortBooks(array $books, string $sortBy = 'added_at', string $order = 'desc'): array {
usort($books, function($a, $b) use ($sortBy, $order) {
$valueA = $a[$sortBy] ?? '';
$valueB = $b[$sortBy] ?? '';
$comparison = strcmp($valueA, $valueB);
return $order === 'desc' ? -$comparison : $comparison;
});
return $books;
}

Statystyki:

function getBookStatistics(array $books): array {
$total = count($books);
$read = count(array_filter($books, fn($b) => $b['status'] === 'read'));
$reading = count(array_filter($books, fn($b) => $b['status'] === 'reading'));
// Statystyki gatunków
$genres = [];
foreach ($books as $book) {
$genre = $book['genre'] ?? 'inne';
$genres[$genre] = ($genres[$genre] ?? 0) + 1;
}
arsort($genres);
// Najlepiej ocenione
$rated = array_filter($books, fn($b) => $b['rating'] !== null);
usort($rated, fn($a, $b) => $b['rating'] <=> $a['rating']);
$topRated = array_slice($rated, 0, 3);
return [
'total' => $total,
'read' => $read,
'reading' => $reading,
'unread' => $total - $read - $reading,
'percentage' => $total > 0 ? round(($read / $total) * 100) : 0,
'genres' => $genres,
'top_rated' => $topRated,
];
}

Kolorowanie statusów:

function getStatusInfo(string $status): array {
$statuses = [
'unread' => ['label' => 'Do przeczytania', 'color' => '#95a5a6', 'icon' => '📚'],
'reading' => ['label' => 'Czytam', 'color' => '#f39c12', 'icon' => '📖'],
'read' => ['label' => 'Przeczytane', 'color' => '#27ae60', 'icon' => ''],
];
return $statuses[$status] ?? $statuses['unread'];
}

Wykorzystaj lekcje!

Cotygodniowe spotkania podczas lekcji to idealny moment, by:

  • Pokazać postępy - nawet małe kroki się liczą
  • Wyjaśnić wątpliwości - pytaj, nie zgaduj
  • Skonsultować rozwiązania - feedback pomoże Ci się rozwijać

Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!