© 2026 Laravel

Design Pattern - Repository là gì? Áp dụng chuẩn Architect trong PHP & Laravel

4 phút đọc 2 lượt xem
#pattern-repository

#Repository Pattern

Repository Pattern là một abstraction layer nằm giữa domain/business logicdata source (DB, API, cache).

Mục tiêu:

  • Tách business logic khỏi persistence
  • Tạo boundary rõ ràng
  • Giúp test dễ dàng
  • Cho phép thay đổi data source mà không ảnh hưởng logic

#1. Bản chất thật sự của Repository

#1.1 Repository KHÔNG phải là “class query DB”

Sai lầm phổ biến:

class UserRepository {
    public function getAllUsers() {
        return DB::table('users')->get();
    }
}

👉 Đây chỉ là wrapper, không phải repository đúng nghĩa.

#1.2 Định nghĩa đúng

Repository là:

Một abstraction cung cấp interface giống collection cho domain object

Ví dụ:

$order = $orderRepository->find($id);
$orderRepository->save($order);

👉 Domain không biết DB là MySQL hay Redis

#2. Vai trò trong kiến trúc (Clean Architecture)

#2.1 Layering

  • Controller → Interface
  • Service → Application
  • Repository → Infrastructure
  • Entity → Domain

👉 Repository nằm ở boundary giữa Application và Infrastructure

#2.2 Dependency Inversion

Service phụ thuộc vào abstraction:

class OrderService {
    public function __construct(OrderRepository $repo) {}
}

👉 Không phụ thuộc MySQL / Mongo / API

#3. Ví dụ PHP thuần (chuẩn domain-driven)

#Entity

class Order {
    public function __construct(
        public ?int $id,
        public int $userId,
        public float $total,
        public string $status
    ) {}

    public function cancel(): void {
        if ($this->status !== 'pending') {
            throw new Exception('Cannot cancel');
        }
        $this->status = 'cancelled';
    }
}

#Repository Interface

interface OrderRepository {
    public function find(int $id): ?Order;
    public function save(Order $order): Order;
}

#Implementation (MySQL)

class MysqlOrderRepository implements OrderRepository {
    public function find(int $id): ?Order {
        $row = DB::table('orders')->find($id);
        if (!$row) return null;

        return new Order($row->id, $row->user_id, $row->total, $row->status);
    }

    public function save(Order $order): Order {
        if ($order->id) {
            DB::table('orders')->where('id', $order->id)->update([
                'total' => $order->total,
                'status' => $order->status
            ]);
        } else {
            $order->id = DB::table('orders')->insertGetId([
                'user_id' => $order->userId,
                'total' => $order->total,
                'status' => $order->status
            ]);
        }

        return $order;
    }
}

#Service

class OrderService {
    public function __construct(private OrderRepository $repo) {}

    public function cancel(int $id): Order {
        $order = $this->repo->find($id);

        if (!$order) throw new Exception('Not found');

        $order->cancel();

        return $this->repo->save($order);
    }
}

#4. Áp dụng trong Laravel (thực tế)

#4.1 Sai lầm phổ biến

interface UserRepositoryInterface {}
class UserRepository implements UserRepositoryInterface {}

👉 Không có nhiều implementation → useless abstraction

#4.2 Laravel đã có Eloquent

Eloquent chính là:

  • Active Record
  • Data Mapper hybrid

👉 Nhiều trường hợp KHÔNG cần Repository

#4.3 Khi nào nên dùng Repository trong Laravel

✔ Multi data source ✔ Complex query logic ✔ Domain isolation ✔ Testing phức tạp

#4.4 Ví dụ chuẩn

interface OrderRepository {
    public function find(int $id): ?Order;
}

class EloquentOrderRepository implements OrderRepository {
    public function find(int $id): ?Order {
        return OrderModel::find($id)?->toDomain();
    }
}

#5. Advanced Patterns kết hợp

#5.1 Repository + Unit of Work

  • Track changes
  • Commit 1 lần

#5.2 Repository + Specification

  • Query reusable

#5.3 Repository + Cache

class CachedOrderRepository implements OrderRepository {
    public function __construct(private OrderRepository $repo) {}
}

#6. Anti-pattern cực nguy hiểm

#6.1 Generic Repository overuse

interface Repository<T>

👉 Mất domain meaning

#6.2 Anemic repository

Chỉ CRUD → không có value

#6.3 Repository chứa business logic

Sai boundary

#7. Trade-off (rất quan trọng)

#Ưu điểm

  • Testable
  • Flexible
  • Clean architecture

#Nhược điểm

  • Boilerplate
  • Over-engineering
  • Performance overhead

#8. Khi nào KHÔNG nên dùng Repository

  • CRUD đơn giản
  • Dự án nhỏ
  • Không cần abstraction

#9. Tips & Tricks

  • Repository nên return domain object
  • Không return raw array
  • Không expose query builder
  • Naming rõ ràng (OrderRepository)

#10. Interview Questions

Repository Pattern là gì?

Summary:

  • Abstraction data access

Deep:

  • Tách domain khỏi persistence
Khi nào nên dùng Repository?

Summary:

  • Khi complexity cao

Deep:

  • Multi source
  • Domain isolation
Tại sao Laravel không luôn cần Repository?

Summary:

  • Vì Eloquent đủ dùng

Deep:

  • Active Record đã handle nhiều case

#11. Kết luận

Repository Pattern là công cụ mạnh nhưng dễ bị lạm dụng.

Dùng đúng:

  • Code clean
  • Dễ test
  • Scale tốt

Dùng sai:

  • Over-engineering
  • Tăng complexity

👉 Senior biết dùng 👉 Architect biết khi KHÔNG dùng