取得するとき
職人
User::find(1);
ナイス職人
User::active()->createdLastMonth()->get();
Userクラスにクエリースコープを作って、それを使う
クエリースコープは下記のようになる
class User extends Model
{
public function scopeActive($query)
{
$query->where('active', true);
}
}
ほぼSQL書いてる急ぎの職人
User::where('active', true)->where('created_at', '>', Carbon::now()->subMonth())->get();
ここはもうSQLを書くことに近づいてきてるね
便利だけど、気をつけてください!
これはすごくメンテしにくいコードに進むパターンだ。
データを入れるとき(インサートでも、アップデートでも)
職人
$user->fill($request->all())->save();
fill()
を使うと、Eloquentは$fillable
をチェックして、このプロパティを設定できるかどうかを確認してくれるね。
$fillable
を無視したい場合はforceFill()
を使うけど、気をつけてね!
普通、forceFill
を使うのはデータベースシーダーとかだね。
書くことが好きな職人
$user->name = $request->name;
$user->email = $request->email;
// ... 永遠に続くorz
$user->birthday = $request->birthday;
$user->save();
これはそんなに悪いパターンじゃないけど、フィールドの数が多いほど、悪いパターンになっていく。
そして、この方法は$fillable
を無視するから、注意!できるだけfill()
にしてください
メソッド名に騙されてる可能性が高い人
$data = ['name' => 'Shintarou', 'is_administrator' => true];
$user->update($data);
直接SQLでデータを入れてるだけですね。
SQLを使えるのは力強いほど危険で、気をつけないとね。
上の例えで、データが$request->all()
から来てる場合、update($data)
することで、なるはずのない誰かが管理者になるかもしれない。
もちろん、update()
使いたいときもあります!
User::haveNotLoggedOnForFewMonths()->update(['inactive' => true]);
複数行にアップデートをしたいときには完璧だね!
作成するとき
## 職人
User::create($data);
これは一番簡単な方法だね!読みやすいから使われるけど、実際には下記のようになっている
public static function create(array $attributes = [])
{
$model = new static($attributes);
$model->save();
return $model;
}
ということで、下記のように書いてもおk!同じことになる。
(new User($data))->save();
使う場合を考えられなかったけど、一応ある方法
User::insert($data);
SQLのupdate()
ができるように、SQLのinsert()
もできます… ちゃんとした理由がないと使わないでくださいね。
これはタイムスタンプを自動的に入れないし、$fillable
もチェックしてくれないんだ。
削除するとき
職人
User::find(1)->delete();
モデルを取得してから削除する。
注意:SELECT(find
)してから、DELETEをしている。クエリーは2つ
PKだけで削除できる職人
User::destroy(1);
User::destroy([1, 2]);
取得せずに削除してる。クエリーは1つ
職人かもしれない、メソッド名に騙されてる人かもしれない
User::whereActive(false)->delete();
updateとinsertと同じ、SQL向きのメソッドだ。
複数行で削除したいなら、便利だけど注意が必要
直接でSQLのDELETEだから、Userクラスにたとえ、SoftDeletesのTraitがあったとしても、deleted_at
をアップデートせずに、その1行がデータベースから消される。
それはもちろん危ないし、誰も望んでいないことだから、そのとき狙いはきっと下記のようなコードだね。
User::whereActive(false)->update(['deleted_at' => Carbon::now()]);
だけど、今回は削除するロジックは2つの場所になるね… EloquentのSoftDeletesのTraitを使いたいね!
$inactiveUserIds = User::whereActive(false)->lists('id');
User::destroy($inactiveUserIds);
すべてのIDを取得してから、クエリー1つですべてのIDをEloquentで削除する
結論
この記事の目的はどこでEloquentのパワーフルなモデルから、自由なQuery BuilderでSQLになることを別々にすることだね。
User::where()
みたいなメソッドを使うときは、EloquentのQuery Builderのインスタンスをもらうから注意!
そのQuery Builderオブジェクトにinsert()
、update()
、delete()
を呼ぶとモデルのいろんな設定を無視して、単純にSQLとして行われる。
推敲
// 3つも同じ結果だけど…
User::where('id', 1)->get()[0]; // 読みづらい
User::where('id', 1)->first(); //
User::find(1); // 読みやすい
User::find(1)->fill($data)->save(); // Eloquent Modelとしてアップデートする
User::where('id', 1)->update($data); // Query BuilderのUPDATEを行う
// 3つも同じ
$user0 = User::create($data);
$user1 = new User($data);
$user1->save();
$user2 = (new User)->fill($data);
$user2->save();
User::find(1)->delete(); // Eloquent Modelを取得してから、削除する
User::where('id', 1)->delete(); // Query BuilderのDELETEを行う