LoginSignup
69
63

More than 5 years have passed since last update.

LaravelのEloquentを使って複合主キーを使用したテーブルを操作する方法

Posted at

概要

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

69
63
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
69
63