PATRÓN REPOSITORY EN PHP: QUÉ ES Y CÓMO IMPLEMENTARLO

En este post se muestra un ejemplo del Patrón Repository en PHP.

Estructura de carpetas recomendada

src/
├── Domain/
│   └── User.php
├── Infrastructure/
│   └── Persistence/
│  ├── UserRepository.php
│  └── UserRepositoryInterface.php
└── index.php

Entidad (Domain)

// src/Domain/User.php
namespace App\Domain;
class User
{
    public function __construct(
   public readonly ?int $id,
   public string $name,
   public string $email
    ) {}
}

Interfaz del Repository

// src/Infrastructure/Persistence/UserRepositoryInterface.php
namespace App\Infrastructure\Persistence;

use App\Domain\User;

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

Implementación con MySQL (PDO)

// src/Infrastructure/Persistence/UserRepository.php
namespace App\Infrastructure\Persistence;

use App\Domain\User;
use PDO;
use PDOException;

class UserRepository implements UserRepositoryInterface
{
    private PDO $db;

    public function __construct(PDO $db)
    {
   $this->db = $db;
    }

    public function findById(int $id): ?User
    {
   $stmt = $this->db->prepare("SELECT * FROM users WHERE id = :id");
   $stmt->execute(['id' => $id]);
   $data = $stmt->fetch(PDO::FETCH_ASSOC);

   if (!$data) {
  return null;
   }

   return new User(
  (int)$data['id'],
  $data['name'],
  $data['email']
   );
    }

    public function findAll(): array
    {
   $stmt = $this->db->query("SELECT * FROM users");
   $users = [];

   while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
  $users[] = new User(
      (int)$data['id'],
      $data['name'],
      $data['email']
  );
   }

   return $users;
    }

    public function save(User $user): void
    {
   if ($user->id === null) {
  // Insertar nuevo usuario
  $stmt = $this->db->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
  $stmt->execute([
      'name' => $user->name,
      'email' => $user->email
  ]);
   } else {
  // Actualizar usuario existente
  $stmt = $this->db->prepare("UPDATE users SET name = :name, email = :email WHERE id = :id");
  $stmt->execute([
      'id' => $user->id,
      'name' => $user->name,
      'email' => $user->email
  ]);
   }
    }

    public function delete(int $id): bool
    {
   $stmt = $this->db->prepare("DELETE FROM users WHERE id = :id");
   return $stmt->execute(['id' => $id]);
    }
}

Uso (index.php)

// index.php
require_once __DIR__ . '/vendor/autoload.php'; //Si se usaComposer

use App\Domain\User;
use App\Infrastructure\Persistence\UserRepository;
use PDO;

// Configuración de la base de datos
try {
    $pdo = new PDO(
   'mysql:host=localhost;dbname=mi_app;charset=utf8mb4',
   'root',      // usuario
   '',     // contraseña
   [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );
} catch (PDOException $e) {
    die("Error de conexión: " . $e->getMessage());
}

// Crear el Repository
$repository = new UserRepository($pdo);

// === Ejemplos de uso ===

// Crear usuario
$newUser = new User(null, "Carlos Ramírez", "carlos@example.com");
$repository->save($newUser);

echo "Usuario guardado correctamente!
"; // Buscar por ID $user = $repository->findById(1); if ($user) { echo "Usuario encontrado: {$user->name} - {$user->email}
"; } // Listar todos echo "Todos los usuarios:"; foreach ($repository->findAll() as $u) { echo "- {$u->name} ({$u->email})
"; }

Tabla en MySQL

CREATE DATABASE mi_app CHARACTER SET utf8mb4;

USE mi_app;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);