Nếu các bạn đã học về cơ sở dữ liệu
thì hẳn mọi người đều biết giữa các bảng có liên kết với nhau. Ở trong Laravel
chũng cung cấp cho chúng các Relationships
giúp việc truy vấn trở nên dễ dàng hơn.
1. One to One
- Đây là kiểu quan hệ đơn giản nhất, nó thể hiện cho việc
một người có một thứ và thứ đó chỉ thuộc về người này
. - Như bạn có bảng
users
và bảngphones
thì mộtuser
có 1 cái điện thoại vàphone
đó chỉ thuộc vềuser
đó. - Trong
laravel
để tạo quan hệ cho 2 model có quan hệOne to One
ta sử dụng phương thứchasOne
.
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model
{ /** * Get the phone associated with the user. */ public function phone() { return $this->hasOne(Phone::class); }
}
- Sau khi tạo
quan hệ
xong ta có thể truy vấn tớiphone
mà cóuser
có tên làNguyen Van A
như sau:
User::where('name', 'Nguyen Van A')->phone;
- Ngoài ra bạn cũng có thể định nghĩa khóa ngoại cho quan hệ này bằng cách thêm tham số thứ 2:
return $this->hasOne(Phone::class, 'foreign_key');
- Ngược lại đối với model
Phone
ta sử dụng phương thứcbelongsTo
để định nghĩaInverse
với modelUser
:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Phone extends Model
{ /** * Get the user that owns the phone. */ public function user() { return $this->belongsTo(User::class); }
}
- Giống với model
User
bạn cũng có thể định nghĩa khóa ngoại bằng cách thêm tham số thứ 2 và tất nhiên là bạn cũng có thể truy vấn tớiuser
tương ứng.
2. One to Many
- Quan hệ này biểu thị cho mối quan hệ
cha-con
. Ví dụ như mộtuser
có nhiềuposts
nhưng các bàipost
chỉ thuộc mộtuser
. - Mối quan hệ này được biểu diễn như sau:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Authenticatable
{ public function posts() { return $this->hasMany(Post::class); }
}
- Giống với quan hệ
One to One
bạn cũng có thể thêm tham số thứ 2 để định nghĩa khóa ngoại. - Và bạn cũng phải định nghĩa
Inverse
cho modelPost
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model
{ public function user() { return $this->belongsTo(User::class); }
}
3. Many to Many
- Quan hệ này phức tạp hơn 2 quan hệ
One to One
vàOne to Many
ví như mộtProduct
sẽ thuộc nhiềuOrders
và mộtOrder
cũng có nhiềuProducts
. - Để biểu diễn được quan hệ này thì chúng ta phải có một bảng thứ 3 là
product_order
và chưa 2 trường làproduct_id
vàorder_id
. - Sau khi có bảng trung gian thì chúng ta định nghĩa quan hệ này thông qua phương thức
belongsToMany
ở cả 2 model.
namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model
{ public function orders() { return $this->belongsToMany(Order::class); }
}
namespace App; use Illuminate\Database\Eloquent\Model; class Order extends Model
{ public function product() { return $this->belongsToMany(Product::class); }
}
-
Và để định nghĩa khóa ngoại thì bạn cần thêm tham số thứ 2, thứ 3 và thứ 4.
-
Trong đó:
Tham số thứ 2
tương ứng với bảng trung gian.Tham số thứ 3
vàtham số thứ 4
tương ứng với khóa ngoại của 2 bảng cần tạo quan hệ.
namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model
{ public function orders() { return $this->belongsToMany(Order::class, 'product_order', 'product_id', 'order_id'); }
}
- Tất nhiên trong một số trường hợp thì bảng trung gian của bạn cũng có thể có thêm các trường khác nữa thì trong
Laravel
cung cấp cho bạn một phương thức làpivot
để lấy ra các trường đó. ví dụ:
$product = Product::find(1); foreach($product->orders as $order)
{ echo $order->pivot->created_at;
}
- Để có thể lấy được thì bạn cần phải định nghĩa tròng model như sau:
namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model
{ public function orders() { return $this->belongsToMany(Order::class)->withPivot('total_price'); }
}
4. Các quan hệ nâng cao
- Ngoài 3 quan hệ cơ bản ở trên thì
laracel
có cung cấp thêm cho bạn các quan hệ nâng cao khác.
4.1 Has One Through
- Đây là một mối quan hệ liên kết các bảng với nhau thông qua một bảng trung gian Ví dụ có 3 bảng:
users id - integer supplier_id - integer suppliers id - integer history id - integer user_id - integer
- Mặc dù bảng
history
không chứasupplier_id
nhưng chúng ta vẫn có thể truy cập đến lịch sử của user đó bới mối quan hệhasOneThrough
như sau:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Supplier extends Model
{ public function userHistory() { return $this->hasOneThrough(History::class, User::class); }
}
- Với tham số thứ nhất được truyền vào là tên của model mà chúng ta muốn truy cập, tham số thứ 2 là model trung gian.
- Còn ở hai bảng
user
vàhistory
chúng ta định nghĩa như bình thường.
4.2 Has Many Through
- Mối quan hệ
has many through
này cung cấp cho chúng ta cách truy cập bảng liên kết dễ dàng hơn thông qua bảng trung gian.
teams id - integer name - string users id - integer team_id - integer name - string posts id - integer user_id - integer title - string
- Giống như
Has One Through
bạn cũng có thể lấy ra tất cả bàiposts
của mộtteam
bằng cách$team->posts
.
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Team extends Model
{ public function posts() { return $this->hasManyThrough(Post::class, User::class); }
}
4.3 One to One Polymorphic
- Mối quan hệ này tương tự quan hệ
One to One
, nhưng mục đích của mối quan hệ này là 1 model có thể belongsTo 1 hay nhiều model khác. - Ví dụ một bài
post
có 1image
và 1product
cũng có 1image
thì bạn cần tạo thêm 2 bảng làpost_image
vàproduct_image
để lưu ảnh cho chúng thì vớiPolymorphic
thì bạn chỉ cần 1 bảngimages
là đủ:
posts id - integer name - string products id - integer name - string images id - integer url - string imageable_id - integer imageable_type - string
-
Trong đó:
imageable_id
làid
của bảngproducts
hoặcposts
.imageable_type
chứa tên của modelApp\Models\Product
hoặcApp\Models\Post
.
-
Model Image:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Image extends Model
{ public function imageable() { return $this->morphTo(); }
}
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model
{ public function image() { return $this->morphOne(Image::class, 'imageable'); }
}
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model
{ public function image() { return $this->morphOne(Image::class, 'imageable'); }
}
- Để lấy ra
image
$post = Post::find(1); $image = $post->image;
- Bạn cũng có thể truy vấn ngược để lấy ra
post
hoặcproduct
:
$image = Image::find(1); $imageable = $image->imageable;
4.4 One to Many Polymorphic
- Quan hệ này khá giống với quan hệ
One to One Polymorphic
bạn chỉ cần thaymorphOne
thànhmorphMany
là được. Vì giống với cách định nghĩa ở trên nên mình sẽ không nhắc lại nữa.
4.5 Many to Many Polymorphic
- Vì là quan hệ
Many to Many
nên bạn cũng cần tạp ra một bảng trung gian. - Ví dụ một
post
hay làvideo
có thể có nhiềutags
. Sử dụng mối quan hệmany to many polymorphic
cho phép bạn truy vấn lấy ra cáctags
thuộc về mộtpost
hayvideo
.
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
- Cấu trúc model
//post.php <?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model
{ public function tags() { return $this->morphToMany(Tag::class, 'taggable'); }
}
class Tag extends Model
{ public function posts() { return $this->morphedByMany(Post::class, 'taggable'); } public function videos() { return $this->morphedByMany(Video::class, 'taggable'); }
}
- Muốn lấy ra các tag thuộc về một post ta cũng làm tương tự nhưng mối quan hệ khác.
$post = Post::find(1); foreach ($post->tags as $tag) { //
}
- hoặc là ngược lại:
$tag = Tag::find(1); foreach ($tag->videos as $video) { //
}
5. Kết luận
- Bài viết này mình giói thiệu cho các bạn về
Relationships
trong laravel. Mong răng nó sẽ giúp ích được cho các bạn. - Link tham khảo: https://laravel.com/docs/8.x/eloquent-relationships