Menu
Coddy logo textTech

Patron Repository

Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy — leçon 81 sur 91.

Le Repository Pattern est un patron de conception qui sert de médiateur entre la logique métier de votre application et le stockage des données. Il fournit une interface de type collection pour accéder aux objets du domaine, masquant les détails sur la manière dont les données sont réellement stockées ou récupérées.

Considérez un repository comme une collection spécialisée qui sait comment persister et récupérer des objets. Le code de votre application demande au repository un utilisateur par son ID ou enregistre un nouveau produit, sans savoir si les données résident dans une base de données, un fichier ou une API. Cette séparation rend votre code plus testable et flexible.

<?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'implémentation du dépôt (repository) gère le mécanisme de stockage réel :

<?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());

Résultat :

Alice
2

La beauté de ce patron de conception est que vous pouvez interchanger les implémentations sans modifier votre logique métier. Besoin de passer d'un stockage en mémoire à une base de données ? Créez une nouvelle classe repository implémentant la même interface. Le code de votre application reste inchangé car il dépend de l'interface, et non de l'implémentation concrète.

challenge icon

Défi

Facile

Construisons un système d'inventaire de produits en utilisant le Repository Pattern. Vous allez créer une séparation nette entre vos objets de domaine et la manière dont ils sont stockés, permettant à votre code d'application de manipuler les produits sans connaître les détails du stockage.

Vous organiserez votre code sur quatre fichiers :

  • Product.php — Créez une classe Product représentant les articles de votre inventaire. Chaque produit possède un id (int), un name (string) et un price (float). Utilisez la promotion de constructeur avec des propriétés publiques pour un accès facile.
  • ProductRepositoryInterface.php — Définissez une ProductRepositoryInterface qui établit le contrat pour toute implémentation de stockage de produits. Votre interface doit déclarer ces méthodes :
    • find(int $id): ?Product — Récupère un produit par son ID, ou null s'il n'est pas trouvé
    • findAll(): array — Récupère tous les produits sous forme de tableau
    • save(Product $product): void — Stocke ou met à jour un produit
    • delete(int $id): void — Supprime un produit par son ID
  • InMemoryProductRepository.php — Incluez à la fois la classe Product et l'interface. Créez une classe InMemoryProductRepository qui implémente l'interface en utilisant un tableau privé pour stocker les produits. Les produits doivent être indexés par leur ID pour une recherche efficace. La méthode findAll() doit retourner uniquement les objets produits (utilisez array_values() pour réinitialiser les clés du tableau).
  • main.php — Incluez le fichier du dépôt. Vous recevrez une entrée : une chaîne JSON contenant un tableau de produits à ajouter, suivie d'un ID à rechercher.

    Le format JSON sera :

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

    Créez une instance de InMemoryProductRepository, sauvegardez tous les produits provenant de l'entrée JSON, puis utilisez la deuxième entrée (l'ID) pour trouver un produit spécifique. Affichez les résultats dans ce format :

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

    Formatez le prix avec deux décimales. Si le produit n'est pas trouvé, affichez Found: Not found à la place.

Le Repository Pattern prend tout son sens lorsque vous devez changer d'implémentation de stockage. Votre code principal ne dépend que de l'interface — passer d'un stockage en mémoire à une base de données signifierait créer une nouvelle classe de dépôt sans modifier la logique de l'application.

Aide-mémoire

Le Repository Pattern (ou patron de conception Répertoire) sert de médiateur entre la logique métier et le stockage des données, fournissant une interface de type collection pour accéder aux objets du domaine tout en masquant les détails d'implémentation du stockage.

Définissez une interface de répertoire qui établit le contrat pour l'accès aux données :

<?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;
}

Créez une classe de domaine en utilisant la promotion de constructeur :

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

Implémentez l'interface de répertoire avec un mécanisme de stockage concret :

<?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]);
    }
}

Utilisez le répertoire via son interface :

$repo = new InMemoryUserRepository();
$repo->save(new User(1, "Alice", "alice@example.com"));
$user = $repo->find(1);
$allUsers = $repo->findAll();

Ce patron permet d'échanger les implémentations sans modifier la logique métier — votre code dépend de l'interface, et non de l'implémentation concrète.

Essayez vous-même

<?php

require_once 'InMemoryProductRepository.php';

// Lire l'entrée
$jsonInput = trim(fgets(STDIN));
$searchId = intval(trim(fgets(STDIN)));

// Analyser l'entrée JSON dans un tableau
$productsData = (array)json_decode($jsonInput, true);

// TODO: Créer une instance de InMemoryProductRepository

// TODO: Parcourir $productsData et sauvegarder chaque produit
// Chaque élément possède les clés 'id', 'name' et 'price'

// TODO: Récupérer tous les produits et afficher le nombre total
// Format: "Total products: [count]"

// TODO: Trouver le produit avec $searchId
// Si trouvé, afficher: "Found: [name] - $[price]" (prix formaté à 2 décimales)
// Si non trouvé, afficher: "Found: Not found"

?>
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet