HomeOur Team
Các kiểu quan hệ giữa các bảng trong Laravel phần 1
Articles
Các kiểu quan hệ giữa các bảng trong Laravel phần 1
chung.nguyen1
chung.nguyen1
March 23, 2021
4 min

Chào các bạn, chắc hẳn trong chúng ta, ai đã từng học lập trình đều biết về 1 số quan hệ giữa các bảng trong database. Vậy thì những kiểu quan hệ này được sử dụng trong Laravel như thế nào,chúng ta sẽ cùng tìm hiểu qua bài viết này.

Cài đặt môi trường Laravel

Để có cái nhìn trực quan thì mình cần cài đặt dự án Laravel trên môi trường local. Link tham khảo: https://laravel.com/docs/8.x/installation

1) Kiểu quan hệ Một - Một (One To One)

Đây là kiểu quan hệ cơ bản trong database. Ví dụ: 1 người dùng chỉ có 1 số điện thoại duy nhất. Để định nghĩa kiểu quan hệ này, chúng ta khai báo 1 hàm phone trong Model User

// app/Models/User.php
<?php

namespace App\Models;

use App\Models\Phone;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function phone() {
        return $this->hasOne(Phone::class);
    }
}

Sau khi khai báo xong chúng ta có thể lấy ra số điện thoại của 1 người dùng nào đó bằng cách

User::find(1)->phone;

Để có thể nhìn trực quan dữ liệu, chúng ta có thể tạo 1 UserController có phương thức getPhoneOfUser để lấy ra số điện thoại của 1 người dùng bất kỳ

// app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function getPhoneOfUser($id, Request $request) {
        $phone = User::find($id)->phone;
        return $phone;
    }
}

Tiếp theo, ta định nghĩa 1 route để có thể truy cập thông qua trình duyệt

// routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/users/{id}/phone', [UserController::class, 'getPhoneOfUser']);

Tiếp theo ta truy cập vào đường dẫn {domain}/users/1/phone để nhìn thấy thông tin số điện thoại của người dùng đó

get phone of user

Xem xét phương thức phone bên trong file app/Models/User.php

// app/Models/User.php
<?php

namespace App\Models;

use App\Models\Phone;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    public function phone() {
        return $this->hasOne(Phone::class, 'user_id', 'id');
    }
}

Eloquent sẽ tự động lấy foreign_key thông qua tên Model cha, ở đây Model cha là User Model. Trong trường hợp này Phone Modelforeign_keyuser_id. Nếu trong database bảng phones của chúng ta có khóa ngoại liên kết đến bảng users không phải là user_id mà là một trường khác ví dụ user_fk_id thì chúng ta sẽ ghi đè khóa ngoại đó vào đối số thứ 2 của hàm phone

// app/Models/User.php
<?php

namespace App\Models;

use App\Models\Phone;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    public function phone() {
        return $this->hasOne(Phone::class, 'user_fk_id');
    }
}

Ngoài ra trường hợp bảng users có khóa chính không phải là id mà là một trường khác, ví dụ pk_id thì chúng ta sẽ ghi đè khóa chính đó vào đối số thứ 3 của hàm phone

// app/Models/User.php
<?php

namespace App\Models;

use App\Models\Phone;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    public function phone() {
        return $this->hasOne(Phone::class, 'user_fk_id', `pk_id`);
    }
}

1.2) Xác định nghịch đảo của mối quan hệ

Ở phần trên chúng ta đang truy xuất dữ liệu Model Phone thông qua Model User. Còn phần này chúng ta sẽ truy xuất dữ liệu Model User thông qua Model Phone

<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Phone extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'user_id'
    ];

    public function user() {
        return $this->belongsTo(User::class);
    }
}

Để có thể nhìn trực quan dữ liệu, chúng ta có thể tạo 1 PhoneController có phương thức getUserByPhone để lấy ra thông tin của người dùng đó thông qua số điện thoại

<?php

namespace App\Http\Controllers;

use App\Models\Phone;
use Illuminate\Http\Request;

class PhoneController extends Controller
{
    public function getUserByPhone($id, Request $request) {
        $user = Phone::find($id)->user;
        return $user;
    }
}

Tiếp theo, ta định nghĩa 1 route để có thể truy cập thông qua trình duyệt

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
use App\Http\Controllers\PhoneController;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/users/{id}/phone', [UserController::class, 'getPhoneOfUser']);
Route::get('/phones/{id}/user', [PhoneController::class, 'getUserByPhone']);

Tiếp theo ta truy cập vào đường dẫn {domain}/phones/1/user để nhìn thấy thông tin người dùng

get user by phone

Xem xét phương thức user bên trong file app/Models/Phone.php

<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Phone extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'user_id'
    ];

    public function user() {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }
}

Trường hợp khóa ngoại của Model Phone không phải là user_id mà là user_fk_id thì chúng ta có thể ghi đè khóa ngoại đó vào đối số thứ 2 của hàm user. Tiếp đó nếu Model cha (User Model) không sử dụng id là khóa chính mà là pk_id thì chúng ta có thể ghi đè khóa chính đó vào đối số thứ 3 của hàm user.

<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Phone extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'user_id'
    ];

    public function user() {
        return $this->belongsTo(User::class, 'user_fk_id', 'pk_id');
    }
}

2) Kiểu quan hệ Một - Nhiều (One To Many)

Đây là kiểu quan hệ 1 Parent Model với nhiều Child Model. Ví dụ 1 người dùng có nhiều bài viết, trước tiên chúng ta sẽ định nghĩa kiểu quan hệ này ở Parent Model (User Model)

<?php

namespace App\Models;

use App\Models\Post;

class User extends Authenticatable
{
    public function posts() {
        return $this->hasMany(Post::class);
    }
}

Để có thể nhìn trực quan dữ liệu, chúng ta có thể tạo 1 UserController có phương thức getPostsOfUser để lấy ra các bài viết của 1 người dùng bất kỳ

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function getPostsOfUser($id, Request $request) {
        $posts = User::find($id)->posts;
        return $posts;
    }
}

Tiếp theo, ta định nghĩa 1 route để có thể truy cập thông qua trình duyệt

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/users/{id}/posts', [UserController::class, 'getPostsOfUser']);

Tiếp theo ta truy cập vào đường dẫn {domain}/users/1/posts để nhìn thấy thông tin các bài viết của người dùng đó

get posts of user

Tương tự như trong quan hệ một - một chúng ta có thể chỉnh sửa foreign_keyprimary_key cho phù hợp database của dự án

<?php

namespace App\Models;

use App\Models\Post;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    public function posts() {
        return $this->hasMany(Post::class, 'foreign_key', 'primary_key');
    }
}

2.2) Xác định nghịch đảo của mối quan hệ

Ở phần trên chúng ta đang truy xuất dữ liệu Model Post thông qua Model User. Còn phần này chúng ta sẽ truy xuất dữ liệu Model Userthông qua Model Post

<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function user() {
        return $this->belongsTo(User::class);
    }
}

Để có thể nhìn trực quan dữ liệu, chúng ta có thể tạo 1 PostController có phương thức getUserByPost để lấy ra thông tin tác giả của bài viết

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function getUserByPost($id, Request $request) {
        $user = Post::find($id)->user;
        return $user;
    }
}

Tiếp theo, ta định nghĩa 1 route để có thể truy cập thông qua trình duyệt

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/posts/{id}/user', [PostController::class, 'getUserByPost']);

Tiếp theo ta truy cập vào đường dẫn {domain}/posts/1/user để nhìn thấy thông tin người dùng

get user by post

Tương tự như trong quan hệ một - một chúng ta có thể chỉnh sửa foreign_keyprimary_key cho phù hợp database của dự án

<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function user() {
        return $this->belongsTo(User::class, 'foreign_key', 'primary_key');
    }
}

3) Kiểu quan hệ Nhiều - Nhiều (Many To Many)

Kiểu quan hệ Nhiều - Nhiều dùng để biểu thị 2 bảng có quan hệ Nhiều - Nhiều với nhau. Ví dụ 1 Category có nhiều Product và 1 Product có nhiều Category, ở trường hợp này chúng ta sẽ cần thêm 1 bảng phụ là category_product và liên kết với 2 bảng categories và products thông qua kiểu dữ liệu Một - Nhiều

Để lấy ra được tất cả product của 1 category thì chúng ta cần định nghĩa phương thức product trong Model Category

<?php

namespace App\Models;

use App\Models\Product;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    public function products() {
        return $this->belongsToMany(Product::class);
    }
}

Sau khi khai báo xong chúng ta có thể lấy ra tất cả product của 1 category nào đó bằng cách

Category::find(1)->products;

Để có thể nhìn trực quan dữ liệu, chúng ta có thể tạo 1 CategoryController có phương thức getProductByCategory để lấy ra tất cả product của 1 categorybất kỳ

<?php

namespace App\Http\Controllers;

use App\Models\Category;
use Illuminate\Http\Request;

class CategoryController extends Controller
{
    public function getProductsByCategory($id, Request $request) {
        $products = Category::find($id)->products;
        return $products;
    }
}

Tiếp theo, ta định nghĩa 1 route để có thể truy cập thông qua trình duyệt

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CategoryController;

Route::get('/categories/{id}/products', [CategoryController::class, 'getProductsByCategory']);

Tiếp theo ta truy cập vào đường dẫn {domain}/categories/1/products để nhìn thấy tất cả product của category đó

Xem xét phương thức products bên trong file app/Models/.php

<?php

namespace App\Models;

use App\Models\Product;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    public function products() {
        return $this->belongsToMany(Product::class, 'category_product', 'category_id', 'product_id');
    }
}

Laravel sẽ tự động kết hợp tên của 2 bảng chính làm tên của bảng trung gian. Ví dụ ta có 2 bảng chính là categories và products thì tên của bảng phụ sẽ là category_product. Trong trường hợp bảng phụ của các bạn không phải là category_product thì chúng ta có thể chỉnh sửa tại đối số thứ 2 của method belongsToMany. Đối số thứ 3 là tên khoá ngoại của bảng định nghĩa quan hệ, đối số thứ 4 là tên khoá ngoại của bảng được join tới

<?php

namespace App\Models;

use App\Models\Product;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    public function products() {
        return $this->belongsToMany(Product::class, 'category_product', 'category_id', 'product_id');
    }
}

3.2) Xác định nghịch đảo của mối quan hệ

Ở phần 3 chúng ta đang truy xuất dữ liệu Model thông qua Model . Còn phần này chúng ta sẽ truy xuất dữ liệu Model thông qua Model Product

Để có thể truy xuất dữ liệu của category thông qua product, chúng ta phải khai báo hàm categories trong file app/Models/Product.php

<?php

namespace App\Models;

use App\Models\Category;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function categories() {
        return $this->belongsToMany(Category::class);
    }
}

Để có thể nhìn trực quan dữ liệu, chúng ta có thể tạo 1 ProductController có phương thức getCategoriesByProduct để lấy ra tất cả category của product đó

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function getCategoriesByProduct($id, Request $request) {
        $categories = Product::find($id)->categories;
        return $categories;
    }
}

Tiếp theo, ta định nghĩa 1 route để có thể truy cập thông qua trình duyệt

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

Route::get('/products/{id}/categories', [ProductController::class, 'getCategoriesByProduct']);

Truy cập vào đường dẫn {domain}/products/1/categories để nhìn thấy thông tin category thuộc product


Tags

202103laravel
chung.nguyen1

chung.nguyen1

Developer

Related Posts

Why Protocol-Oriented Programming?
Why Protocol-Oriented Programming?
March 31, 2021
2 min
© 2021, All Rights Reserved.

Quick Links

HomeOur Team

Social Media