PHP
laravel

【Laravel】DBにデータを保存する方法。createとinsertの違いなど

DBにデータを保存する

DBにデータを保存する方法は、大きく分けてEloquentでモデルインスタンスを作成して保存する方法と、SQLで直で保存する方法の2通りあります。
Eloquentでモデルインスタンスを作成して保存する方法はさらにいくつかの方法に分かれます。

1. createメソッド

// fillableかguardedのどちらかを指定する必要あり
protected $fillable = ['name'];
// protected $guarded = [''];

$flight = App\Flight::create(['name' => 'Flight 10']);

モデルクラスからcreateメソッドを呼ぶことで、インスタンスの作成→属性の代入→データの保存を一気通貫でやってくれます。
さらに作成したインスタンスを返してくれるのも便利。
基本的にはcreateメソッドを使用するのが良いと思う。

注意しなければならない点として、Eloquentはデフォルトで複数代入から保護されているため、createメソッドを使う際は、fillableかguarded属性のどちらかを指定する必要があります。
fillableはホワイトリスト的に、guardedはブラックリスト的に指定します。
上記例では、nameを保存させたいのでfillableにnameを指定しています。

※複数代入とは

ユーザーからの入力を元にデータを保存する場合、悪意のあるユーザーがこちらの意図しないデータの保存・更新を行うように複数の項目を代入してくることです。
例えば、ユーザー作成の際に管理者権限にするかどうかは通常のページにはPOSTする項目として設定していないにも関わらず、悪意のあるユーザーが独自に項目を追加しPOSTすることで、管理者になってしまうようなものです。

2. fillメソッド → saveメソッド

// fillableかguardedのどちらかを指定する必要あり
protected $fillable = ['name'];
// protected $guarded = [''];

$flight = new App\Flight();

$flight->fill(['name' => 'Flight 10']);

$flight->save();

インスタンスの作成をnewで、属性の代入をfillメソッドで、DBへの保存をsaveメソッドでといくつかの処理に分けて行うスタイル。
インスタンスは作成したいが、DBへの保存は処理を分けたいなどの際に使用する。
createメソッドと同じく複数代入保護のため、fillableかguardedを指定する。
なお、findメソッドなどで取得したインスタンスに同じことをすればデータの更新になる。

3. 属性を直埋め → saveメソッド

$flight = new App\Flight();

$flight->name = $request->name; // 属性を直埋め

$flight->save();

2のfillメソッドと同じく、いくつかの処理に分けて行うスタイルだが複数代入から保護されない。
書き方としても冗長なため、あえて使用する意味はないと思う。

4. insertメソッド

App\Flight::insert(['name' => 'Flight 10']);

SQLで直にインサートするスタイル。
複数代入から保護されていないのでセキュリティ的に危険、モデルインスタンスを作成しているわけではないのでクエリスコープが無視されるなどのデメリットがある。
ただ、配列の配列をinsertの引数に渡して一度に多くのレコードをまとめて挿入できるので、ユーザーからの入力の可能性がないなど、上記デメリットを無視できる場合は使用した方がよい場合もある。

おまけ1. insertGetIdメソッド

$id = App\Flight::insertGetId(['name' => 'Flight 10']);

テーブルが自動増分IDを持っている場合はレコードを挿入した上、そのレコードのIDを返してくれる。

おまけ2. firstOrCreateメソッド/firstOrNewメソッド

// nameでフライトを取得するか、存在しなければ作成する
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);

// nameでフライトを取得するか、存在しなければインスタンス化する
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

どちらも一度は渡された引数でDBに条件に一致するレコードがないか探します。
なければ、あとはcreateメソッドとnewの違いで、一度にレコードの保存まで行うか、インスタンスの作成までにとどまるかの違い。

おまけ3. updateOrCreateメソッド

// OaklandからSan Diego行きの飛行機があれば、料金へ99ドルを設定する。
// 一致するモデルがなければ、作成する。
$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99]
);

第1引数で指定した条件に一致する既存のモデルで第2引数を更新するか、なければインスタンスの作成→レコードの保存まで行う。

参考

LaravelのORMで初心者から職人へ