環境
- windows10
- DockerDesktop for Win 3.5.x
- Laravel 8.x
- PHP 8.x
- VsCode
- gitbash 2.32.0.1
前提
本記事を読んでいただくに際して、前提として以下のクラスは必ず押さえておく必要があります。理由としては、Eloquent ORMではいろいろなメソッドを呼び出すことが可能ですが、内部的にはEloquentビルダークラスを呼び出してよしなにクエリを組み立ててくれているからです。
- EloquentのModelクラス
- vendor/laravel/framework/src/Illuminate/Database/EloquentModel.php
- Eloquentビルダークラス
- vendor/laravel/framework/src/Illuminate/Database/EloquentBuilder.php
メソッド一覧
Laravelで使用可能なEloquent/クエリビルダーの主なメソッドと特徴およびその返り値(戻り値)をまとめました。
メソッド名 | 処理内容 | 返り値(戻り値) |
find | 主キーで単一のレコードを取得 | Modelのオブジェクト |
first | 単一のレコードを取得 | Modelのオブジェクト |
get | 複数のレコードを取得 | ModelのオブジェクトのCollection |
all | 全レコードを取得 | Modelクラスからの呼び出しならCollection。 |
with | リレーション | Builderクラスのオブジェクト |
where | クエリによる条件付与 | Builderクラスのオブジェクト |
create | 新規追加 ※Modelにfillable(ないしguarded)の設定が必要 | Modelのオブジェクト |
save | 新規追加(更新) | bool値 |
update | 更新 | Modelクラスのupdateは、bool値。 |
delete | 削除 | Modelクラスなら、bool値。Eloquentビルダーなら処理したレコード数。 |
destroy | 削除 | 処理したレコード数 |
各メソッドの詳細
tinkerコマンドで各メソッドの返り値を確認できるのでこちらを使用する
find(findOrFail)
- メソッド概要
- 主キーでレコードを取得できるメソッド
- 属するクラス
- Eloquentビルダークラス
- 返り値
- Modelのオブジェクト(インスタンス)
※findOrFailだと、モデルが見つからなかった場合に例外を投げる
- Modelのオブジェクト(インスタンス)
>>> App\Models\ModelUser::query()->find(1)
=> App\Models\Model\User {#4617
id: 1,
name: "Shaniya Grimes",
email: "damore.karolann@example.com",
..
}
>>> App\Models\ModelUser::query()->findOrFail(198388372)
Illuminate\Database\Eloquent\ModelNotFoundException with message 'No query results for model [App\Models\ModelUser] 198388372'
ちなみに、公式でも紹介されているように、より簡潔に下記のよう(Model::メソッド名)に記述することも可能ですが、IDEの補完が効かなるのでちょっと微妙。上記のように、明示的にEloquentビルダーを介してメソッドを呼び出す形式のほうがよい。
>>> ModelUser::findOrFail(1)
=> AppModelsModelUser {#3621
id: 1,
name: "Shaniya Grimes",
email: "damore.karolann@example.com",
..
}
IDEの補完が効かなくなる理由
- findメソッドに限った話ではないですが、Modelクラスに存在しないメソッドを直接呼び出そうとすると、IDEから判断できなくなるため
- 存在しないメソッドが呼び出せるのはおかしくない?となりますが、実際には、Modelクラス(vendorlaravelframeworksrcIlluminateDatabaseEloquentModel.php)の__call()から内部的にEloquentビルダーを呼び、そこからfindメソッドを呼び出すという仕組みになっている
- もちろん、以下のようなModelクラスに存在するall()などは直接Modelのオブジェクトから呼び出しても補完が効くので特に問題はないが、結局内部的にはquery()でEloquentビルダーを呼び出している
public static function all($columns = ['*']) { return static::query()->get( is_array($columns) ? $columns : func_get_args() ); }
first()
- メソッド概要
- 最初のレコードを1件だけ取得できるメソッド
- 属するクラス
- Eloquentビルダークラス
- 返り値
- Modelのオブジェクト(インスタンス)
>>> App\Models\ModelUser::query()->first()
=> App\Models\ModelUser {#4585
id: 1,
name: "Shaniya Grimes",
email: "damore.karolann@example.com",
..
}
get()
- メソッド概要
- 複数レコードを取得できるメソッド
- 属するクラス
- Eloquentビルダークラス
- 返り値
- Modelのオブジェクト(インスタンス)が入ったコレクション
>>> App\Models\ModelUser::query()->get()
=> IlluminateDatabaseEloquentCollection {#3604
all: [
App\Models\ModelUser {#3605
id: 1,
name: "Shaniya Grimes",
..
},
App\Models\ModelUser {#3606
id: 2,
name: "Isobel Fisher",
..
},
..
]
all()
- メソッド概要
- 全レコードを取得できるメソッド
- 属するクラス
- Modelクラス、Eloquentビルダークラス
- 返り値
- Modelクラス
- Modelのオブジェクト(インスタンス)が入ったコレクション
- Eloquentビルダークラス
- Modelのオブジェクト(インスタンス)が入った配列
- Modelクラス
Modelクラス
>>>
$modelUser = new ModelUser();
$modelUser->all();
=> Illuminate\Database\Eloquent\Collection {#3592
all: [
App\Models\ModelUser {#3604
id: 1,
name: "Shaniya Grimes",
..
},
App\Models\ModelUser {#3615
id: 2,
name: "Isobel Fisher",
..
},
]
Builderクラス
>>> ModelUser::query()->get()->all()
=> [
App\Models\ModelUser {#3614
id: 1,
name: "Shaniya Grimes",
},
App\Models\ModelUser {#3600
id: 2,
name: "Isobel Fisher",
},
ちなみにcollect()を使用すると、コレクションクラスのオブジェクトを作成することが可能なので、これに対して、all()すると配列が得られる
>>> collect([1, 2, 3])
=> IlluminateSupportCollection {#3594
all: [
1,
2,
3,
],
}
with
- メソッド概要
- リレーション
- 属するクラス
- Modelクラス、Eloquentビルダークラス
※ただし最終的にはEloquentビルダーのwithが実行される
- Modelクラス、Eloquentビルダークラス
- 返り値
- Builderクラスのオブジェクト。whereなり、getなりがチェーンできる
>>> ModelUser::query()->with("stocks")->where('id', '=', "2")->get()
=> Illuminate\Database\Eloquent\Collection {#3569
all: [
App\Models\ModelUser {#3576
id: 2,
name: "Isobel Fisher",
stocks: Illuminate\Database\Eloquent\Collection {#3593
all: [
App\Models\ModelStock {#3567
id: 2,
user_id: 3,
name: "Mr. Lennie Renner V",
},
],
},
},
],
}
where
- メソッド概要
- クエリに条件を付与する
- 属するクラス
- Eloquentビルダークラス
- 返り値
- Builderクラスのオブジェクト。getなりがチェーンできる
>>> ModelUser::query()->with("stocks")->where('id', '=', "2")
=> Illuminate\Database\Eloquent\Builder {#3568}
create
- メソッド概要
- 新規追加
- 属するクラス
- Eloquentビルダークラス
- 返り値
- Modelのオブジェクト
>>> App\Models\ModelPost::query()->create([
"user_id" => 1,
"title" => "hoge",
"detail" => "foo",
])
=> App\Models\ModelPost {#3592
user_id: 1,
title: "hoge",
detail: "foo",
..
}
save
- メソッド概要
- 新規追加(更新でも使用可能)
- 属するクラス
- Modelクラス
- 返り値
- Bool値。成功したら、true失敗したらfalseを返す
$modelPost = new ModelPost();
=> App\Models\ModelPost {#3611}
$modelPost->user_id = 1;
$modelPost->title = "hoge";
$modelPost->detail = "foo";
$modelPost->save();
=> true
update
- メソッド概要
- 新規追加(更新でも使用可能)。
- 属するクラス
- Modelクラス・Eloquentビルダークラスの両方から呼び出し可能だが、それぞれプロセスが異なる
- 返り値
- Modelクラス
- bool値
- 内部的にはfill+saveすることで更新
- Eloquentビルダークラス
- 更新件数が返る
- 内部的には、クエリビルダを使って更新
- Modelクラス
Modelクラス
>>> $modelPost = new ModelPost();
>>> $modelPost = $modelPost::find(3);
=> App\Models\ModelPost {#3794
id: 3,
user_id: 2,
title: "更新後の記事タイトル",
detail: "Repellendus ipsa ullam corporis iusto tenetur. Dicta impedit eius minima harum aut et. Molestiae voluptas harum qui magnam. Quibusdam consectetur officiis corporis qui et quasi nihil.",
created_at: "2022-01-01 03:08:08",
updated_at: "2022-01-06 08:21:01",
}
>>> $modelPost->title = "更新後の記事タイトル";
>>> $modelPost->update();
=> true
Eloquentビルダー
>>> ModelPost::where("id","=","3")->update(["title" => "hoge"])
=> 1
delete
- メソッド概要
- レコードの削除
- 属するクラス
- Modelクラス・Eloquentビルダークラスの両方から呼び出し可能だが、それぞれプロセスが異なる
- ModelクラスはConnectionInterfaceのdeleteメソッドを呼び出して削除
- Eloquentビルダーはクエリビルダを使って削除
- Modelクラス・Eloquentビルダークラスの両方から呼び出し可能だが、それぞれプロセスが異なる
- 返り値
- Modelクラス
- bool値
- Eloquentビルダークラス
- 処理したレコード数
- Modelクラス
Modelクラス
>>> ModelUser::find(3)->delete()
=> true
Eloquentビルダー
>>> ModelPost::where("id", "=", "15")->delete()
=> 1
destroy
主キーを引数に渡すと、そのレコードを削除可能。(主キーの配列を渡せば複数のレコードを削除可能)。また、Modelクラスからのみ呼び出し可能なメソッド
>>> ModelPost::destroy(10)
=> 1
以上です。長々と書きましたが、まとめると、
- IDEの補完を最大限生かすためにも、Eloquentビルダーを介して(Model::query())クエリを組み立てるほうがよさそう
- 各メソッドはModelクラス(ないしEloquentビルダー)固有のメソッドなのか、どちらでも使えるメソッドなのかということをある程度理解して使うとスムーズに記述できそう
- 各メソッドの返り値が何なのかを理解しているとスムーズに記述できそう(Collectionなのか、Eloquentビルダークラスのオブジェクトなのか、Modelのオブジェクトなのか...)
まとめ
いかがでしたでしょうか。本記事では、laravelを学習しはじめの頃に遭遇する419エラーが出る仕組みをざっくり紹介しています。結論から言うと、laravelのフレームワークが、CSRF対策を行ってくれているために、Httpリクエスト時に必要な情報が抜けているとエラーが表示されるという仕組みです。