The Repository Design Pattern is a commonly used pattern in PHP to separate the business logic from the data access logic. By implementing this pattern, developers can create code that’s easier to maintain, test, and extend. In this blog, we’ll dive into the basics of the Repository Design Pattern, how to implement it in PHP 8.3, and why it's beneficial for building scalable applications.

What is Repository Design Pattern?

The Repository Design Pattern acts as an abstraction layer between the data access logic and the business logic of an application. It provides a way to interact with data sources (like databases, APIs, or even files) in a clean and organized way.

In a typical PHP application, we might write SQL queries directly in our business logic, which can make the code harder to manage and test. By using a Repository, we create a single source of truth for all database operations, making the codebase more modular and maintainable.

Benefits of the Repository Design Pattern

Some key benefits of using the Repository pattern include:

  • Decoupling: It decouples the data access logic from the business logic, making each layer easier to manage.
  • Testability: It allows for mocking data access in unit tests, enabling us to test business logic without needing a real database connection.
  • Maintainability: With a dedicated class handling data access, it's easier to make changes to the underlying data source without affecting business logic.

Setting Up the Project

For this example, we’ll build a simple PHP 8.3 application that uses the Repository pattern to manage User data in a MySQL database.

Directory Structure

src/
│
├── Models/
│   └── User.php
│
├── Repositories/
│   ├── UserRepositoryInterface.php
│   └── MySQLUserRepository.php
│
└── Services/
    └── UserService.php

We'll follow these steps to implement the Repository Design Pattern in our PHP application.

 

Creating the Repository Interface

The first step in implementing the Repository pattern is to define an interface for the repository. This interface will define the methods our repository class should implement, providing a contract for interacting with User data.

<?php
// src/Repositories/UserRepositoryInterface.php

declare(strict_types=1);

namespace App\Repositories;

use App\Models\User;

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

 

Implementing the Repository Class

Next, we’ll create a concrete implementation of UserRepositoryInterface. For this example, we’ll use MySQL as our data source.

<?php
// src/Repositories/MySQLUserRepository.php

declare(strict_types=1);

namespace App\Repositories;

use App\Models\User;
use PDO;
use PDOException;

class MySQLUserRepository implements UserRepositoryInterface
{
    private PDO $connection;

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

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

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

    public function findAll(): array
    {
        $stmt = $this->connection->query("SELECT * FROM users");
        $data = $stmt->fetchAll();

        return array_map(fn($user) => new User($user['id'], $user['name'], $user['email']), $data);
    }

    public function save(User $user): bool
    {
        try {
            if ($user->getId()) {
                $stmt = $this->connection->prepare("UPDATE users SET name = :name, email = :email WHERE id = :id");
                return $stmt->execute([
                    'id' => $user->getId(),
                    'name' => $user->getName(),
                    'email' => $user->getEmail()
                ]);
            } else {
                $stmt = $this->connection->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
                $stmt->execute([
                    'name' => $user->getName(),
                    'email' => $user->getEmail()
                ]);
                $user->setId((int) $this->connection->lastInsertId());
                return true;
            }
        } catch (PDOException $e) {
            return false;
        }
    }

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

In this class, we implemented all the methods from the UserRepositoryInterface interface. The methods use PDO to interact with the database and map database records to User model objects.

 

Using the Repository in a Service

Now that we have a repository, we can use it in a service layer to manage business logic. This layer calls the repository, which separates the data access logic from the business logic.

<?php
// src/Services/UserService.php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\UserRepositoryInterface;
use App\Models\User;

class UserService
{
    private UserRepositoryInterface $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUserById(int $id): ?User
    {
        return $this->userRepository->find($id);
    }

    public function getAllUsers(): array
    {
        return $this->userRepository->findAll();
    }

    public function createUser(string $name, string $email): User
    {
        $user = new User(null, $name, $email);
        $this->userRepository->save($user);

        return $user;
    }

    public function updateUser(int $id, string $name, string $email): bool
    {
        $user = $this->userRepository->find($id);
        if ($user) {
            $user->setName($name);
            $user->setEmail($email);
            return $this->userRepository->save($user);
        }
        return false;
    }

    public function deleteUser(int $id): bool
    {
        return $this->userRepository->delete($id);
    }
}

 

Conclusion

The Repository Design Pattern is a valuable approach for structuring data access in PHP applications. By using a repository, we can separate concerns, making the code more testable and maintainable.

This is especially useful for larger applications where data access can get complex and spread across various parts of the code. With the Repository Design Pattern, data access logic is centralized, making it easier to maintain and scale the application over time.

With PHP 8.3, you can take advantage of strict typing, improved exception handling, and enhanced readability, making this approach even more effective and clear for modern PHP projects.

Category : #php

Tags : #php

0 Shares
pic

👋 Hi, Introducing Zuno PHP Framework. Zuno Framework is a lightweight PHP framework designed to be simple, fast, and easy to use. It emphasizes minimalism and speed, which makes it ideal for developers who want to create web applications without the overhead that typically comes with more feature-rich frameworks.

Related content