Polymorphic Relations là gì
Ví dụ bạn đang thiết kế web về bán hàng và dữ liệu có mỗi quan hệ phức tạp, khi đó ta cần biết về Quan hệ đa hình cho phép 1 model thuộc về nhiều hơn 1 model khác. Ví dụ, hãy tưởng tượng users của ứng dụng của bạn có thể "comments" cả post và video. Sử dụng các mối quan hệ đa hình, bạn có thể sử dụng 1 bảng comments
duy nhất cho cả 2. Trước tiên, hãy kiểm tra các cấu trúc bảng cần thiết để xây dựng mối quan hệ này.
Cấu trúc bảng
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
Hai cột quan trọng cần lưu ý là cột commentable_id
và commentable_type
trong bảng comments
. Cột commentable_id
sẽ chứa giá trị id
của post hoặc video. Trong khi cột commentable_type
sẽ chứa tên lớp của model sở hữu. Cột commentable_type
là cách ORM xác định "type" của model sở hữu sẽ trả về khi truy cập vào các mối quan hệ commentable
.
Model Structure
Tiếp theo, hãy kiểm tra các định nghĩa model cần thiết để xây dựng mối quan hệ này:
<?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');
}
}
Retrieving Polymorphic Relations
Mỗi khi bảng cơ sở dữ liệu và model của bạn được xác định, bạn có thể truy cập vào các mối quan hệ thông qua model của bạn. Ví dụ, để truy cập vào tất cả các comments cho một post, chúng ta có thể đơn giản sử dụng những property động:
$post = App\Post::find(1);
foreach ($post->comments as $comment) {
//
}
Bạn cũng có thể truy xuất các chủ sở hữu của một mối quan hệ đa hình từ model đa hình bằng cách truy cập vào tên của method thực hiện gọi đến method morphTo
. Trong trường hợp của chúng ta, đó là method commentable
trên Comment
model. Vì vậy, chúng ta sẽ tiếp cận phương pháp đó như là một property động:
$comment = App\Comment::find(1);
$commentable = $comment->commentable;
Các mối quan hệ commentable
trên mô Comment
model sẽ trả lại hoặc là một Post
hay dụ Video
instance, tùy thuộc vào loại mô hình sở hữu các comment.
Custom Polymorphic Types
Theo mặc định, Laravel sẽ sử dụng tên lớp đầy đủ để lưu trữ các loại model có liên quan. Ví dụ, với các ví dụ ở trên, nơi một comment
có thể thuộc về một Post
hoặc một Video
, commentable_type
mặc định sẽ là một trong hai App\Post
hoặc App\Video
tương ứng. Tuy nhiên, bạn có thể muốn tách cơ sở dữ liệu của bạn từ cấu trúc bên trong của ứng dụng của bạn. Trong trường hợp đó, bạn có thể xác định một mối quan hệ "morph map" để hướng dẫn Eloquent để sử dụng một tên tùy chỉnh cho mỗi model thay vì tên lớp:
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([
'posts' => App\Post::class,
'videos' => App\Video::class,
]);
Bạn có thể đăng ký morphMap
trong các boot
function của AppServiceProvider
của bạn hoặc tạo ra một service provider riêng biệt nếu bạn muốn.
Many To Many Polymorphic Relations
Ngoài mối quan hệ đa hình truyền thống, bạn cũng có thể định nghĩa "many-to-many" mối quan hệ đa hình. Ví dụ, một blog Post
và Video
model có thể chia sẻ một mối quan hệ đa hình cho một Tag
model. Sử dụng một mối quan hệ đa hình many-to-many cho phép bạn có một danh sách duy nhất của unique tags được chia sẻ trên các blog posts và videos. Trước tiên, hãy kiểm tra cấu trúc bảng:
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
Model Structure
Tiếp theo, chúng ta đã sẵn sàng để xác định các mối quan hệ trên model. Các Post
model và Video
model cả hai sẽ có một tags
method gọi phương thức morphToMany
trên lớp base Eloquent:
<?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');
}
}
Defining The Inverse Of The Relationship
Tiếp theo, trên Tag
model, bạn nên xác định một method cho mỗi model có liên quan của nó. Vì vậy, trong ví dụ này, chúng tôi sẽ xác định một posts
method và video
method:
<?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');
}
}
Retrieving The Relationship
Khi bảng cơ sở dữ liệu và model của bạn được xác định, bạn có thể truy cập vào các mối quan hệ thông qua model của bạn. Ví dụ, để truy cập vào tất cả các tags cho một post, bạn chỉ có thể sử dụng các tags
property động:
$post = App\Post::find(1);
foreach ($post->tags as $tag) {
//
}
Bạn cũng có thể truy xuất các chủ sở hữu của một mối quan hệ đa hình từ model đa hình bằng cách truy cập vào tên của phương thức đó thực hiện các cuộc gọi đến morphedByMany
. Trong trường hợp của chúng ta, đó là những posts
hoặc videos
method trên Tag
model. Vì vậy, bạn sẽ truy cập vào các method đó là property động:
$tag = App\Tag::find(1);
foreach ($tag->videos as $video) {
//
}
Vậy là mình đã giới thiệu cho các bạn về các mối quan hệ trong Eloquent. Ở phần tiếp theo, mình sẽ tiếp tục giới thiệu cho các bạn về Querying Relations
, Eager Loading
và Inserting & Updating Related Models
.