Modello Repository
Fa parte della sezione Programmazione orientata agli oggetti del percorso PHP di Coddy. Lezione 81 di 91.
Il Repository Pattern è un pattern di progettazione che funge da intermediario tra la logica di business della tua applicazione e l'archiviazione dei dati. Fornisce un'interfaccia simile a una collezione per accedere agli oggetti di dominio, nascondendo i dettagli di come i dati vengono effettivamente archiviati o recuperati.
Pensa a un repository come a una raccolta specializzata che sa come rendere persistenti e recuperare gli oggetti. Il codice della tua applicazione chiede al repository un utente tramite ID o salva un nuovo prodotto, senza sapere se i dati risiedono in un database, in un file o in un'API. Questa separazione rende il tuo codice più facile da testare e più flessibile.
<?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
) {}
}
L'implementazione del repository gestisce il meccanismo di archiviazione effettivo:
<?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());
Output:
Alice
2Il bello di questo pattern è che puoi sostituire le implementazioni senza modificare la logica di business. Devi passare dall'archiviazione in memoria a un database? Crea una nuova classe repository che implementi la stessa interfaccia. Il codice della tua applicazione rimane intatto perché dipende dall'interfaccia, non dall'implementazione concreta.
Sfida
FacileCostruiamo un sistema di inventario dei prodotti usando il Repository Pattern. Creerai una netta separazione tra gli oggetti del dominio e il modo in cui vengono archiviati, così il codice della tua applicazione potrà lavorare con i prodotti senza conoscere i dettagli dell’archiviazione.
Organizzerai il codice in quattro file:
Product.php: Crea una classeProductche rappresenti gli articoli del tuo inventario. Ogni prodotto ha unid(int), unname(string) e unprice(float). Usa la promozione dei parametri del costruttore con proprietà pubbliche per facilitare l’accesso.ProductRepositoryInterface.php: Definisci un’interfacciaProductRepositoryInterfaceche stabilisca il contratto per qualsiasi implementazione dell’archiviazione dei prodotti. La tua interfaccia dovrebbe dichiarare questi metodi:find(int $id): ?Product: Recupera un prodotto tramite ID, oppure null se non viene trovatofindAll(): array: Ottieni tutti i prodotti come arraysave(Product $product): void: Archivia o aggiorna un prodottodelete(int $id): void: Rimuovi un prodotto tramite ID
InMemoryProductRepository.php: Includi sia la classe Product sia l’interfaccia. Crea una classeInMemoryProductRepositoryche implementi l’interfaccia usando un array privato per archiviare i prodotti. I prodotti dovrebbero essere indicizzati tramite il loro ID per consentire ricerche efficienti. Il metodofindAll()dovrebbe restituire solo gli oggetti prodotto (usaarray_values()per reimpostare le chiavi dell’array).main.php: Includi il file del repository. Riceverai due input: prima una stringa JSON con i prodotti da aggiungere, poi, su una riga separata, l’ID intero da cercare.Il formato JSON sarà:
[{"id": 1, "name": "Laptop", "price": 999.99}, {"id": 2, "name": "Mouse", "price": 29.99}]Crea un
InMemoryProductRepository, salva tutti i prodotti dall’input JSON, poi usa il secondo input (l’ID) per trovare un prodotto specifico. Stampa i risultati in questo formato:Total products: [count] Found: [name] - $[price]Formatta il prezzo con due cifre decimali. Se il prodotto non viene trovato, stampa
Found: Not found.
Il Repository Pattern è particolarmente utile quando devi sostituire le implementazioni di archiviazione. Il codice principale dipende solo dall’interfaccia: passare dall’archiviazione in memoria a un database significherebbe creare una nuova classe repository senza modificare alcuna logica dell’applicazione.
Provalo tu
<?php
require_once 'InMemoryProductRepository.php';
// Leggi l'input
$jsonInput = trim(fgets(STDIN));
$searchId = intval(trim(fgets(STDIN)));
// Converti l'input JSON in un array
$productsData = (array)json_decode($jsonInput, true);
// TODO: Crea un'istanza di InMemoryProductRepository
// TODO: Scorri $productsData e salva ogni prodotto
// Ogni elemento ha le chiavi 'id', 'name' e 'price'
// TODO: Ottieni tutti i prodotti e stampa il numero totale
// Formato: "Total products: [count]"
// TODO: Trova il prodotto con $searchId
// Se trovato, stampa: "Found: [name] - $[price]" (con il prezzo formattato a 2 cifre decimali)
// Se non trovato, stampa: "Found: Not found"
?>Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave $thisMetodiProprietàCostruttore (__construct)Distruttore (__destruct)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa parola chiave parent::Sovrascrittura dei metodiLa parola chiave finalClassi astratteRiepilogo - Gerarchia dei dipendenti7Incapsulamento
Pubblico, Protetto, PrivatoApprofondimento sui modificatori di accessoGetter e SetterOccultamento delle informazioniPromozione dei parametri del costruttore (8.0)Riepilogo - Sistema di gestione dei registri degli studenti10Concetti avanzati di programmazione a oggetti
Composizione vs ereditarietàDependency InjectionClassi anonimeEnumerazioni (PHP 8.1)Fibers (PHP 8.1)Approfondimento sulla clonazione degli oggettiGeneratori e iteratori13Modelli di progettazione, parte 2
Modello CommandModello AdapterModello DecoratorModello Template MethodModello StateModello CompositeModello Repository2Namespace e autoloading
Introduzione ai namespaceLa keyword useStandard di autoloading PSR-4Autoloader di ComposerRiepilogo - Progetto organizzato5Interfacce e contratti
Introduzione alle interfacceImplementare le interfacceImplementare più interfacceInterfaccia vs classe astrattaType hinting con le interfacceRiepilogo - Calcolatore di forme8Metodi magici
Introduzione ai metodi magici__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e clonazione degli oggetti__serialize e __unserializeRiepilogo - Collezione personalizzata11Sistema dei tipi e gestione degli errori
Dichiarazioni di tipoTipi nullableTipi unione e intersezioneClassi di eccezioneGerarchia di eccezioni personalizzataTry, Catch, FinallyRiepilogo - Validatore di moduli14Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente3Proprietà delle classi
Proprietà di istanza e staticheCostanti nelle classiMetodi e proprietà staticiProprietà private e protectedProprietà readonly (PHP 8.1)Riepilogo - Gestore di conti bancari6Polimorfismo
Ridefinizione dei metodi, ripresaPolimorfismo tramite interfacceSuggerimenti sui tipi e tipi UnionBinding statico tardivoRiepilogo - Processore di pagamenti9Tratti
Introduzione ai trattiUtilizzare più trattiRisoluzione dei conflitti tra trattiMetodi astratti nei trattiTratti vs ereditarietà12Design pattern - Parte 1
Introduzione ai design patternPattern SingletonPattern FactoryPattern ObserverPattern StrategyEsercitati da solo: Compilatore PHP online