この記事ではLaravelでデータベースに複数の新規レコードを追加する方法を紹介します。
Laravel側で複数レコードを保存する際にforeachとsave()を使っていましたが、これよりもっと良い方法があるのではないかと思い調べてみました。
より効率的に複数データの保存ができる方法があったのでそれを紹介します。
新規データ登録の方法も改めて整理したのでLaravelでデータベースに保存する方法を知りたい方もぜひ参考にしてみてください。
この記事を読むメリット
- Laravelで複数データを一括で保存する方法が分かる
- 新規データ登録の方法にどんなものがあるか整理できる
新規レコードを保存する方法
まずはLaravelで新規レコードをデータベースに保存する方法を整理します。
3種類の保存方法があります。
- save()
- create()
- insert()
1つずつ簡単に使い方を紹介します。
save()
まずはsave()から。
私は新規登録する際はsave()を使っています。
使い方はこちらです。
public function createPostBySave()
{
$post = new Post();
$post->user_id = 1;
$post->content = 'テスト投稿';
$post->save();
return $post;
}
$userの中身は以下のようになります。
{
"user_id": 1,
"content": "save()で投稿追加",
"updated_at": "2024-07-21T03:46:57.000000Z",
"created_at": "2024-07-21T03:46:57.000000Z",
"id": 6
}
save()を使って新規レコードする際は、「new」を使って新しいモデルインスタンスを作成します。
続いて必要なカラム情報を設定していき、最後に「save()」とすると、新規レコードが追加されます。
fill()を使って配列を使った登録も可能
先ほどは1つずつカラムを指定して最後にsave()で登録していました。
しかしfill()メソッドを使うとまとめてカラム指定ができます。
public function createPostBySave()
{
$post = new Post();
$post->fill([
'content' => '投稿内容',
'user_id' => 1,
])->save();
return $post;
}
fill()の中に配列でキーとバリューをセットにして登録するとまとめてカラム指定ができます。
複数代入と呼ばれる方法となっています。
これはフォーム送信などの際に入力値をそのまま登録するときなどに使われます。
「$post->fill($request->all())->save()」などとすると、そのままフォームの内容を登録することができます。
しかしその際には注意点があります。
- フォーム内のname属性を登録するカラム名と合わせる
- 対象モデルの$fillableで対象カラムを指定する
$fillableの設定は以下のようにします。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'content',
'user_id',
];
}
こうすることで、「content」「user_id」の2つのみが変更可能なカラムに指定され、他のカラムは変更できないようになっています。
fillableについての詳しい記事はこちらの記事で紹介しています。
fillableの必要性と注意点をまとめています。
save()の返り値はboolean
ちなみに、save()の返り値はbooleanになります。
処理が正常に完了した場合はtrue、失敗した場合はfalseが返ってきます。
他のメソッドの返り値も気になる方は以下記事を参考にしてみてください。
以上、save()での新規レコード追加の方法でした。
エンジニアにおすすめ書籍
エンジニアになりたて、これから勉強を深めていきたいという方におすすめの書籍はこちら!
create()
続いてはcreate()です。
create()を使ったレコード追加は以下のようになります。
public function createPostByCreate()
{
$newPost = Post::create([
'content' => 'createメソッドで作成',
'user_id' => 1,
]);
return $newPost;
}
モデルクラスPostに対してcreate()を呼び出します。
その中身は先ほどのfill()でも行った複数代入です。
ですのでPost.phpで$fillableの設定が必須となります。
create()はsave()での新規追加処理をまとめてやってくれる
create()の特徴として先ほどのsave()でやっていた処理をまとめてやってくれているという特徴があります。
save()で行っていた、インスタンスの作成→カラム登録、保存処理をまとめて行っています。
こちらの方がコード量も少なく可読性も上がりそうです。
insert()
最後はinsert()になります。
insert()はこれまでのモデルインスタンスを使った追加ではなく、クエリビルダを使います。
クエリビルダとは、SQLのクエリ文を生成するために用意された一連のメソッドです。
素のSQL文よりも簡潔でわかりやすく実行させることができます。
追加方法は以下のようになります。
public function createPostByInsertOnePost()
{
$result = DB::table('posts')->insert([
'content' => 'insert()による投稿追加',
'user_id' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
return $result;
}
「DB::table(‘posts’)」の部分でテーブルを指定し、insert()の中身に必要なカラム設定を配列で指定します。
1点注意点としては、「created_at」「updated_at」は自動でつかないということです。
create()やsave()などのモデルインスタンスから追加する方法は、migration設定で
$table->timestampe()を使っていると、わざわざ指定しなくても自動で追加された日時が挿入されます。
insert()を使う際は忘れないようにしましょう。
1件の追加の際はcreate()もしくはsave()が適していると思います。
insert()の返り値もboolean
ちなみにinsert()の返り値もbooleanになります。
追加が正常に完了しているか確認するために使えます。
複数データを一括登録する場合は「insert()」を使う
ここから本題ですが、複数データを一括登録する場合は「insert()」を使うことで実現できます。
逆に先ほど紹介したsave()、create()では一括登録はできません。
1件追加の際はcreate()かsave()が適切だと述べましたが、複数データの一括登録はinsert()が適しています。
実際に一括登録する際のコードは以下のようになります。
public function createPostByInsert()
{
$posts = [
[
'content' => '最初の投稿',
'user_id' => 1,
'created_at' => now(),
'updated_at' => now(),
],
[
'content' => '2番目の投稿',
'user_id' => 1,
'created_at' => now(),
'updated_at' => now(),
],
[
'content' => '3番目の投稿',
'user_id' => 1,
'created_at' => now(),
'updated_at' => now(),
],
];
$result = DB::table('posts')->insert($posts);
return $result;
}
このように、入れたいデータを配列に格納し、insert()の引数に代入します。
これで複数のデータを一気に登録することができます。
insert()は複数代入の保護を受けられない
しかし、注意点もあります。
それは複数代入の保護を受けられないということです。
モデル側で$fillableの設定をしていたとしても、適用はされません。
ですのでセキュリティ的にリスクはあります。
理由は、メソッド種類の違いです。
insert()はクエリビルダのメソッドでcreate()やsave()はEloquent ORMのメソッドです。
$fillableによる複数代入保護はEloquentモデルにしか適用されないのでinsert()では適用されないみたいです。
ユーザー側が入力したものなどをデータ追加する際などにはinsert()は使用せず、ループ処理で
save()もしくはcreate()でデータ追加をした方が良いです。
$table->timestamps()の恩恵も受けられない。
同じ理由でinset()では「$table->timestamps()」の恩恵も受けられません。
マイグレーション時に「$table->timestamps()」と設定することで、Eloquentモデルではcreated_atとupdated_atの値が自動で更新されるようになっています。
insert()では自動で更新されません。
必要な場合は個別で指定して設定する必要があります。
適切な方法でデータ追加を行う
いかがだったでしょうか。
複数データの一括登録にはinsert()が適切になります。
しかし、セキュリティ面でリスクもあるので考慮が必要です。
要件に合わせて適切な方法を採用できるようになりましょう。