2千分後の私へ。
もくじ
ポイント
App/Http/Models/Job.php
<?php namespace App\Http\Models; use App\User; use Illuminate\Database\Eloquent\Model; class Job extends Model { public function users() { return $this->belongsToMany('App\Http\Models\Users', 'user_job', 'job_id', 'user_id'); }
- 第1引数:リレーション先のモデル名
- 第2引数:リレーション先のテーブル名
- 第3引数:自モデルの主キー
- 第4引数:相手モデルの主キー
App/Http/Models/User.php
<?php namespace App\Http\Models; use Illuminate\Database\Eloquent\Model; class Users extends Model { public function departs() { return $this->belongsToMany('App\Http\Models\job', 'user_job', 'user_id', 'job_id'); }
こちらも引数を同じにします。
あとはuser_jobの中間テーブルを作成すれば良い。
指定したjob_idを持つユーザの名前とidを取得する例
$jobUsers = $job->find($job_id)->users()->pluck('name', 'id')
以下ゆっくり解説🐱✨
テーブルはこんな感じ
users
user_id | role | name | create_at | updated_at | |
1 | 1 | yuu | yuu@example.net | 2019-12-29 03:18:05 | 2019-12-29 03:18:05 |
devices
udid | device_name | create_at | updated_at |
1 | windows_phone | 2019-12-29 03:25:09 | 2019-12-29 03:25:09 |
2 | ios | 2019-12-29 03:18:05 | 2019-12-29 03:18:05 |
3 | android | 2019-12-29 03:25:09 | 2019-12-29 03:25:09 |
user_device_chains
user_id | udid |
1 | 2 |
1 | 3 |
中間テーブルのマイグレーションファイルの注意
user_device_chainsテーブル定義ファイル
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\DB; class CreateUserDeviceChainsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() Schema::create('user_device_chains', function (Blueprint $table) { $table->unsignedBigInteger('user_id')->nullable(true)->comment('users.user_id - 会員情報id'); $table->string('udid')->nullable(true)->comment('devices.udid - デバイスid'); $table->foreign('user_id') ->references('user_id') ->on('users') ->onDelete('cascade'); $table->foreign('udid') ->references('udid') ->on('devices') ->onDelete('cascade'); $table->primary(['user_id', 'udid']); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('user_device_chains'); } }
ポイント① BigIncrementで生成されたid列はunsignedBigIntegerで指定する
$table->unsignedBigInteger('user_id')->nullable(true)->comment('users.user_id - 会員情報id'); $table->string('udid')->nullable(true)->comment('devices.udid - デバイスid');
ポイント② 外部キー制約
$table->foreign('user_id') ->references('user_id') ->on('users') ->onDelete('cascade'); $table->foreign('udid') ->references('udid') ->on('devices') ->onDelete('cascade');
ポイント③ 複合主キーの設定
$table->primary(['user_id', 'udid']);
これを設定しないとパフォーマンスが落ちる
users
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\DB; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrements('user_id')->comment('会員情報テーブル主キー'); $table->integer('user_role_id')->comment('会員種別'); $table->string('user_name')->nullable(true)->comment('会員名'); $table->string('email')->nullable(true)->comment('email'); $table->timestamp('created_at')->nullable()->comment('作成日時'); $table->timestamp('updated_at')->nullable()->comment('更新日時'); $table->index('email'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } }
ポイント① whereで検索されるものはindexをつける
$table->index('email');
devices
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\DB; class CreateUserDevicesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('devices', function (Blueprint $table) { $table->string('udid')->comment('devices.udid devicesテーブル主キー'); $table->string('device_name')->comment('ツール名'); $table->timestamp('created_at')->nullable()->comment('作成日時'); $table->timestamp('updated_at')->nullable()->comment('更新日時'); $table->index('udid'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('devices'); } }
リレーション定義
Models/User.php
<?php namespace App\Models; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; protected $carbon; protected $now; protected $primaryKey = 'user_id'; /** * The attributes that are mass assignable. * * @var array */ protected $guarded = [ ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; public function devices() { return $this->belongsToMany('App\Models\Device', 'user_device_chains', 'user_id', 'udid'); } public function userRoles() { return $this->belongsTo(UserRole::class, 'user_role_id', 'user_role_id'); } ・・・
Models/Devices.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Device extends Model { protected $primaryKey = 'udid'; protected $guarded = [ ]; public function users() { return $this->belongsToMany('App\Models\User', 'user_device_chains', 'udid', 'udid'); } }
Tinkerで確認
Userの確認
bash-5.0# php artisan tinker Psy Shell v0.9.12 (PHP 7.3.11 — cli) by Justin Hileman >>> use App\Models >>> User::find(1) [!] Aliasing 'User' to 'App\Models\User' for this Tinker session. => App\Models\User {#3089 user_id: 1, user_role_id: 1, user_name: yuu, email: yuu@example.net }
Devicesから
>>> User::find(1)->devices => Illuminate\Database\Eloquent\Collection {#3101 all: [ App\Models\Device {#3105 udid: "2", device_name: "ios", created_at: "2019-12-29 03:18:05", updated_at: "2019-12-29 03:18:05", pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3098 user_id: 1, udid: "1", }, }, App\Models\Device {#3102 udid: "3", device_name: "android", created_at: "2019-12-29 03:25:09", updated_at: "2019-12-29 03:25:09", pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3089 user_id: 1, udid: "3", }, }, ], }
リレーション先の値を利用した検索
iosを持っているかつ、user_role_idが1のuserを検索
$device_name = 'ios' $user_role_id = 1; $user = User::whereHas('devices', function($query) { $query->where('devices.name', $device_name); })->where('users.user_role_id', $user_role_id) ->get();
- whwreHasの中のfunction() {$query->where(‘devices.name’, $device_name);}で結合条件を指定してjoinさせて、
- 結合したデータに対して最後にwhere(‘users.user_role_id’, $user_role_id)で行を絞り混み
中間テーブルにデータを挿入する時はattach()を利用する
DB::beginTransaction(); try { $user = new User(); $user->user_name = $request->user_name; $user->email = $request->email; $user->password = $request->password; $user->save(); $user_id = $user->user_id; $udid = $request->udid; $device_name = $request->device_name; $userDevice = new Device(); $userDevice->timestamps = false; Device::create([ 'udid' => $udid, 'device_name' => $device_name ]); $user->devices()->attach( ['user_id' => $user_id], ['udid' => $udid], ['created_at' => $this->now], ['updated_at' => $this->now] ); DB::commit(); return response()->json(config('mail.message.add_user_success')); } catch (\Exception $e) { DB::rollback(); Log::error('WEB /users/me/verify - Class ' . get_class() . ' - PDOException Error. Rollback was executed.' . $e->getMessage()); return response()->json(config('error.databaseTransactionRollback')); }
外部キー制約をかけているので順番があります。
- usersテーブルにレコード挿入
- devicesテーブルにレコード挿入
- 中間テーブルにレコード挿入
Insertしたレコードのidを知りたい時
save()を行ってからプロパティで取得する
$instance->save(); $instance->id;
usersテーブルにレコードを挿入した時の例
$user = new User(); $user->user_name = $request->user_name; $user->email = $request->email; $user->password = $request->password; $user->save(); $user_id = $user->user_id; echo $user_id; // 2
usersテーブルのidのカラムはuser_idなので合わせて対応しています。
中間テーブルのカラムを取得する