概要
LaravelのEloquentを使用して複合主キーを使用したテーブルを操作する方法です。多対多の中間テーブルで使用することが多いと思います。
ユーザ同士のフォロー機能を例にすると下記のようなテーブル。
Field | Type | Null | Key |
---|---|---|---|
following_user_id | int(10) | NO | PRI |
followed_user_id | int(10) | NO | PRI |
created_at | timestamp | NO | |
updated_at | timestamp | NO |
ここではフォロー/フォロワーを実装するために、usersとfollowersの2テーブルを使用しています。
テーブル生成マイグレーション
各テーブルを作成するための、マイグレーションファイル。
usersテーブル
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function($table) {
$table->increments('id');
$table->string('nickname', 100)->nullable;
$table->string('introduction', 500)->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
followersテーブル
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFollowersTable extends Migration {
public function up()
{
Schema::create('followers', function(Blueprint $table) {
$table->integer('following_user_id')->unsigned();
$table->integer('followed_user_id')->unsigned();
$table->timestamps();
// 外部キー設定(必要だったら)
$table->foreign('following_user_id')->references('id')->on('users');
$table->foreign('followed_user_id')->references('id')->on('users');
// プライマリキー設定
$table->unique(['following_user_id', 'followed_user_id']);
});
}
public function down()
{
Schema::drop('followers');
}
}
Eloquentクラス
Followerクラスではプライマリキーを指定して、incrementを無効化しています。
Follower.php
<?php
class Follower extends Eloquent
{
// テーブル名
protected $table = 'followers';
// プライマリキー設定
protected $primaryKey = ['following_user_id', 'followed_user_id'];
// increment無効化
public $incrementing = false;
protected $fillable = ['following_user_id', 'followed_user_id'];
}
User.php
class User extends Eloquent
{
// テーブル名
protected $table = 'users';
protected $guarded = array('id');
// フォローしているユーザ一覧を取得する
public function followUsers()
{
return $this->belongsToMany('User', 'followers', 'following_user_id', 'followed_user_id')
->withTimestamps();
}
// フォローされているユーザ一覧を取得する
public function followedUsers()
{
return $this->belongsToMany('User', 'followers', 'followed_user_id', 'following_user_id')
->withTimstamps();
}
}
できること/できないこと
上記のテーブルとFollowerクラスでできることとできないこと。
- データ作成はできる
$follower = Follower::create(['following_user_id' => 6, 'followed_user_id' => 10]);
- first/allによるデータ取得はできる
$follower = Follower::first();
$followers = Follower::all();
- saveによる保存はできない(※1)
$follower = Follower::first();
$follower->user_id = 1;
$follower->save();
- 関連モデルからattach/detachはできる
$user = User::find(1);
$user->followUsers()->detach(2);
$user->followUsers()->attach(2);
※1 基本的に中間テーブルとして使う場合が多いので、直接操作することはあまりないと思うのですが、どうしても複合主キーを使用したEloquentクラスからsaveを呼び出したい場合は、下記参考リンクのようにoverrideすることにより実装できる。
参考
http://laravel.com/docs/4.2/eloquent#working-with-pivot-tables
https://github.com/laravel/framework/issues/5517