Laravel Eloquent ORM [Part 2]
Bài đăng này đã không được cập nhật trong 8 năm
Bài viết này sẽ đi sâu về Relationships
, về các thao tác cơ bản trên Eloquent
, các bạn có thể tham khảo tại link: https://viblo.asia/vu.huy.tuan/posts/1ZnbRlr3G2Xo.
Các bảng trong cơ sở dữ liệu của chúng ta luôn có liên kết với nhau, việc khai báo các liên kết sẽ giúp chúng ta giảm thiểu số lượng truy vấn không cần thiết đồng thời giúp chúng ta đảm bảo được tính toàn vẹn của cơ sở dữ liệu.
Laravel cũng như các framework khác, nó hỗ trợ khá nhiều kiểu liên kết
như:
- One To One
- One To Many
- Many To Many
- Has Many Through
- Polymorphic Relations
- Many To Many Polymorphic Relations
1. One To One
one-to-one là một loại liên kết rất cơ bản, ví dụ 1 User có 1 Phone, chúng ta định nghĩa mối liên kết này trong cơ sở dữ liệu như sau:
class User extends Model {
public function phone()
{
return $this->hasOne('App\Phone');
}
}
Tham số đầu tiên trong phương thức hasOne
là tên của model
liên kết. Sau khi chúng ta định nghĩa liên kết như ở trên, chúng ta có thể sử dụng chúng như một thuộc tính động
:
$phone = User::find(1)->phone;
Truy vấn SQL tương ứng với câu lệnh trên sẽ là:
select * from users where id = 1
select * from phones where user_id = 1
Chú ý rằng Eloquent
sử dụng khóa ngoài của liên kết dựa theo tên của model
, ví dụ với liên kết giữa 2 model User
và Phone
, khóa ngoài tương ứng sẽ là user_id
và phone_id
. Nếu bảng của chúng ta có khóa ngoài có tên khác với định nghĩa ở trên, chúng ta cần phải khai báo chính xác khóa ngoài của liên kết giữa 2 bảng như sau:
return $this->hasOne('App\Phone', 'foreign_key');
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
Để định nghĩa liên kết ngược lại liên kết 1 user có 1 phone
, chúng ta sử dụng belongsTo
để định nghĩa liên kết 1 phone thuộc 1 user
:
class Phone extends Model {
public function user()
{
return $this->belongsTo('App\User');
}
}
2. One To Many
Một ví dụ đơn giản cho liên kết "one-to-many" là 1 post có nhiều comment
class Post extends Model {
public function comments()
{
return $this->hasMany('App\Comment');
}
}
Bây giờ chúng ta có thể truy vấn tới các comments
trong 1 post
dựa trên thuộc tính động như sau:
$comments = Post::find(1)->comments;
Chúng ta có thể thêm các điều kiện trong truy vấn tìm comments
ở trên:
$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first();
Cũng tương tự với one-to-one, nếu khóa ngoài và khóa trong không giống như format mặc định của laravel, chúng ta cần phải khai báo nó trong định nghĩa:
return $this->hasMany('App\Comment', 'foreign_key');
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
Để định nghĩa mối quan hệ ngược lại của mối quan hệ one-to-many
, chúng ta sử dụng belongsTo
:
class Comment extends Model {
public function post()
{
return $this->belongsTo('App\Post');
}
}
3. Many To Many
Mối quan hệ many-to-many
là một kiểu quan hệ phức tạp hơn. Một ví dụ về một mối quan hệ như là một người sử dụng (user
) với nhiều vai trò (role
), nơi mà vai trò (role
) cũng được chia sẻ bởi người dùng (user
) khác. Ví dụ, nhiều người sử dụng có thể có vai trò Admin
. Ba bảng cơ sở dữ liệu cần thiết cho mối quan hệ này: User
, Role
và role_user
.
Chúng ta có thể định nghĩa many-to-many
bằng phương thức belongsToMany
:
class User extends Model {
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
Bấy giờ chúng ta có thể lấy roles
từ model User
:
$roles = User::find(1)->roles;
Tương tự với các liên kết đã định nghĩa ở trên, nếu tên bảng liên kết không như format mặc định của laravel, chúng ta có thể truyền nó vào như tham số thứ 3:
return $this->belongsToMany('App\Role', 'user_roles');
return $this->belongsToMany('App\Role', 'user_roles', 'user_id', 'foo_id');
Chúng ta cũng có thể định nghĩa liên kết ngược lại trên model Role
:
class Role extends Model {
public function users()
{
return $this->belongsToMany('App\User');
}
}
4. Has Many Through
Mối quan hệ "has-many-through" cung cấp một shortcut
thuận tiện cho việc truy 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
có thể có nhiều Post
thông qua model User
.
countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string
Mặc dù bảng posts
không chứa cột country_id
, nhưng liên kết hasManyThrough
cho phép chúng ta lấy dữ liệu về posts
của một country
thông qua `$country->posts'.
class Country extends Model {
public function posts()
{
return $this->hasManyThrough('App\Post', 'App\User');
}
}
Chúng ta có thể khai báo đầy đủ hơn như sau:
class Country extends Model {
public function posts()
{
return $this->hasManyThrough('App\Post', 'App\User', 'country_id', 'user_id');
}
}
5. Polymorphic Relations
Quan hệ đa hình (Polymorphic relations) cho phép một model
thuộc về nhiều hơn một model
khác dựa vào một liên kết duy nhất. Ví dụ, bạn có thể có một model
Photo thuộc về một trong hai model
Staff hoặc model
Order. Chúng ta sẽ xác định mối quan hệ này như sau:
class Photo extends Model {
public function imageable()
{
return $this->morphTo();
}
}
class Staff extends Model {
public function photos()
{
return $this->morphMany('App\Photo', 'imageable');
}
}
class Order extends Model {
public function photos()
{
return $this->morphMany('App\Photo', 'imageable');
}
}
Bây giờ chúng ta có thể lấy ra các photos
của một staff
hoặc của một order
:
$staff = Staff::find(1);
foreach ($staff->photos as $photo)
{
//
}
Truy xuất ngược của mối quan hệ đa hình.
Chúng ta có thể truy xuất ngược lại staff
hoặc order
từ photo
:
$photo = Photo::find(1);
$imageable = $photo->imageable;
Cấu trúc bảng dữ liệu của mối quan hệ đa hình
staff
id - integer
name - string
orders
id - integer
price - integer
photos
id - integer
path - string
imageable_id - integer
imageable_type - string
6. Many To Many Polymorphic Relations
Mở rộng hơn của mối quan hệ đa hình đã được nói ở trên, chúng ta có mối quan hệ many-to-many
Ví dụ: một Post
và Video
model
có thể chia sẻ một mối quan hệ đa hình tới một Tag
model
. Cấu trúc bảng dữ liệu sẽ được khai báo như sau:
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
Tiếp theo, chúng ta khai báo các quan hệ trong các model. Cả model
Post
và Video
đều có môt liên kết morphToMany
thông qua model tags
:
class Post extends Model {
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}
Model Tag
cần phải định nghĩa 1 phương thức cho mỗi liên kết của nó:
class Tag extends Model {
public function posts()
{
return $this->morphedByMany('App\Post', 'taggable');
}
public function videos()
{
return $this->morphedByMany('App\Video', 'taggable');
}
}
All rights reserved