👍📃 Laravel Advanced: Little Known Relationships - hasOneThrough() and hasManyThrough()

https://laravel.com/docs/11.x/eloquent-relationships

Có lẽ bạn đã từng sử dụng các mối quan hệ hasOne, hasMany, belongsTobelongsToMany trong các dự án của mình. Nhưng bạn có biết Laravel cũng cung cấp các mối quan hệ hasOneThroughhasManyThrough? Chúng rất lý tưởng để truy cập các mối quan hệ lồng nhau mà không cần thêm thao tác phức tạp. Hãy cùng phân tích chi tiết hơn.

Hãy tưởng tượng bạn có một ứng dụng quản lý dự án với các bảng sau:

Users: Đại diện cho người dùng trong hệ thống.
Projects: Mỗi người dùng có thể có nhiều dự án.
Tasks: Mỗi dự án có thể có nhiều nhiệm vụ.
Statuses: Mỗi nhiệm vụ có một trạng thái (ví dụ: đang chờ xử lý, đã hoàn thành).

Thiết lập Mô hình & Mối quan hệ

Hãy định nghĩa các mô hình và mối quan hệ của chúng trong dự án Laravel của chúng ta.

🟡 Project Model

<?php
class Project extends Model
{
  public function user()
  {
    return $this->belongsTo(User::class);
  }
  public function tasks()
  {
    return $this->hasMany(Task::class);
  }
}

🟡 Task Model

🟡 Status Model

🔴 User Model

Using hasOneThrough

You can access the status of a task directly from a user:

Nó lấy trạng thái của tác vụ đầu tiên mà nó gặp (dựa trên thứ tự truy vấn cơ sở dữ liệu).

Using hasManyThrough

Trong mô hình User, chúng ta đã sử dụng hasManyThrough để lấy tất cả các nhiệm vụ của một người dùng, mặc dù các nhiệm vụ có liên quan trực tiếp đến dự án. Sau đây là cách bạn có thể sử dụng nó:

Các mối quan hệ hasOneThroughhasManyThrough có thể đơn giản hóa mã của bạn để dễ dàng truy cập các mối quan hệ lồng nhau sâu. Chúng rất phù hợp cho các trường hợp bạn cần duyệt qua nhiều cấp độ quan hệ.

Ví dụ, trong ứng dụng sửa chữa xe Vehicle, mỗi mô hình thợ sửa xe Mechanic có thể được liên kết với một mô hình Car, và mỗi mô hình Car có thể được liên kết với một mô hình người sở hữu Owner. Mặc dù cơ sở dữ liệu không có mối quan hệ trực tiếp giữa mechanic owner, nhưng mechanic có thể truy cập owner thông qua mô hình Car. Hãy xem xét các bảng cần thiết để định nghĩa mối quan hệ này:

Giờ chúng ta đã xem xét cấu trúc bảng cho mối quan hệ này, hãy định nghĩa mối quan hệ đó trên mô hình Mechanic:

Tham số đầu tiên được truyền cho phương thức hasOneThrough là tên của mô hình cuối cùng mà chúng ta muốn truy cập, trong khi tham số thứ hai là tên của mô hình trung gian.

Hoặc, nếu các mối quan hệ liên quan đã được định nghĩa trên tất cả các mô hình tham gia vào mối quan hệ, bạn có thể định nghĩa một mối quan hệ "has-one-through" một cách linh hoạt bằng cách gọi phương thức through và cung cấp tên của các mối quan hệ đó. Ví dụ, nếu mô hình Mechanic có mối quan hệ cars và mô hình Car có mối quan hệ owner, bạn có thể định nghĩa một mối quan hệ "has-one-through" kết nối mechanic owner như sau:

Các quy ước chính

Các quy ước khoá ngoại thông thường của Eloquent sẽ được sử dụng khi thực hiện các truy vấn của mối quan hệ. Nếu bạn muốn tuỳ chỉnh các khoá của mối quan hệ, bạn có thể truyền chúng dưới dạng đối số thứ ba và thứ tư vào phương thức hasOneThrough. Đối số thứ ba là tên của khoá ngoại trên mô hình trung gian. Đối số thứ tư là tên của khoá ngoại trên mô hình cuối cùng. Đối số thứ năm là khoá nội bộ, trong khi đối số thứ sáu là khoá nội bộ của mô hình trung gian.

Hoặc, như đã thảo luận trước đó, nếu các mối quan hệ liên quan đã được định nghĩa trên tất cả các mô hình tham gia vào mối quan hệ, bạn có thể định nghĩa một mối quan hệ "has-one-through" một cách linh hoạt bằng cách gọi phương thức through và cung cấp tên của các mối quan hệ đó. Cách tiếp cận này mang lại lợi thế là tái sử dụng các quy ước khoá đã được định nghĩa trên các mối quan hệ hiện có.

Mối quan hệ "has-many-through" cung cấp một cách tiện lợi để truy cập các mối quan hệ xa thông qua một mối quan hệ trung gian. Ví dụ, giả sử chúng ta đang xây dựng một nền tảng triển khai như Laravel Vaporarrow-up-right. Mô hình Project có thể truy cập nhiều mô hình Deployment thông qua một mô hình trung gian là Environment. Sử dụng ví dụ này, bạn có thể dễ dàng thu thập tất cả các lần triển khai cho một dự án cụ thể. Hãy cùng xem các bảng cần thiết để định nghĩa mối quan hệ này:

Bây giờ chúng ta đã xem xét cấu trúc bảng cho mối quan hệ, hãy cùng định nghĩa mối quan hệ trên mô hình Project:

Đối số đầu tiên được truyền vào phương thức hasManyThrough là tên của mô hình cuối cùng mà chúng ta muốn truy cập, trong khi đối số thứ hai là tên của mô hình trung gian.

Hoặc, nếu các mối quan hệ liên quan đã được định nghĩa trên tất cả các mô hình tham gia vào mối quan hệ, bạn có thể định nghĩa một mối quan hệ "has-many-through" một cách linh hoạt bằng cách gọi phương thức through và cung cấp tên của các mối quan hệ đó. Ví dụ, nếu mô hình Project có mối quan hệ environments và mô hình Environment có mối quan hệ deployments, bạn có thể định nghĩa một mối quan hệ "has-many-through" kết nối project và deployments như sau:

Mặc dù bảng của mô hình Deployment không chứa cột project_id, mối quan hệ hasManyThrough cung cấp quyền truy cập vào các deployment của một project thông qua $project->deployments. Để truy xuất các mô hình này, Eloquent kiểm tra cột project_id trên bảng của mô hình trung gian Environment. Sau khi tìm thấy các ID môi trường liên quan, chúng được sử dụng để truy vấn bảng của mô hình Deployment.

Các quy ước chính

Các quy ước khoá ngoại thông thường của Eloquent sẽ được sử dụng khi thực hiện các truy vấn của mối quan hệ. Nếu bạn muốn tuỳ chỉnh các khoá của mối quan hệ, bạn có thể truyền chúng dưới dạng đối số thứ ba và thứ tư vào phương thức hasManyThrough. Đối số thứ ba là tên của khoá ngoại trên mô hình trung gian. Đối số thứ tư là tên của khoá ngoại trên mô hình cuối cùng. Đối số thứ năm là khoá nội bộ, trong khi đối số thứ sáu là khoá nội bộ của mô hình trung gian.

Hoặc, như đã thảo luận trước đó, nếu các mối quan hệ liên quan đã được định nghĩa trên tất cả các mô hình tham gia vào mối quan hệ, bạn có thể định nghĩa một mối quan hệ "has-many-through" một cách linh hoạt bằng cách gọi phương thức through và cung cấp tên của các mối quan hệ đó. Cách tiếp cận này mang lại lợi thế là tái sử dụng các quy ước khoá đã được định nghĩa trên các mối quan hệ hiện có.

Mối quan hệ có phạm vi (Scoped Relationships)

Việc thêm các phương thức bổ sung vào mô hình để ràng buộc các mối quan hệ là rất phổ biến. Ví dụ, bạn có thể thêm một phương thức featuredPosts vào mô hình User để ràng buộc mối quan hệ posts rộng hơn với một điều kiện where bổ sung:

Tuy nhiên, nếu bạn cố gắng tạo một mô hình thông qua phương thức featuredPosts, thuộc tính featured của nó sẽ không được thiết lập thành true. Nếu bạn muốn tạo các mô hình thông qua các phương thức mối quan hệ và cũng chỉ định các thuộc tính nên được thêm vào tất cả các mô hình được tạo ra qua mối quan hệ đó, bạn có thể sử dụng phương thức withAttributes khi xây dựng truy vấn mối quan hệ.

Phương thức withAttributes sẽ thêm các điều kiện where vào truy vấn sử dụng các thuộc tính đã cho, và nó cũng sẽ thêm các thuộc tính đã cho vào bất kỳ mô hình nào được tạo ra thông qua phương thức mối quan hệ.

Last updated