---
description: https://morioh.com/p/adf2a700f4e2
---

# Adding & Retrieving Pivot Table Columns in Many To Many Laravel Eloquent Relationships

## Pivot tables and many-to-many relationships trong Laravel

## Pivot tables and many-to-many relationships trong Laravel

Hôm nay chúng ta cùng tìm hiểu về Eloquent trong Laravel với mối quan hệ nhiều - nhiều (many to many relationship). Thoạt đầu, có thể sẽ hơi lạ và khó định nghĩa cụm từ pivot tables nhưng tính năng này rất hữu dụng trong việc build many-to-many relationship với Laravel framework. Pivot tables về cơ bản là một bảng trung gian giữa 2 bảng chính (main tables). Chúng ta sẽ cùng tìm hiểu cụ thể ở ví dụ thực tế dưới đây.

**Example of pivot tables:**

Ở trong documentation của Laravel, họ lấy ví dụ về mối quan hệ giữa **User** và **Role**, một user về cơ bản có nhiều role và ngược lại. Để dễ hiểu, mình sẽ lấy một ví dụ thực tế khác đó là , _một phần yêu cầu của bài cuối kỳ môn học về webservices của mình_, mối quan hệ giữa bài viết và các tags (**article - tag relationship**). Ví dụ như các bài viết trên viblo chẳng hạn, hay như bài viết này của mình sẽ có các tag như: Laravel, PHP, Eloquent mà trong tag Laravel thì có nhiều bài viết khác như về Trait, gulp,…

Đầu tiên, chúng ta sẽ tạo 2 bảng chính. Ở ví dụ này, chúng ta sẽ tạo 2 bảng **article** và **tag** trước:

```
public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('short_intro');
            $table->text('content');
            $table->string('slug')->nullable();
            $table->integer('category_id')->unsigned();
            $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
            $table->integer('author_id')->unsigned();
            $table->foreign('author_id')->references('id')->on('authors')->onDelete('cascade');
            $table->timestamps();
        });
    }
```

tiếp theo là bảng tag:

```
public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('slug')->nullable();
            $table->timestamps();
        });
    }
```

Bước tiếp theo, chúng ta sẽ tạo pivot table dựa trên 2 bảng chính là article và tag. Ở đây chúng ta cần chú ý một chút:

* Tên của pivot table bao gồm tên của 2 bảng chính (ở dạng số ít), ngăn cách nhau bởi dấu gạch dưới (underscore) và sắp xếp theo thứ tự bảng chữ cái (alphabetical).
* Để tạo pivot table đơn gianr chúng ta có thể dùng

```
    php artisan make:migration
```

hoặc dùng Jeffrey Way’s package [Laravel 5 Generators Extended](https://github.com/laracasts/Laravel-5-Generators-Extended#pivot-tables) Mặc định trong pivot table sẽ chỉ có 2 trường article\_id và tag\_id. Chúng ta sẽ nói thêm về việc customize sao nếu như muốn add thêm trường vào pivot table. Do vậy ở ví dụ này pivot table của chúng ta sẽ có tên là **article\_tag**

**Model**

Ở phần trên, chúng ta mới chỉ tạo ra migration. Gio chúng ta sẽ tạo model và mối quan hệ many to many cho 2 bảng qua pivot table. Việc này có thể làm ở một trong hai bảng chính. Tất nhiên là bạn có thể viết ở cả 2 bảng (nhưng thường thì k ai làm như vậy cả). Ở ví dụ này, mình sẽ viết ở **tag** model như sau:

```
class Tag extends Model
{
    //
  protected $table = 'tags';
  protected $fillable = ['name'];

  public $timestamps = true;

  public function articles() {
    return $this->belongsToMany('App\Article', 'article_tag', 'article_id', 'tag_id');
  }
}
```

Như mọi người thấy, ở đây mình chỉ ra rõ 2 trường của pivot table là article\_id và tag\_id. Lợi ích: Chúng ta sẽ chẳng cần tạo thêm một model là article\_tag làm gì cả. Chúng ta sẽ quản lý nó dựa trên commands.

**Managing Many-to-Many Relationships: attach-detach-sync**

Đã có bảng và model rồi. Chúng ta chỉ việc xử lý việc lưu dữ liệu dựa trên pivot table.

Ví dụ chúng ta muốn add thêm 1 tag cho 1 bài viết cụ thể, chúng ta sử dụng method **attach()**:

```
$article = Article::find($article_id);
$article->tags()->attach($tag_id);
```

Và kết qủa thu được là gía trị của article\_id và tag\_id được thêm vào bảng article\_tag.

Cũng tương tự vậy, nếu như chúng ta muốn gỡ bỏ 1 tag từ article thì chúng ta sử dụng method **detach()**:

```
$article->tags()->detach($tag_id);
```

hoặc nếu như bạn muốn gỡ bỏ toàn bộ tag trong article đó- easy :

```
$article->tags()->detach();
```

Chúng ta cũng có thể attach() và detach() rows bằng việc truyền vào một tham biến (params) như một array:

```
$article->tags()->attach([123, 456, 789]);
```

```
$article->tags()->detach([123, 456, 789]);
```

Một function khác cũng hữu ích đó là update toàn bộ pivot table: **sync()**

Method này chỉ accept một mảng ID truyền vào trong pivot table. Do vậy, tất cả ID không nằm trong mảng ID đó sẽ bị loại bỏ khỏi pivot table và trong pivot table lúc này sẽ chỉ còn lại ID nằm trong mảng truyền vào:

```
$article->tags()->sync([1, 2, 3]);
```

Nếu bạn không muốn detach những ID tồn tại trong đó, bạn nên dùng method **syncWithoutDetaching** :

```
$article->tags()->syncWithoutDetaching([1, 2, 3]);
```

**Additional Columns in Pivot Tables**

Như đã đề cập ở trên, chúng ta sẽ làm gì nếu như muốn thêm 1 trường và pivot table? ĐƠn giản là chúng ta sẽ dùng hàm **withPivot()** để thêm vào pivot table (mình sẽ lấy 1 ví dụ khác):

```
public function skills() {
    return $this->belongsToMany('App\Skill',  'skill_user', 'user_id', 'skill_id')->withPivot('level');
}
```

ở ví dụ này, mình giả sử mình có 2 bảng chính đó là **user** và **skill** với 1 pivot table là **skill\_user**. Mối quan hệ là many to many, một user có thể có nhiều skill như HTML, CSS, PHP,... và tương tự skill cũng vậy. Trong pivot table skill\_user mình muốn thêm một trường đó là **level**. Thuộc tính này dùng để define level của user về skill nào đó. Ví dụ như user1 có skill PHP ở mức độ là intermediate và Java level là talented. Bạn cũng có thể thêm timestamps vào bằng việc gọi đến method **withTimestamps()**.

Bây giờ, chúng ta có thể gọi value level với thuộc tính đó là **pivot**:

```
@foreach ($member->skills as $skill)
    <div class="col-md-3">
        <div class="circular-bar">
            <div class="circular-bar-chart" data-percent="{{$skill->pivot->level}}" data-plugin-options='{"barColor": "{{rand_color()}}", "delay":300}'>
                <strong>{{$skill->name}}</strong>
                <label><span class="percent">{{$skill->pivot->level}}</span>%</label>
            </div>
        </div>
    </div>
 @endforeach
```

**Updating A Record On A Pivot Table**

Nếu như bạn muốn update 1 row đã có trong pivot table, bạn có thể sử dụng **updateExistingPivot** method.

```
$article->tags()->updateExistingPivot($tag_id, $attributes);
```

**Conclusion**

Pivot table là một technique rất tiện trong việc xây dựng eloquent và mối quan hệ many to many, chúng ta không cần thiết phải tạo một model riêng cho pivot table. Cảm ơn mọi người đã quan tâm !

**References**

[Pivot tables and many-to-many relationships](http://laraveldaily.com/pivot-tables-and-many-to-many-relationships/)

[Eloquent: Relationships](https://laravel.com/docs/5.3/eloquent-relationships)
