LaravelテクニックのPivot
3237 ワード
リレーショナル・データベースで、パターンに一致する複数対のマルチテーブル関係を定義するには、2つのテーブルの関係として中間テーブルが必要です.Laravelではこのテーブルをpivotと呼び、関連するレコードをクエリーした後、
実際のアプリケーションでは、この中間テーブルには2つのテーブルの外部キーだけでなく、いくつかの追加のフィールドがあります.例を挙げます.
1人のユーザーは複数の部門に属することができます.すなわち、ユーザーと部門は多対多関係であり、1人のユーザーは異なる部門で役割が異なる可能性があります.つまり、ユーザーと役割も多対多です.この中間表の構造は以下の通りです.
すべての部門でユーザーが対応する役割を取得する場合:
手順はやはり煩雑で、このpivotが他のModelのように
Laravelのコードを検討したところ、実装可能であることがわかりました.まずクラスを新規作成します.
次に、
この時tinkerでテストできます
さらに、
pivot
のプロパティを使用して関連テーブルのフィールドにアクセスできます.$user = App\User::find(1);
foreach ($user->roles as $role) {
echo $role->pivot->created_at;
}
実際のアプリケーションでは、この中間テーブルには2つのテーブルの外部キーだけでなく、いくつかの追加のフィールドがあります.例を挙げます.
1人のユーザーは複数の部門に属することができます.すなわち、ユーザーと部門は多対多関係であり、1人のユーザーは異なる部門で役割が異なる可能性があります.つまり、ユーザーと役割も多対多です.この中間表の構造は以下の通りです.
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| user_id | int(10) unsigned | NO | | NULL | |
| role_id | int(10) unsigned | NO | | NULL | |
| department_id | int(10) unsigned | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+---------------+------------------+------+-----+---------+----------------+
すべての部門でユーザーが対応する役割を取得する場合:
foreach($user->departments as $department) {
$role = Role::find($department->privot->role_id);
}
手順はやはり煩雑で、このpivotが他のModelのように
$department->privot->role
でキャラクター情報を直接入手できれば便利です.Laravelのコードを検討したところ、実装可能であることがわかりました.まずクラスを新規作成します.
namespace App\PivotModels;
use Illuminate\Database\Eloquent\Relations\Pivot;
use App\Models\Role;
use App\Models\Department;
class UserRole extends Pivot
{
public function role()
{
return $this->belongsTo(Role::class);
}
public function department()
{
return $this->belongsTo(Department::class);
}
}
次に、
App\Models\Department
クラスでnewPivot
メソッドを書き換えます.public function newPivot(Model $parent, array $attributes, $table, $exists)
{
if ($parent instanceof User) {
return new UserRole($parent, $attributes, $table, $exists);
}
return parent::newPivot($parent, $attributes, $table, $exists);
}
App\Models\User
クラスのdepartments
メソッドを変更します.public function departments()
{
return $this->belongsToMany(Department::class, 'user_role', 'department_id', 'user_id')
->withPivot(['department_id', 'user_id', 'role_id']) //
->withTimestamps();
}
この時tinkerでテストできます
$pivot = $user->departments()->first()->pivot; // App\PivotModels\UserRole
$pivot->role; //
$pivot->department; //
さらに、
Illuminate\Database\Eloquent\Relations\Pivot
というクラスは、実際にはIlluminate\Database\Eloquent\Model
クラスに継承されており、すなわちmutators機能によってgetter/setterをカスタマイズすることができる.(テストpivotはmodelの$appends
/$with
などの属性をサポートせず、定義しても対応する動作はありませんが、load
メソッドで関連オブジェクトをロードできます).