Relationships trong Eloquent

Bài trước chúng ta đã tìm hiểu về Eloquent ORM trong laravel rồi, thế nhưng vấn đề là trong khi lập trình các ứng dụng thực tế thì các bảng không độc lập với nhau mà sẽ có mối quan hệ với nhau. Và thật tuyệt vời Laravel cũng cung cấp cho chúng ta các mối quan hệ có sẵn để giảm thiểu thời gian cũng như công sức khi làm việc với database. Trong bài học này chúng ta sẽ tìm hiểu kỹ hơn về Relationships trong Eloquent trong Laravel các bạn nhé!

1. Các mối quan hệ trong Eloquent.

Từ phiên bản Laravel version 5.7 trở đi thay vì chỉ cung cấp cho chúng ta 3 mối quan hệ chính Laravel đã nâng cố các mối quan hệ chính lên mối quan hệ.

Bao gồm:

  • One to One : Một Một.
  • One to Many: Một nhiều.
  • Many to Many: Nhiều nhiều.
  • Has Many Through: Nhiều nhiều qua lại trung gian.
  • Polymorphic Relations: Đa hình.
  • Many To Many Polymorphic Relations : Nhiều nhiều đa hình.

Có vẻ hơi phức tạp đúng không mọi người? Để mình đi vào ví dụ cụ thể cho mọi người hiểu hơn nhé.

2. One To One.

Đây là mối quan hệ đơn giản nhất trong tất cả các mối quan hệ mà Laravel cung cấp.

Ví dụ: Chúng ta có một bảng Posts để đăng bài và một bảng Featured_images để đặt ảnh đại diện cho bài post đó . Mình sẽ tạo ra mối quan hệ 1- 1 như sau: một bài viết của mình chỉ có thể có một ảnh đại diện và ngược lại một ảnh đại diện mình sẽ chỉ dùng cho một bài viết.

Để làm điều này mình sẽ phải tạo 2 model là Posts.

{
    protected $table = 'Posts';
    
    public $timestamp = false;
    
    public function FeaturedImages()
    {
    	return $this->hasOne('App\FeaturedImages');
    }
}

  FeaturedImages:

{
    protected $table = 'FeaturedImages';
    
    public $timestamp = false;
}

Khi này các bạn chỉ cần triệu gọi với lệnh Eloquent dạng như sau:

App\Posts::find(1)->FeaturedImages;

Chú ý: Câu lệnh ở trên chỉ đúng nếu như khóa ngoại(forigen key) của bạn là FeaturedImages_id. Nhưng không sao Laravel vẫn cung cấp cho chúng ta tùy biến cột khóa ngoại với cú pháp như sau:

public function FeaturedImages()
{
    return $this->hasOne('App\FeaturedImages', 'foreign_key');
}

-Nhưng nếu như ở bảng FeaturedImages của bạn cũng không phải liên kết với Post qua cột id thì bạn có thể khai báo thêm cho Larvel bằng cách sau:

public function FeaturedImages()
{
    return $this->hasOne('App\FeaturedImages', 'foreign_key', 'local_key');
}

Định nghĩa các mối quan hệ đảo ngược.

Vì là mối quan hệ 1 vs 1  FearturedImages cũng chỉ thuộc về một bài post nên chúng ta hoàn toàn có thể khai báo định nghĩa đảo ngược lại với model FearturedImages như sau:

{
    protected $table = 'FeaturedImages';
    
    public $timestamp = false;
    
    public function posts()
    {
    	return $this->belongsto('App\Posts');
    }
}

Cách gọi và truyền các khóa ngoại cho nó cũng tương tự như với model Posts.

public function posts()
{
    return $this->belongsto('App\Posts', 'foreign_key');
}
public function posts()
{
    return $this->belongsto('App\Posts', 'forigen_key', 'local_key');
}
App\FearturedImages::find(1)->posts;

3. One to Many.

Mối quan hệ này one to many cũng tương tự như One to One nhưng nó chỉ khác nhau về câu lệnh thôi à.

Ví dụ : Cũng với bảng Posts nhưtrên nhưng lần này tôi sẽ tạo thêm một bảng Author , Nhưng ở đây nó sẽ là mối quan hệ một nhiều vì một Author thì có thể có nhiều bài posts và một bài post chỉ có một Author thôi.

-Mình sẽ tạo thêm model Author và phương thức hasMany() để tạo mối quan hệ cho nó.

{
    protected $table = 'Author';
    
    public $timestamp = false;
    
    public function posts()
    {
    	return $this->hasMany('App\Posts');
    }
}

Và Larvel cũng cho chúng ta truyền khóa ngoại, cột liên kết như mối Quan hệ One to One.

public function posts()
{
    return $this->hasMany('App\Posts', 'author_id');
}
public function posts()
{
    return $this->hasMany('App\Posts', 'author_id', 'local_key');
}

Để gọi phương thức cũng không khác gì.

App\author::find(1)->posts;

Định nghĩa các mối quan hệ đảo ngược.

+Về phần này thì hoàn toàn giống phần One to One  nên mình không viết lại nữa.

4. Many to Many.

Mối quan hệ này many to many có hơi phức tạp hơn hai mối quan hệ kia một chút, nhưng không có gì là khó cả.

VD: Vẫn Là bảng posts như trên nhưng ta sẽ tạo thêm 2 bảng là posts_category và category . Mối quan hệ được diễn tả như sau: Một bài posts thì sẽ thuộc một hoặc nhiều category và ngược lại một category cũng có một hoặc nhiều bài posts Và chúng được kết nối với nhau qua bảng posts_category.

-Chúng ta sẽ thể hiện quan hệ giữa 2 bảng này bằng phương thức belongstoMany() như sau:

{
    protected $table = 'Posts';
    
    public $timestamp = false;
    
    public function category()
    {
    	return $this->belongstoMany('App\category');
    }
}

Cách gọi phương thức cũng tương tự như 2 quan hệ trên.

App\Posts::find()->category;

Chú ý: Ở đây bảng trung gian của các bạn không phải là bảng posts_category (quy ước mặc định của Laravel) mà là một bảng khác thì các bạn phải tùy biến như sau:

public function category()
{
    return $this->belongstoMany('App\category', 'table_medium');
}
// table_medium la ten bang trung gian cua cac ban

Nếu hai column liên kết của bạn khác với quy ước của Laravel thì bạn có thể tùy biến như sau:

public function category()
{
    return $this->belongstoMany('App\category', 'table_medium', 'posts_id', 'category_id');
}

Định nghĩa các mối quan hệ đảo ngược.

Về phần này của quan hệ Many to Many thì nó lại giống hệt với phần chính của nó.

VD: chúng ta sẽ gọi phương thức posts trong category như sau.

{
    protected $table = 'category';
    
    public $timestamp = false;
    
    public function posts ()
    {
    	return $this->belongstoMany('App\Posts');
    }
}

Truy cập vào Table trung gian qua quan hệ Many to Many.

Như ở trên mình có nói là để sử dụng mối quan hệ Many to Many thì chúng ta cần phải giao tiếp qua một bảng trung gian. Và để truy cập vào bảng trung gian đó thì trong Laravel có cung cấp cho chúng ta một phương thức pivot attribute. VD: Tôi muốn xem mối quan hệ được xây dựng trên bảng trung gian posts_category vào khi nào thì sẽ phải truy vấn như sau:

$post = App\Posts::find(1);

foreach ($post->category as $rows) {
    echo $rows->pivot->created_at;
}

4. Has Many Through.

Ở mối quan hệ này chúng ta có thể cập vào các mối quan hệ xa thông qua một mối quan hệ trung gian.

Ví dụ, một Country model có thể có nhiều Post model thông qua một User model trung gian. Trong ví dụ này, bạn có thể dễ dàng lấy tất cả các blog post cho 1 country.

Hãy nhìn vào các bảng cần thiết để xác định mối quan hệ này:

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string

Mặc dù post không chứa cột country_id, mối quan hệ hasManyThrough cung cấp quyền truy cập vào post của country thông qua $country->posts. Để thực hiện các truy vấn này, Eloquent kiểm tra các country_id trên bảng user trung gian. Sau khi tìm ra id của user phù hợp, chúng được sử dụng để truy vấn bảng posts. Bây giờ chúng ta đã xem xét các cấu trúc bảng cho các mối quan hệ, hãy định nghĩa nó trên Country model.

Default
{
    /**
     * Get all of the posts for the country.
     */
    public function posts()
    {
        return $this->hasManyThrough('App\Post', 'App\User');
    }
}

Đối số đầu tiên truyền cho phương thức hasManyThrough là tên của model cuối cùng chúng ta muốn truy cập, trong khi đối số thứ 2 là tên của model trung gian. Nếu bạn muốn tùy chỉnh các foreign key của relationship, bạn có thể truyền vào các đối số thứ 3 và thứ 4 của phương thức hasManyThrough. Đối số thứ 3 là foreign key của model trung gian, đối số thứ 4 là foreign key của model cuối cùng và đối số thứ 5 là local key.

class Country extends Model
{
    public function posts()
    {
        return $this->hasManyThrough(
            'App\Post', 'App\User',
            'country_id', 'user_id', 'id'
        );
    }
}

5. Các mối quan hệ khác.

Các mối quan hệ còn lại rất ít khi sử dụng lên chúng mình sẽ không nói đến ở bài này, các bạn nào quan tâm có thể xem tại đây.

6.  Lời kết.

Có thể thấy rằng các ràng buộc, các mối quan hệ trong Laravel khá là đầy đủ và chi tiết đúng không? Để làm việc với database cần có các mối quan hệ này nên các bạn cần đọc bài cho kỹ nhé. Chúc các bạn thành công!

Bình luận