Chú ý phần này quan trọng là chúng ta xóa và cập nhập mối quan hệ :)
Khi loại bỏ belongsTo relationship, bạn có thể sử dụng dissociate method. Method này sẽ thiết lập các foreign key thành null. đọc thêm về xóa ở dưới
Ví dụ 1
Lấy code giống của ví dụ 1 phần One To One chỉ thay đổi chỗ phương thức
app\Models\User.php
<?phpnamespaceApp\Models;useIlluminate\Database\Eloquent\Factories\HasFactory;useIlluminate\Foundation\Auth\Useras Authenticatable;useIlluminate\Notifications\Notifiable;useLaravel\Sanctum\HasApiTokens;classUserextendsAuthenticatable {useHasApiTokens,HasFactory,Notifiable;/** * The attributes that are mass assignable. * * @vararray<int, string> */protected $fillable = ['name','email','password', ];/** * The attributes that should be hidden for serialization. * * @vararray<int, string> */protected $hidden = ['password','remember_token', ];/** * The attributes that should be cast. * * @vararray<string, string> */protected $casts = ['email_verified_at'=>'datetime', ];publicfunctionphone() {// return $this->hasOne(Phone::class);return$this->hasMany(Phone::class); }}
Ta nhận thấy nếu dùng phương thức hasMany thay cho hasOne kết quả trả về là một mảng. Nếu không dùng như chúng ta biết nó chỉ lấy 1 giá trị gần nhất sắp xếp theo thứ tự giảm dần (des)im
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = [
'name'
];
/**
* Get the comments for the blog post.
*/
public function comments()
{
return $this->hasMany(Comment::class);
}
}
<?phpnamespaceApp\Models;useIlluminate\Database\Eloquent\Factories\HasFactory;useIlluminate\Database\Eloquent\Model;classCommentextendsModel{useHasFactory;protected $fillable = ['post_id','comment' ];/** * Get the post that owns the comment. */publicfunctionpost() {return$this->belongsTo(Post::class,'id'); }}
<?phpuseIlluminate\Support\Facades\Route;useApp\Http\Controllers\TestController;/*|--------------------------------------------------------------------------| Web Routes|--------------------------------------------------------------------------|| Here is where you can register web routes for your application. These| routes are loaded by the RouteServiceProvider within a group which| contains the "web" middleware group. Now create something great!|*/Route::get('/',function () {returnview('welcome');});Route::get('/test/{id}', [TestController::class,'index']);Route::get('/test2/{id}', [TestController::class,'index2']);Route::get('/save/{id}', [TestController::class,'save']);Route::get('/create/{id}', [TestController::class,'create']);Route::get('/associate/{idcom}/{idpost}', [TestController::class,'associate']);
Laravel 9 One to Many Eloquent Relationship Tutorial
Hi Dev,
Here, I will show you laravel 9 one to many relationship examples. it's a simple example of laravel 9 hasmany relationship examples. step by step explain has many relationship laravel 9. This tutorial will give you a simple example of laravel 9 one to many sync. Alright, let’s dive into the steps.
So in this tutorial, you can understand how to create migration with a foreign key schema for one to many relationships, use sync with a pivot table, create records, get all data, delete, update, and everything related to one to many relationships.
In this example, I will create a "posts" table and a "comments" table. both tables are connected with each other. now we will create one to many relationships with each other by using the laravel Eloquent Model. We will first create database migration, then model, retrieve records, and then how to create records too. So you can also see the database table structure on the below screen.
One to Many Relationship will use "hasMany()" and "belongsTo()" for relation.
Create Migrations:
Now we have to create migration of "posts" and "comments" table. we will also add foreign key with posts table. so let's create like as below:
posts table migration:
<?php use Illuminate\Database\Migrations\Migration;use Illuminate\Database\Schema\Blueprint;use Illuminate\Support\Facades\Schema; return new class extends Migration{ /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string("name"); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); }};
comments table migration:
<?php use Illuminate\Database\Migrations\Migration;use Illuminate\Database\Schema\Blueprint;use Illuminate\Support\Facades\Schema; return new class extends Migration{ /** * Run the migrations. * * @return void */ public function up() { Schema::create('comments', function (Blueprint $table) { $table->id(); $table->foreignId('post_id')->constrained('posts'); $table->string("comment"); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('comments'); }};
Create Models:
Here, we will create Post and Comment table model. we will also use "hasMany()" and "belongsTo()" for relationship of both model.
app/Models/Post.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model; class Post extends Model{ use HasFactory; /** * Get the comments for the blog post. * * Syntax: return $this->hasMany(Comment::class, 'foreign_key', 'local_key'); * * Example: return $this->hasMany(Comment::class, 'post_id', 'id'); * */ public function comments() { return $this->hasMany(Comment::class); }}
app/Models/Comment.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model; class Comment extends Model{ use HasFactory; /** * Get the post that owns the comment. * * Syntax: return $this->belongsTo(Post::class, 'foreign_key', 'owner_key'); * * Example: return $this->belongsTo(Post::class, 'post_id', 'id'); * */ public function post() { return $this->belongsTo(Post::class); }}
Retrieve Records:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request;use App\Models\Post; class PostController extends Controller{ /** * Write code on Method * * @return response() */ public function index(Request $request) { $comments = Post::find(1)->comments; dd($comments); }}
<?php namespace App\Http\Controllers; use Illuminate\Http\Request;use App\Models\Comment; class PostController extends Controller{ /** * Write code on Method * * @return response() */ public function index(Request $request) { $post = Comment::find(1)->post; dd($post); }}
Create Records:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request;use App\Models\Post;use App\Models\Comment; class PostController extends Controller{ /** * Write code on Method * * @return response() */ public function index(Request $request) { $post = Post::find(1); $comment = new Comment; $comment->comment = "Hi ItSolutionStuff.com"; $post = $post->comments()->save($comment); }}
<?php namespace App\Http\Controllers; use Illuminate\Http\Request;use App\Models\Post;use App\Models\Comment; class PostController extends Controller{ /** * Write code on Method * * @return response() */ public function index(Request $request) { $post = Post::find(1); $comment1 = new Comment; $comment1->comment = "Hi ItSolutionStuff.com Comment 1"; $comment2 = new Comment; $comment2->comment = "Hi ItSolutionStuff.com Comment 2"; $post = $post->comments()->saveMany([$comment1, $comment2]); }}
Vì tất cả các mối quan hệ của Eloquent được định nghĩa qua các function, bạn có thể gọi những function để có được một thể hiện của mối quan hệ mà không thực sự thực hiện các truy vấn về quan hệ. Ngoài ra, tất cả các loại của các mối quan hệ Eloquent cũng phục vụ truy vấn, cho phép bạn tiếp tục hạn chế chuỗi vào truy vấn relationship cuối cùng trước khi SQL thi hành trong cơ sở dữ liệu của bạn.
Ví dụ, hãy tưởng tượng một hệ thống blog, trong đó mỗi User model có nhiều Post model liên quan.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get all of the posts for the user.
*/
public function posts()
{
return $this->hasMany('App\Post');
}
}
Bạn có thể truy vấn các posts trong mối quan hệ và thêm các giằng buộc cho relationship như sau:
Bạn có thể sử dụng bất kỳ query builder methods nào trong relationship.
Relationship Methods Vs. Dynamic Properties
Nếu bạn không cần phải thêm vào các giằng buộc cho 1 truy vấn Eloquent relationship, bạn có thể truy cập vào 1 relationship như là 1 property. Ví dụ, tiếp tục sử dụng User và Post model, chúng ta có thể truy cập đến tất cả các posts của user như sau:
$user = App\User::find(1);
foreach ($user->posts as $post) {
//
}
Dynamic properties là "lazy loading", có nghĩa là nó sẽ chỉ tải dữ liệu của relationship khi bạn thực sự truy cập chúng. Bởi vì điều này, các developers thường sử dụng eager loading để truy cập vào các relationship. Eager loading cung cấp một sự giảm đáng kể trong các truy vấn SQL mà cần để thực hiện tải các relationship của model.
Querying Relationship Existence
Khi truy cập vào các record của 1 model, bạn muốn giới hạn kết quả của bạn dựa trên sự tồn tại của các relationship. Ví dụ, hãy tưởng tượng bạn muốn lấy tất cả các bài viết blog mà có ít nhất 1 comment. Để làm như vậy, bạn có thể vượt qua tên của các relationship với has method:
// Retrieve all posts that have at least one comment...
$posts = App\Post::has('comments')->get();
Bạn cũng có thể chỉ định 1 operator và đếm để tùy chỉnh cho truy vấn:
// Retrieve all posts that have three or more comments...
$posts = Post::has('comments', '>=', 3)->get();
Các câu lệnh lồng nhau cũng có thể được xây dựng bằng các dấu ".", Ví dụ, bạn có thể lấy hết các posts mà có ít nhất 1 comment và vote:
// Retrieve all posts that have at least one comment with votes...
$posts = Post::has('comments.votes')->get();
Nếu bạn cần nhiều hơn nữa, bạn có thể sử dụng các method whereHas và orWhereHas đặt "where" trong điều kiện query của bạn. Những method này cho phép bạn thêm các ràng buộc tùy chỉnh cho 1 relationship, chẳng hạn như kiểm tra nội dung của 1 comment:
// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
Querying Relationship Absence
Khi truy cập vào các record của 1 model, bạn muốn giới hạn kết quả dựa trên sự vắng mặt của 1 relationship. Ví dụ, hãy tưởng tượng bạn muốn lấy tất cả các posts mà không có bất kỳ comment nào, Để làm như vậy, bạn có thể sử dụng method doesntHave.
$posts = App\Post::doesntHave('comments')->get();
Nếu bạn cần nhiều hơn nữa, bạn có thể sử dụng method whereDoesntHave đặt "where" trong điều kiện query của bạn. Method này cho phép bạn thêm các ràng buộc tùy chỉnh cho 1 relationship, chẳng hạn như kiểu tra nội dung của 1 comment:
$posts = Post::whereDoesntHave('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
Counting Related Models
Nếu bạn muốn đếm số lượng các kết quả từ 1 relationship mà không load chúng, bạn có thể sử dụng withCount method, bạn sẽ đặt cột {relation}_count trên result model của bạn. Ví dụ:
Khi truy cập vào Eloquent relationship như property, các dữ liệu relationship là "lazy loaded". Điều này có nghĩa là các dữ liệu relationship không thực sự được load cho đến khi bạn truy cập vào property. Tuy nhiên, Eloquent có thể "eager load" các relationship vào thời điểm bạn truy vấn vào parent model. Eager loading làm giảm bớt các vấn đề truy vấn N+1. Để minh họa vấn đề truy vấn N+1, ta có Book model có liên quan đến Author model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
/**
* Get the author that wrote the book.
*/
public function author()
{
return $this->belongsTo('App\Author');
}
}
Bây giờ, chúng ta hãy lấý tất cả các books và author của nó:
Vòng lặp này sẽ thực hiện 1 truy vấn để lấy ra tất cả các books trên bàn, sau đó 1 truy vấn cho từng book để lấy ra author. Vì vậy, nếu chúng ta có 25 books, vòng lặp này sẽ chạy 26 truy vấn: 1 truy vấn để lấy ra các books và 25 truy vấn để lấy ra author cho các books.
Rất may, chúng ta có thể sử dụng eager loading để giảm thiểu số truy vấn này chỉ còn 2 truy vấn. Khi truy vấn, bạn có thể chỉ định các relationship được load bằng with method:
Để eager load các mối quan hệ lồng nhau, bạn có thể sử dụng dấu ".". Ví dụ, hãy eager load tất cả các author của các books và tất cả các contact của author trong 1 Eloquent statement:
Trong ví dụ này, Eloquent sẽ chỉ eager load các posts với điều kiện cột title của nó có chứa chữ "first". Dĩ nhiên, bạn có thể gọi các query builder method khác cho tùy chỉnh của bạn.
$users = App\User::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc');
}])->get();
Lazy Eager Loading
Đôi khi bạn có thể cần phải eager load 1 relationship theo parent model đã được lấy ra. Ví dụ, điều này có thể hữu ích nếu bạn cần phải tự động quyết định để load các model liên quan:
$books = App\Book::all();
if ($someCondition) {
$books->load('author', 'publisher');
}
Nếu bạn cần phải thiết lập các truy vấn rằng buộc vào các truy vấn eager loading, bạn có thể vượt qua một mảng mới quan hệ bạn muốn load. Các giá trị mảng nên là thể hiện của Closure:
$books->load(['author' => function ($query) {
$query->orderBy('published_date', 'asc');
}]);
Inserting & Updating Related Models
The Save Method
Eloquent cung cấp phương thức thuận tiện cho việc thêm các models tới 1 relationships. Ví dụ, có lẽ bạn cần phải chèn thêm 1 Comment cho 1 Post model. Thay vì tự thiết lập attribute post_id vào Comment, bạn có thể chèn Comment trực tiếp từ method save của relationships:
$comment = new App\Comment(['message' => 'A new comment.']);
$post = App\Post::find(1);
$post->comments()->save($comment);
Chú ý rằng chúng ta đã không truy cập comments relationships như một thuộc tính động (dynamic property). Thay vào đó, chúng ta gọi comments method để có được một thể hiện của relationships. Phương thức save sẽ tự động thêm giá trị post_id phù hợp với Comment model.
Nếu bạn cần save nhiều models có liên quan, bạn có thể sử dụng saveMany method:
$post = App\Post::find(1);
$post->comments()->saveMany([
new App\Comment(['message' => 'A new comment.']),
new App\Comment(['message' => 'Another comment.']),
]);
The Create Method
Ngoài save và saveMany methods, bạn có thể sử dụng create method, mà chấp nhận 1 mảng các thuộc tính, tạo ra 1 model và chèn nó vào cơ sở dữ liệu. Một lần nữa, sự khác biệt giữa save và create là save chấp nhận một thể hiện của Eloquent model đầy đủ trong khi create chấp nhận 1 mảng PHP:
$post = App\Post::find(1);
$comment = $post->comments()->create([
'message' => 'A new comment.',
]);
Belongs To Relationships
Khi cập nhật 1 belongsTo relationship, bạn có thể sử dụng associate method. Method này sẽ set foreign key trên model con.
Khi loại bỏ belongsTo relationship, bạn có thể sử dụng dissociate method. Method này sẽ thiết lập các foreign key thành null.
$user->account()->dissociate();
$user->save();
Many To Many Relationships
Eloquent cũng cung cấp cấp thêm một vài helper method để làm việc với các model liên quan 1 cách thuận tiện. Ví dụ, hãy tưởng tượng 1 user có thể có nhiều roles và 1 role có thể có nhiều users. Để gắn 1 role cho 1 user bằng cách chèn 1 bản ghi trong bảng trung gian, sử dụng attach method:
Dĩ nhiên, đôi khi nó có thể là cần thiết để loại bỏ 1 role từ 1 user. Để loại bỏ 1 quan hệ many-to-many record, sử dụng detach method. Phương thức detach sẽ loại bỏ các bản ghi phù hợp ra khỏi bảng trung gian. Tuy nhiên, cả 2 model vẫn còn lại trong cơ sở dữ liệu.
// Detach a single role from the user...
$user->roles()->detach($roleId);
// Detach all roles from the user...
$user->roles()->detach();
Để thuận tiện, attach và detach cũng chấp nhận đầu vào là mảng:
Bạn cũng có thể sử dụng sync method để xây dựng many-to-many associations. Phương thức sync chấp nhận 1 mảng các ID để đặt trên các bảng trung gian. Bất kỳ ID mà không phải là trong mảng sẽ được đưa ra khỏi bảng trung gian. Vì vậy, sau khi hoạt động này hoàn tất, chỉ có các ID có trong mảng sẽ tồn tại trong bảng trung gian.
$user->roles()->sync([1, 2, 3]);
Bạn cũng có thể thêm giá trị bảng trung gian với các ID:
Nếu bạn cần update 1 hàng hiện có trong pivot table của bạn, bạn có thể sử dụng phương thức updateExistingPivot. Phương thức này chấp nhận các pivot record foreign key và 1 mảng các thuộc tính để update: