Czego się nauczysz?
- Generowania sekwencyjnych numerów
- Formatowania stringów z paddingiem (str_pad)
- Pracy z datami w numeracji
- Walidacji unikalności
- Tworzenia konfigurowalnych wzorców
Stworzysz Generator numeru referencyjnego - aplikację do tworzenia unikalnych identyfikatorów w określonym formacie (np. REF-2026-0001, INV-202602-0042). System zapewnia unikalność numerów, pozwala na wybór formatu i prowadzi historię wygenerowanych kodów.
Czego się nauczysz?
W prawdziwej pracy...
Generowanie unikalnych identyfikatorów jest podstawą każdego systemu biznesowego - numery faktur, numerów zamówień, kodów produktów, identyfikatorów transakcji. Umiejętność projektowania systemów z sekwencyjną numeracją i gwarancją unikalności jest niezbędna dla każdego programisty aplikacji enterprise.
Przycisk generowania Użytkownik klika przycisk “Generuj numer” i otrzymuje nowy, unikalny numer referencyjny.
Format numeru Numer składa się z prefiksu, roku i numeru sekwencyjnego (np. REF-2026-0001).
Zapis do historii Każdy wygenerowany numer jest zapisywany do pliku JSON z datą utworzenia.
Lista numerów Użytkownik widzi historię wszystkich wygenerowanych numerów.
Przykładowa struktura pliku JSON:
{ "references": [ { "id": 1, "code": "REF-2026-0001", "format": "prefix_year_seq", "purpose": "Faktura", "created_at": "2026-02-10 14:30:00" }, { "id": 2, "code": "REF-2026-0002", "format": "prefix_year_seq", "purpose": "", "created_at": "2026-02-10 15:45:00" }, { "id": 3, "code": "INV-202602-0001", "format": "prefix_yearmonth_seq", "purpose": "Zamówienie", "created_at": "2026-02-11 09:00:00" } ]}| Format | Przykład | Opis |
|---|---|---|
| PREFIX-YYYY-NNNN | REF-2026-0001 | Prefiks, rok, numer sekwencyjny |
| PREFIX-YYYYMM-NNNN | INV-202602-0042 | Prefiks, rok i miesiąc, numer |
| YYYY/NNNN | 2026/0001 | Rok/numer |
| PREFIX-NNNN | DOC-0001 | Prefiks, numer (bez daty) |
Wymagane funkcje:
Przykładowy scenariusz:
Ocena: 3.0Użytkownik klika “Generuj”. System wyświetla: “Wygenerowano: REF-2026-0001”. Po kolejnym kliknięciu: “REF-2026-0002”. Numery są unikalne i sekwencyjne.
Wszystko z wariantu A, plus:
Przykładowy scenariusz:
Ocena: 4.0-5.0Użytkownik wpisuje cel “Faktura VAT” i klika “Generuj”. Numer REF-2026-0003 zostaje zapisany z opisem. Na liście widać wszystkie numery z datami i celami. Może kliknąć ikonę kopiowania.
Wszystko z wariantu B, plus:
Przykładowy scenariusz:
Ocena: 5.0-6.0Użytkownik wybiera format “INV-YYYYMM-NNNN” i prefiks “INV”. System generuje: INV-202602-0001. Może wybrać inny format dla zamówień: “ORD-2026-0001”. W lutym numeracja INV zaczyna się od 0001.
Podstawowy generator numeru:
function generateReferenceNumber(array $existingCodes, string $prefix = 'REF'): string { $year = date('Y'); $pattern = $prefix . '-' . $year . '-';
// Znajdź najwyższy numer w tym roku $maxSeq = 0; foreach ($existingCodes as $ref) { if (strpos($ref['code'], $pattern) === 0) { $seq = (int) substr($ref['code'], strlen($pattern)); $maxSeq = max($maxSeq, $seq); } }
$nextSeq = $maxSeq + 1; return $pattern . str_pad($nextSeq, 4, '0', STR_PAD_LEFT);}
// Wynik: REF-2026-0001, REF-2026-0002, ...Generator z różnymi formatami:
function generateByFormat(array $existingCodes, string $format, string $prefix = 'REF'): string { switch ($format) { case 'prefix_year_seq': // REF-2026-0001 $pattern = $prefix . '-' . date('Y') . '-'; break;
case 'prefix_yearmonth_seq': // REF-202602-0001 $pattern = $prefix . '-' . date('Ym') . '-'; break;
case 'year_seq': // 2026/0001 $pattern = date('Y') . '/'; break;
case 'prefix_seq': // REF-0001 $pattern = $prefix . '-'; break;
default: $pattern = $prefix . '-' . date('Y') . '-'; }
$maxSeq = findMaxSequence($existingCodes, $pattern); $nextSeq = $maxSeq + 1;
return $pattern . str_pad($nextSeq, 4, '0', STR_PAD_LEFT);}
function findMaxSequence(array $codes, string $pattern): int { $maxSeq = 0;
foreach ($codes as $ref) { $code = $ref['code']; if (strpos($code, $pattern) === 0) { $seqPart = substr($code, strlen($pattern)); $seq = (int) preg_replace('/[^0-9]/', '', $seqPart); $maxSeq = max($maxSeq, $seq); } }
return $maxSeq;}Walidacja unikalności:
function isUnique(array $existingCodes, string $newCode): bool { foreach ($existingCodes as $ref) { if ($ref['code'] === $newCode) { return false; } } return true;}
function generateUniqueCode(array $existingCodes, string $format, string $prefix): string { $attempts = 0; $maxAttempts = 100;
do { $code = generateByFormat($existingCodes, $format, $prefix); $attempts++;
if ($attempts >= $maxAttempts) { throw new Exception("Nie można wygenerować unikalnego kodu"); } } while (!isUnique($existingCodes, $code));
return $code;}Resetowanie numeracji (wariant C):
function shouldResetSequence(string $format, array $existingCodes): bool { if (empty($existingCodes)) { return false; }
$lastRef = end($existingCodes); $lastDate = date('Y-m', strtotime($lastRef['created_at'])); $currentDate = date('Y-m');
// Resetuj przy zmianie miesiąca dla formatów z miesiącem if ($format === 'prefix_yearmonth_seq' && $lastDate !== $currentDate) { return true; }
// Resetuj przy zmianie roku dla formatów z rokiem $lastYear = date('Y', strtotime($lastRef['created_at'])); $currentYear = date('Y');
if (in_array($format, ['prefix_year_seq', 'year_seq']) && $lastYear !== $currentYear) { return true; }
return false;}Zapis do historii:
function saveReference(array &$references, string $code, string $format, string $purpose = ''): int { $newId = empty($references) ? 1 : max(array_column($references, 'id')) + 1;
$newRef = [ 'id' => $newId, 'code' => $code, 'format' => $format, 'purpose' => trim($purpose), 'created_at' => date('Y-m-d H:i:s'), ];
$references[] = $newRef; return $newId;}JavaScript - kopiowanie do schowka:
function copyCode(code) { navigator.clipboard.writeText(code).then(() => { showNotification('Skopiowano: ' + code); }).catch(err => { console.error('Błąd kopiowania:', err); // Fallback dla starszych przeglądarek fallbackCopy(code); });}
function fallbackCopy(text) { const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); showNotification('Skopiowano: ' + text);}Dostępne formaty:
function getAvailableFormats(): array { return [ 'prefix_year_seq' => [ 'name' => 'PREFIX-RRRR-NNNN', 'example' => 'REF-2026-0001', 'description' => 'Prefiks, rok, numer sekwencyjny', ], 'prefix_yearmonth_seq' => [ 'name' => 'PREFIX-RRRRMM-NNNN', 'example' => 'INV-202602-0001', 'description' => 'Prefiks, rok i miesiąc, numer (resetuje się co miesiąc)', ], 'year_seq' => [ 'name' => 'RRRR/NNNN', 'example' => '2026/0001', 'description' => 'Rok/numer', ], 'prefix_seq' => [ 'name' => 'PREFIX-NNNN', 'example' => 'DOC-0001', 'description' => 'Prefiks i numer (bez daty)', ], ];}Wykorzystaj lekcje!
Cotygodniowe spotkania podczas lekcji to idealny moment, by:
Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!