Quan hệ đa hình trong Laravel: Polymorphic Relationships
Bài đăng này đã không được cập nhật trong 5 năm
Mối quan hệ đa hình trong Laravel cho phép 1 Model có thể belongsTo nhiều Model khác mà chỉ cần dùng 1 associate.
1. Mối quan hệ One To One (Polymorphic):
1.1 Table Structure
Mối quan hệ này cho phép 1 Model có thể belongsTo 1 hoặc nhiều Model khác. Ví dụ: 1 Model Post và 1 Model User có thể cùng chia sẻ mối quan hệ đa hình với Model Image. Kết quả, chúng ta chỉ cần dùng 1 list ảnh duy nhất có thể dùng chung cho cả các bài Post và tài khoản User. Nếu không chúng ta sẽ phải có 2 list ảnh riêng 1 cho Post và 1 cho User.
posts
id - integer
name - string
users
id - integer
name - string
images
id - integer
url - string
imageable_id - integer
imageable_type - string
Trong bảng images có 2 trường đặc biệt đó là:
- imageable_id - chứa giá trị Id của User hoặc Post
- imageable_type: Chứa tên class của Model User hoặc Post - dùng để xác định xem Model nào sẽ được trả về khi truy cập vào mối quan hệ imageable
1.2 Model Structure
Cách định nghĩa Model trong Laravel để xây dựng mối quan hệ 1:1 đa hình
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
/**
* Get all of the owning imageable models.
*/
public function imageable()
{
return $this->morphTo();
}
}
class Post extends Model
{
/**
* Get the post's image.
*/
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}
class User extends Model
{
/**
* Get the user's image.
*/
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}
1.3 Retrieving The Relationship
Khi đã định nghĩa các models và các tables trong cơ sở dữ liệu, chúng ta có thể sử dụng mối quan hệ 1:1 đa hình. Ví dụ để truy xuất đến các image của các bài post, chúng ta có thể sử dụng thuộc tính động image
$post = App\Post::find(1);
$image = $post->image;
Ngược lại, chúng từ 1 Model Image chúng ta cũng có thể suy ngược lại Model User hoặc Post phụ thuộc vào loại Model nào sở hữu Model Image này
$image = App\Image::find(1);
$imageable = $image->imageable;
2. Mối quan hệ One To Many (Polymorphic)
2.1 Table Structure
Mối quan hệ 1:N đa hình giống với mối quan hệ 1:1 đa hình chỉ khác ở chỗ đây là quan hệ 1:N tương tự như quan hệ giữa các bảng trong cơ sơ dữ liệu. Ví dụ, 1 User có thể comment ở cả bài post và video. Sử dụng mối quan hệ đa hình chúng ta chỉ cần dùng 1 bảng comments duy nhất cho 2 TH này. Giả sử ta xây dụng cấu trúc bảng như sau:
posts
id - integer
title - string
body - text
videos
id - integer
title - string
url - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
2.2 Model Structure
Định nghĩa cấu trúc Model cần có để có thể sử dụng mối quan hệ đa hình 1:N
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get all of the owning commentable models.
*/
public function commentable()
{
return $this->morphTo();
}
}
class Post extends Model
{
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
class Video extends Model
{
/**
* Get all of the video's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
2.3 Retrieving The Relationship
Khi đã định nghĩa xong Model và tạo ra các tables như trên, chúng ta có thể sử dụng mối quan hệ đa hình này. Ví dụ, bâu giờ nếu muốn lấy tất cả các comments của 1 bài Post chúng ta có thể sử dụng thuộc tính động comments
$post = App\Post::find(1);
foreach ($post->comments as $comment) {
//
}
Ngược lại, từ 1 Model đa hình chúng ta có thể truy cập ngược lại Model đang sở hữu quan hệ đa hình này bằng cách truy cập vào tên của method mà đã gọi method morphTo(). Trong TH này đó là method commentable trong model comment
$comment = App\Comment::find(1);
$commentable = $comment->commentable;
quan hệ commentable trong model Comment sẽ trả về 1 instance của Post hoặc Video phụ thuộc vào loại model đang sở hữu comment
3. Mối quan hệ Many To Many (Polymorphic)
3.1 Table Structure
posts
id - integer
name - string
videos
id - integer
name - string
tags
id - integer
name - string
taggables
tag_id - integer
taggable_id - integer
taggable_type - string
3.2 Model Structure
Định nghĩa các mối quan hệ trên model. Cả 2 model Post và Video đều có 1 method tags() và gọi đến method morphToMany
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}
3.3 Defining The Inverse Of The Relationship
Trong model Tag, chúng ta sẽ định nghĩa 1 method cho mỗi 1 Model nó có quan hệ. Ở đây là method pots và method videos
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
/**
* Get all of the posts that are assigned this tag.
*/
public function posts()
{
return $this->morphedByMany('App\Post', 'taggable');
}
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany('App\Video', 'taggable');
}
}
3.3 Retrieving The Relationship
Bây giờ, nếu muốn lấy tất cả các tags của 1 bài Post ta sẽ dùng thuộc tính động tags:
$post = App\Post::find(1);
foreach ($post->tags as $tag) {
//
}
Ngược lại, chúng ta cũng có thể truy xuất đến Model sở hữu mối quan hệ đa hình từ 1 Model đa hình bằng cách truy cập vào tên của phương thức mà call đến method morphedByMany. Trong trường hợp này đó là method posts và videos trong model Tag
$tag = App\Tag::find(1);
foreach ($tag->videos as $video) {
//
}
Bài viết có tham khảo từ các nguồn: https://laravel.com/docs/5.8/eloquent-relationships#polymorphic-relationships
All rights reserved