LoginSignup
890
800

More than 3 years have passed since last update.

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

Last updated at Posted at 2016-05-29

取得するとき

職人

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で削除する :smile:

結論

この記事の目的はどこで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を行う
890
800
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
890
800