Menu
Coddy logo textTech

Wzorzec repozytorium

Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 81 z 91.

Wzorzec repozytorium to wzorzec projektowy, który pośredniczy między logiką biznesową Twojej aplikacji a przechowywaniem danych. Zapewnia interfejs podobny do kolekcji, umożliwiający dostęp do obiektów domenowych, ukrywając szczegóły faktycznego przechowywania i pobierania danych.

Repository możesz sobie wyobrazić jako wyspecjalizowaną kolekcję, która wie, jak przechowywać i pobierać obiekty. Kod aplikacji prosi repozytorium o użytkownika na podstawie ID lub zapisuje nowy produkt, nie wiedząc, czy dane znajdują się w bazie danych, pliku czy API. Taki podział sprawia, że kod łatwiej testować i jest bardziej elastyczny.

<?php
interface UserRepositoryInterface {
    public function find(int $id): ?User;
    public function findAll(): array;
    public function save(User $user): void;
    public function delete(int $id): void;
}

class User {
    public function __construct(
        public int $id,
        public string $name,
        public string $email
    ) {}
}

Implementacja repozytorium obsługuje mechanizm przechowywania danych:

<?php
class InMemoryUserRepository implements UserRepositoryInterface {
    private array $users = [];
    
    public function find(int $id): ?User {
        return $this->users[$id] ?? null;
    }
    
    public function findAll(): array {
        return array_values($this->users);
    }
    
    public function save(User $user): void {
        $this->users[$user->id] = $user;
    }
    
    public function delete(int $id): void {
        unset($this->users[$id]);
    }
}

$repo = new InMemoryUserRepository();
$repo->save(new User(1, "Alice", "alice@example.com"));
$repo->save(new User(2, "Bob", "bob@example.com"));

echo $repo->find(1)->name . "\n";
echo count($repo->findAll());

Wynik:

Alice
2

Piękno tego wzorca polega na tym, że możesz wymieniać implementacje bez zmieniania logiki biznesowej. Chcesz przejść z przechowywania danych w pamięci na bazę danych? Utwórz nową klasę repozytorium implementującą ten sam interfejs. Kod aplikacji pozostaje nietknięty, ponieważ zależy od interfejsu, a nie od konkretnej implementacji.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system ewidencji produktów z wykorzystaniem wzorca Repository. Utworzysz wyraźny podział między obiektami domenowymi a sposobem ich przechowywania, dzięki czemu kod aplikacji będzie mógł pracować z produktami bez znajomości szczegółów przechowywania.

Podzielisz kod na cztery pliki:

  • Product.php: Utwórz klasę Product reprezentującą produkty w Twoim magazynie. Każdy produkt ma id (int), name (string) i price (float). Użyj promocji konstruktora z publicznymi właściwościami, aby ułatwić dostęp.
  • ProductRepositoryInterface.php: Zdefiniuj ProductRepositoryInterface, który określa kontrakt dla każdej implementacji przechowywania produktów. Twój interfejs powinien deklarować następujące metody:
    • find(int $id): ?Product: Pobierz produkt według ID albo null, jeśli nie został znaleziony
    • findAll(): array: Pobierz wszystkie produkty jako tablicę
    • save(Product $product): void: Zapisz lub zaktualizuj produkt
    • delete(int $id): void: Usuń produkt według ID
  • InMemoryProductRepository.php: Dołącz zarówno klasę Product, jak i interfejs. Utwórz klasę InMemoryProductRepository, która implementuje interfejs, używając prywatnej tablicy do przechowywania produktów. Produkty powinny być indeksowane według ich ID, aby umożliwić szybkie wyszukiwanie. Metoda findAll() powinna zwracać wyłącznie obiekty produktów (użyj array_values(), aby zresetować klucze tablicy).
  • main.php: Dołącz plik repozytorium. Otrzymasz dwa wejścia: najpierw ciąg JSON z produktami do dodania, a następnie, w osobnym wierszu, całkowitą liczbę ID produktu do wyszukania.

    Format JSON będzie następujący:

    [{"id": 1, "name": "Laptop", "price": 999.99}, {"id": 2, "name": "Mouse", "price": 29.99}]

    Utwórz InMemoryProductRepository, zapisz wszystkie produkty z wejścia JSON, a następnie użyj drugiego wejścia (ID), aby znaleźć konkretny produkt. Wypisz wyniki w tym formacie:

    Total products: [count]
    Found: [name] - $[price]

    Sformatuj cenę do dwóch miejsc po przecinku. Jeśli produkt nie zostanie znaleziony, wypisz Found: Not found.

Wzorzec Repository sprawdza się, gdy trzeba zamienić jedną implementację przechowywania danych na inną. Główny kod zależy wyłącznie od interfejsu: przejście z przechowywania w pamięci na bazę danych wymagałoby utworzenia nowej klasy repozytorium bez zmieniania jakiejkolwiek logiki aplikacji.

Spróbuj swoich sił

<?php

require_once 'InMemoryProductRepository.php';

// Odczytaj dane wejściowe
$jsonInput = trim(fgets(STDIN));
$searchId = intval(trim(fgets(STDIN)));

// Przekształć dane wejściowe JSON w tablicę
$productsData = (array)json_decode($jsonInput, true);

// TODO: Utwórz instancję InMemoryProductRepository

// TODO: Przejdź przez $productsData i zapisz każdy produkt
// Każdy element ma klucze 'id', 'name' i 'price'

// TODO: Pobierz wszystkie produkty i wypisz ich łączną liczbę
// Format: "Total products: [count]"

// TODO: Znajdź produkt o identyfikatorze $searchId
// Jeśli zostanie znaleziony, wypisz: "Found: [name] - $[price]" (cenę sformatuj do 2 miejsc po przecinku)
// Jeśli nie zostanie znaleziony, wypisz: "Found: Not found"

?>
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator PHP online