Relationships trong Laravel
Bài đăng này đã không được cập nhật trong 2 năm
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
usersvà bảngphonesthì mộtusercó 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 Oneta 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ớiphonemà cóusercó tên làNguyen Van Anhư 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
Phoneta sử dụng phương thứcbelongsTođể định nghĩaInversevớ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
Userbạ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ớiusertương ứng.
2. One to Many
- Quan hệ này biểu thị cho mối quan hệ
cha-con. Ví dụ như mộtusercó nhiềupostsnhưng các bàipostchỉ 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 Onebạ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
Inversecho 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 OnevàOne to Manyví như mộtProductsẽ thuộc nhiềuOrdersvà mộtOrdercũ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_ordervà chưa 2 trường làproduct_idvà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ứ 2tương ứng với bảng trung gian.Tham số thứ 3vàtham số thứ 4tươ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
Laravelcung 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ì
laracelcó 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
historykhông chứasupplier_idnhưng chúng ta vẫn có thể truy cập đến lịch sử của user đó bới mối quan hệhasOneThroughnhư 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
uservàhistorychúng ta định nghĩa như bình thường.
4.2 Has Many Through
- Mối quan hệ
has many throughnà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 Throughbạn cũng có thể lấy ra tất cả bàipostscủa mộtteambằ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
postcó 1imagevà 1productcũng có 1imagethì bạn cần tạo thêm 2 bảng làpost_imagevàproduct_imageđể lưu ảnh cho chúng thì vớiPolymorphicthì bạn chỉ cần 1 bảngimageslà đủ:
posts
id - integer
name - string
products
id - integer
name - string
images
id - integer
url - string
imageable_id - integer
imageable_type - string
-
Trong đó:
imageable_idlàidcủa bảngproductshoặcposts.imageable_typechứa tên của modelApp\Models\Producthoặ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
posthoặ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 Polymorphicbạn chỉ cần thaymorphOnethànhmorphManylà đượ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 Manynên bạn cũng cần tạp ra một bảng trung gian. - Ví dụ một
posthay làvideocó thể có nhiềutags. Sử dụng mối quan hệmany to many polymorphiccho phép bạn truy vấn lấy ra cáctagsthuộc về mộtposthayvideo.
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ề
Relationshipstrong 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
All rights reserved