Implementing the Data Mapper Pattern to Decouple Business Logic from Persistence Layer in Php

The Data Mapper pattern is a design technique used in software development, particularly in PHP applications, to separate business logic from data persistence. This separation improves code maintainability, testability, and scalability by isolating how data is stored and retrieved from the core business rules.

Understanding the Data Mapper Pattern

The core idea of the Data Mapper pattern is to use a dedicated layer—called the Data Mapper—to transfer data between objects and a database without the objects needing to know about the database details. This approach contrasts with the Active Record pattern, where objects themselves handle database operations.

Benefits of Using the Data Mapper Pattern

  • Decoupling: Separates business logic from data access code.
  • Testability: Business logic can be tested independently of the database.
  • Flexibility: Changes in database schema or storage methods require minimal modifications to business logic.
  • Maintainability: Clear separation of concerns simplifies code management.

Implementing the Data Mapper in PHP

Implementing the Data Mapper pattern involves creating three main components:

  • Domain Objects: Represent the business entities.
  • Data Mapper Classes: Handle data transfer between objects and the database.
  • Database Layer: The actual database connection and queries.

Example: User Entity

Suppose we have a User class representing a user in our application:

class User {
    public $id;
    public $name;
    public $email;

    public function __construct($id = null, $name = '', $email = '') {
        $this->id = $id;
        $this->name = $name;
        $this->email = $email;
    }
}

Creating the Data Mapper Class

The Data Mapper for the User class manages database interactions:

class UserMapper {
    protected $pdo;

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

    public function findById($id) {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->execute([':id' => $id]);
        $row = $stmt->fetch();

        if ($row) {
            return new User($row['id'], $row['name'], $row['email']);
        }
        return null;
    }

    public function save(User $user) {
        if ($user->id) {
            $stmt = $this->pdo->prepare('UPDATE users SET name = :name, email = :email WHERE id = :id');
            $stmt->execute([
                ':name' => $user->name,
                ':email' => $user->email,
                ':id' => $user->id
            ]);
        } else {
            $stmt = $this->pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
            $stmt->execute([
                ':name' => $user->name,
                ':email' => $user->email
            ]);
            $user->id = $this->pdo->lastInsertId();
        }
    }
}

Conclusion

Implementing the Data Mapper pattern in PHP helps create a clean architecture by decoupling business logic from data storage. This approach not only makes your code more maintainable but also facilitates testing and future modifications, ensuring your application remains robust and adaptable.