Eloquent Relationships in Laravel 5.3 (Chap 3)

Index

  1. Eloquent Relationships in Laravel 5.3 (Chap 1)
  2. Eloquent Relationships in Laravel 5.3 (Chap 2)

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 ModelsTouching 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 areasstations 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 savesaveMany, 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 savecreate đó 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ì attachdetach 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