EloqeuentはLaravelの持つORM(データベースをマッピングしたモデル)です。これには他テーブルとの関係性をモデル内に定義するためのリレーションという仕組みが備わっています。
Eloquent:リレーション 6.x Laravel
例えば、次の様になります
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * ユーザーに関連する電話レコードを取得 */ public function phone() { return $this ->hasOne( 'App\Phone' ); } } // 別ファイルで /** @var App\Phone $phone ユーザに関連する電話レコードインスタンス */ $phone = User::find( $id )->phone; |
上記の様にプロパティとして呼び出すだけで適切なSQLが発行され、関連したレコードを元にしたモデルインスタンスを得られます。
この呼び出しだけでも便利なのですが保存でも活躍します。詳しくは次リンクの”関連したモデルの挿入/更新”です。
Eloquent:リレーション 6.x Laravel
例としては次になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * ユーザーに関連する電話レコードを取得 */ public function phone() { return $this ->hasOne( 'App\Phone' ); } } // 別ファイルで $phone = new Phone( $validatedRequest ); // user_idカラムの様なリレーションに使うカラムの値が自動で代入される保存処理 User::find( $id )->phone()->save( $phone ); |
リレーション用のidの代入が不要な保存です。かなり便利です。当然の様に1対多の保存も備わっています。
1 2 3 4 5 6 | $post = App\Post::find(1); $post ->comments()->saveMany([ new App\Comment([ 'message' => 'A new comment.' ]), new App\Comment([ 'message' => 'Another comment.' ]), ]); |
話は変わってEloquentにはpushというメソッドもあります。これはリレーションを使った再帰保存です。具体的には次の様になります。
1 2 3 4 5 6 7 8 | $post = App\Post::find(1); $post ->comments[0]->message = 'Message' ; $post ->comments[0]->author->name = 'Author Name' ; $post ->push(); // postに関連するcommentテーブルのレコード一つ目のmessageカラムを更新して保存 // postに関連するcommentテーブルのレコード一つ目に関連するauthorテーブルのレコードのnameカラムを更新して保存 |
トランザクションを書いた後長々とsaveを書き続ける必要はありません。pushで事足ります。
pushメソッドにはもの足りない部分があります。それは先述した外部キーの自動割り当てです。これがないため、外部キーを手動で割り当てた後にpushかひとつづつrelation()->save($model)をするかの二択になりがちです。いいとこどりをしたいものです。いいとこどりをするには例えば次の様なメソッドが考えられます。既存のpushメソッドになかったrelation()->save($model)を増やしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?php namespace App\Models\Eloquents; use App\Models\Eloquents\Contracts\HasRulesContract; use App\Models\Eloquents\Traits\HasRules; use Eloquent as Model; use Illuminate\Database\Eloquent\Collection; /** * 認証機能持ち以外のモデルのベース */ abstract class BaseEloquent extends Model { /** * リレーションを参照した自動キー割り当て機能を搭載したpushメソッド. * 再帰によって呼び出し済みのリレーション先全てをsaveする. * @param bool $skipSave このループでsaveをスキップするならばtrue. 主に一つ前のループでリレーションを元にした保存をした時に使用 * @return bool */ public function push( $skipSave = false) { if (! $skipSave && ! $this ->save()) { return false; } // すべての関係をデータベースに同期するために単にスピンスルーします // 関係を作成し、このpushメソッドを介して各モデルを保存します。 // モデルインスタンスのこれらのネストされたリレーションすべてに再帰します。 foreach ( $this ->getRelations() as $relationName => $models ) { $models = $models instanceof Collection ? $models ->all() : [ $models ]; foreach ( array_filter ( $models ) as $model ) { // HasOneOrManyがあった上で保存に失敗したらreturn false if (method_exists( $this , $relationName ) && $this -> $relationName () instanceof HasOneOrMany) { if ( $this -> $relationName ()->save( $model )) { $successSave = true; } else { return false; } } // 再帰 if (! $model ->push( $successSave ?? false)) { return false; } } } return true; } } |