> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 自訂 Pivot Model 與 chaperone

> 說明如何將 belongsToMany 的中介資料表當作自訂 Pivot Model 處理，以及 Laravel 13 新增的 chaperone 自動 Eager Loading。

## 什麼是自訂 Pivot Model

[belongsToMany（多對多）](/zh-TW/eloquent-relationships#belongstomany多對多)的中介資料表，預設會以未加工的 `Illuminate\Database\Eloquent\Relations\Pivot` 實例處理。若想在中介資料表加入額外欄位（例如審核時間、角色種類等），或想新增 accessor、mutator、自訂方法時，可以建立繼承 `Pivot` 的自訂 Model。

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    protected function casts(): array
    {
        return [
            'approved' => 'boolean',
        ];
    }
}
```

在 `belongsToMany` 的定義中呼叫 `using()`，告訴關聯改用這個自訂 Model。

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Role extends Model
{
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class)
            ->using(RoleUser::class);
    }
}
```

<Info>
  儲存自訂 Pivot Model 時，Model 名稱請務必採用 **字母順序的單數形式** 命名（也就是 `RoleUser`，而不是 `UserRole`）。不過這只是命名慣例，實際的類別名稱可以自由決定。
</Info>

## 以 `as()` 指定想取得的屬性

預設情況下，中介資料表的值透過 `pivot` 屬性存取。使用 `as()` 方法可以變更此名稱。

```php theme={null}
return $this->belongsToMany(Role::class)
    ->using(RoleUser::class)
    ->as('membership')
    ->withTimestamps()
    ->withPivot('approved');
```

```php theme={null}
foreach ($user->roles as $role) {
    echo $role->membership->approved;
    echo $role->membership->created_at;
}
```

## 額外欄位與 timestamp

若中介資料表有 `approved` 這類額外欄位，需以 `withPivot()` 明確納入取得對象。若要管理 `created_at` / `updated_at`，請呼叫 `withTimestamps()`。

```php theme={null}
return $this->belongsToMany(Role::class)
    ->using(RoleUser::class)
    ->withPivot('approved')
    ->withTimestamps();
```

<Warning>
  只有在以 `using()` 明確指定 Pivot Model 時，Eloquent 才會自動更新中介資料表的 `updated_at`。即使沿用預設的 `Pivot` 類別，`withTimestamps()` 仍然可以運作，但以 `using()` 指定自訂 Model 後，就可以使用自訂事件、自訂 cast 等功能。
</Warning>

## 從 Pivot Model 反向參照

自訂 Pivot Model 上可以自由定義指向宣告端 Model 與關聯端 Model 的 `belongsTo` 關聯。

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    public function role(): BelongsTo
    {
        return $this->belongsTo(Role::class);
    }

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

如此一來，即使只取得 Pivot Model 本身，也能透過 `$roleUser->role`、`$roleUser->user` 存取關聯 Model。不過若希望在父查詢執行時自動 Eager Load 這些關聯，可以使用下一節介紹的 `chaperone()`。

## 以 `chaperone()` 進行自動 Eager Loading（Laravel 13）

Laravel 13 新增了 `chaperone()` 方法，可將 Pivot Model 上定義的 `role()` / `user()` 等 `belongsTo` 關聯，於 `belongsToMany` 查詢執行時自動 hydrate（等同 Eager Load 的連結）。

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Role extends Model
{
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class)
            ->using(RoleUser::class)
            ->chaperone();
    }
}
```

呼叫 `chaperone()` 後，Eloquent 會自動推測 Pivot Model（`RoleUser`）所持有的 `belongsTo` 關聯名稱；在以 `Role::with('users')` 等方式取得集合時，會為每個 pivot 設定指向宣告端 Model 與關聯端 Model 的參照，且不需要額外的查詢。

```php theme={null}
$role = Role::with('users')->first();

foreach ($role->users as $user) {
    // 不需額外查詢，即可透過 pivot 存取父 Model
    echo $user->pivot->role->name;
}
```

### 使用非標準的關聯名稱時

若 Pivot Model 上 `belongsTo` 關聯的方法名稱與標準命名（宣告端／關聯端 Model 名稱的 camelCase 單數形）不同，可以透過 `chaperone()` 的參數明確指定。

```php theme={null}
return $this->belongsToMany(User::class)
    ->using(RoleUser::class)
    ->chaperone(declaring: 'role', related: 'user');
```

<Tip>
  `chaperone()` 是可以連中介資料表相關參照也一併解決「N+1 問題」的機制。在頻繁從 Pivot Model 參照父 Model 資訊（如同時顯示審核時間與使用者名稱）的應用中，搭配一般的 `with()` Eager Load 使用，效果非常好。
</Tip>

## 下一步

<Card title="關聯" icon="link" href="/zh-TW/eloquent-relationships">
  回頭複習包含 belongsToMany 在內的基本關聯定義方式。
</Card>

<Card title="Eloquent Observers 與 Model 事件" icon="bolt" href="/zh-TW/advanced/eloquent-observers">
  學習如何以 Model 事件 hook Pivot Model 的儲存、更新。
</Card>


## Related topics

- [Eloquent 關聯入門](/zh-TW/eloquent-relationships.md)
- [從 Laravel 12 升級到 13 指南](/zh-TW/blog/upgrade-12-to-13.md)
- [自訂 Agent](/zh-TW/packages/laravel-copilot-sdk/custom-agents.md)
- [自訂 Provider](/zh-TW/packages/laravel-copilot-sdk/custom-providers.md)
- [Eloquent 的自訂 Cast](/zh-TW/advanced/eloquent-casts.md)
