Eloquent Relationships in Laravel 5.3 (Chap 3)
This post hasn't been updated for 7 years
Index
Mở đầu
Đây là bài kết thúc cho loạt bài về Eloquent Relationships
trong Laravel 5.3, phần này mình sẽ giới thiệu cho các bạn 2 mục khá quan trọng đó là Inserting & Updating Related Models
và Touching Parent Timestamps
. Để hiểu rõ hơn thì các bạn hãy kéo xuống phía dưới đọc và cùng làm 1 số ví dụ với mình nhé.
The Save Method
Ví dụ nếu bạn muốn thêm 1 station
nằm trong 1 area
. Cách thủ công mà mọi người nghĩ đến đó là sẽ chèn thêm từng trường vào trong bảng station
, trong đó có cả area_id
. Nhưng thay vào đó, Eloquent cung cấp cho chúng ta một phương thức save
để chèn trực tiếp 1 station
:
$station = new App\Station(['name' => 'Tan Son Nhat']);
$area = App\Area::find(1);
$area->stations()->save($station);
Nếu như đã đọc những phần trước mình viết thì chắc hẳn các bạn đã biết 2 bảng areas
và stations
có quan hệ 1-n. Và đoạn code trên mình không truy cập vào quan hệ stations
như một thuộc tính động mà mình đã gọi phương thức stations()
để có được một thực thể của quan hệ.
Phương thức save
sẽ tự động thêm giá trị area_id
phù hợp vào model Station
mới.
Một điều rất thuận tiện ở đây vì là quan hệ 1-n nên bạn có thể lưu nhiều giá trị station
cùng một lúc cho cùng 1 area
, bạn có thể sử dụng phương thức saveMany
:
$area = App\Area::find(1);
$area->stations()->saveMany([
new App\Station(['name' => 'Tan Son Nhat']),
new App\Station(['name' => 'Long Bien']),
]);
The Save Method And Many-Many Relationship
Khi làm việc với quan hệ n-n thì phương thức save
chấp nhận một mảng các thuộc tính của bảng trung gian như là tham số thứ 2:
App\Course::find(1)->subjects()->save($subject, ['expires' => $expires]);
The Create Method
Ngoài phương thức save
và saveMany
, bạn cũng có thể sử dụng phương thức create
, cái mà cho phép một mảng của các thuộc tính, tạo ra 1 model, và chèn nó vào trong database. Một lần nữa, sự khác nhau giữa save
và create
đó là save chấp nhận một Eloquent model instance
(một biến đã được gán giá trị) trong khi create
chấp nhận một PHP array
:
$area = App\Area::find(1);
$station = $area->stations()->create([
'name' => 'Tan Son Nhat',
'address' => '134 Nguyen Trai',
]);
Hoặc bạn cũng có thể viết ngắn gọn:
$area = App\Area::find(1);
$station = $area->stations()->create(['Long Bien','213 Nguyen Van Cu']);
Trước khi sử dụng phương thức create
bạn phải biết về Mass Assignment
. Nói dễ hiểu thì phương thức create
sẽ chèn các giá trị theo các thuộc tính trong mảng fillable
protected $fillable = ['name', 'address'];
Belongs To Relationships
Khi bạn cập nhật một quan hệ belongsTo
, bạn có thể sử dụng phương thức associate
. Phương thức này sẽ thiết lập khóa ngoại trên model con.
$account = App\Account::find(10);
$user->account()->associate($account);
$user->save();
Khi xóa quan hệ belongsTo
, bạn có thể sử dụng phương thức dissociate
. Phương thức này sẽ thiết lập lại khóa ngoại cũng như quan hệ trên model con:
$user->account()->dissociate();
$user->save();
Many To Many Relationships
Attaching / Detaching
Chắc các bạn ai cũng đều rất ngại khi làm việc với quan hệ n-n, nhưng giờ Eloquent đã cung cấp một số phương thức rất hữu ích để làm việc với các model quan hệ. Vẫn ví dụ 1 course
có thể có nhiều subjects
và 1 subject
cũng có thể nằm trong nhiều courses
. Để thêm 1 subject
cho 1 course
bằng cách chèn thêm 1 bản ghi vào trong bảng trung gian thì ta sử dụng phương thức attach
:
$course = App\Course::find(1);
$course->subjects()->attach($subjectId);
Ngoài ra bạn cũng có thẻ chèn 1 mảng các giá trị vào bảng trung gian như sau:
$course->subjects()->attach($subjectId, ['expires' => $expires]);
Ngược lại khi bạn muốn xóa bỏ 1 subject
khỏi 1 course
. Để xóa bỏ bản ghi quan hệ n-n, sử dụng phương thức detach
. Phương thức này sẽ xóa bỏ bản ghi phù hợp khỏi bảng trung gian. Tuy nhiên, cả hai model vẫn sẽ còn trong database:
// Detach a single subject from the course...
$course->subjects()->detach($subjectId);
// Detach all subjects from the course...
$course->subjects()->detach();
Để thuận tiện hơn thì attach
và detach
cũng chấp nhận một mảng các ID đầu vào:
$course = App\Course::find(1);
$course->subjects()->detach([1, 2, 3]);
$course->subjects()->attach([1 => ['expires' => $expires], 2, 3]);
Syncing Associations
Bạn có thể cũng sử dụng phương thức sync
để khởi tạo quan n-n. Phương thức sync
chấp nhận 1 mảng ID để đưa vào bảng trung gian. Bất kì ID nào không ở trong mảng này sẽ bị xóa khỏi bảng trung gian. Vì vậy sau khi tính toán hoàn thành, chỉ có những ID trong mảng sẽ tồn tại trong bảng trung gian:
$course->subjects()->sync([1, 2, 3]);
Bạn cũng có thể truyền thêm các giá trị cho bảng trung gian cùng với ID:
$course->subjects()->sync([1 => ['expires' => true], 2, 3]);
Mình đã từng làm một vài ví dụ với sync
, ví dụ như tạo 1 bảng gồm nhiều subjects
, mỗi một hàng sẽ có 1 ô checkbox
(lưu id của subject) để mình lựa chọn thêm những subjects
nào vào trong course
. Khi mình tích chọn nhiều giá trị đồng nghĩa với việc mình sẽ chèn nhiều giá trị subjects
của course
vào bảng trung gian. Việc mình muốn đó là subjects
nào của course
đã tồn tại trong bảng trung gian rồi thì sẽ không được chèn thêm vào nữa, và subjects
nào mình không tích chọn mà đã tồn tại trong bảng trung gian thì sẽ được xóa đi. Và sync
đã giúp mình làm việc đó rất dễ dàng với 1 dòng code như trên.
Touching Parent Timestamps
Khi một model belongsTo
hoặc belongsToMany
những model khác, như là Station
sẽ thuộc về 1 Area
, đôi khi rất hữu ích khi cập nhật lại timestamp của model cha khi model con được cập nhật. Ví dụ, khi 1 model Station
được cập nhật, bạn có thể muốn tự động cập nhật tới timestamp update_at
của Area
. Eloquent làm việc này dễ dàng đó là chỉ cần thêm thuộc tính touches
chứa tên của quan hệ đến model con:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Station extends Model
{
/**
* All of the relationships to be touched.
*
* @var array
*/
protected $touches = ['area'];
/**
* Get the area that the station belongs to.
*/
public function area()
{
return $this->belongsTo('App\Area');
}
}
Bây giờ, khi bạn cập nhật 1 Station
, model Area
sở hữu nó sẽ được cập nhật tại cột update_at
:
$station = App\Station::find(1);
$station->name = 'Gia Lam';
$station->save();
Vậy là xong loạt bài của mình về Eloquent Relationships
. Trên docs của Laravel viết khá là dài và có thể các bạn sẽ ngại đọc. Nếu vậy thì hãy đọc bài viết của mình bởi mình đã chia ra thành nhiều phần nhỏ để tiện theo dõi hơn. Cảm ơn các bạn đón đọc!
Thankyou very much! (love)
Tham khảo
Inserting & Updating Related Models: https://laravel.com/docs/5.3/eloquent-relationships#inserting-and-updating-related-models
Touching Parent Timestamps: https://laravel.com/docs/5.3/eloquent-relationships#touching-parent-timestamps
All Rights Reserved