概要
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テーブルを使用しています。
テーブル生成マイグレーション
各テーブルを作成するための、マイグレーションファイル。
<?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');
}
}
<?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を無効化しています。
<?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'];
}
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