waste of time

主にPHP

Laravel5.2.x EloquentORM

これまで2年弱、PHPフレームワークといえばCakePHP2を使っていましたが、ここ2,3ヶ月ほど趣味でも仕事でもLaravel5を触っています。

Cake2.xからLaravel5.xに乗り換えて全然違うなぁと感じたのはDB操作周りです。いわゆるO/Rマッパーの使い勝手が結構違います。

問い合わせの結果はモデルインスタンス

CakePHP3もたぶんそうなってると思いますが、Laravel5は問い合わせの結果がモデルインスタンスとして返ってきます。first()やfind()のように結果が1件の場合はModelインスタンスがそのまま返ってきますが、get()やall()のように結果が複数件の場合はCollectionインスタンスが返ってきます。Collectionインスタンスにはイテレータが実装されており、普通の配列のようにforeachで回すことができます。(Collectionインスタンス複数のModelインスタンスにアクセスできる認識であってますかね?)

// Userモデルに対して制約を加えてモデルインスタンスを得る
$user = User::where('age', 20)
                ->orderBy('created_at', 'desc')
                ->first();

// 結果のフィールドにはプロパティとしてアクセスできる
echo $user->name;

// そのまま更新もできる
$user->name = 'ほげほげ';
$user->save();

クエリビルダと組み合わせての更新など、Modelクラスの実装を見るとだいたい何ができそうか確認できます。

https://laravel.com/api/5.2/Illuminate/Database/Eloquent/Model.html

リレーション/Eagerロード

Laravel5では、Illuminate\Database\Eloquent\Modelを継承したEloquentモデルにリレーションを記述します。 リレーションの定義を行った後であれば、Modelインスタンスから自由にリレーションにアクセスすることができます。

// articles -< comments のようなリレーションを仮定

// IDを指定してモデルインスタンスを得る
$article = Article::find(1);

// Articleモデルインスタンスからcommnetsテーブルのデータにアクセスできる
foreach($article->comments as $comment) {
    echo $comment->body;
}

これを見てEloquentの強力さに驚きました。驚きません?

ところが、上記のようにリレーションをループさせて取得する場合、クエリがループ回数分+1回発行されてしまう罠があります。リレーションのプロパティにアクセスする度にクエリを投げているわけです。 これを回避するため、Eagerロードという仕組みを使います。withメソッドでリレーションを指定すると、IN句で必要なデータを予めロードするようになります。

// articles -< comments のようなリレーションを仮定

// withメソッドでcommentsをEagerローディング
$article = Article::with('comments')->find(1);

// articlesに紐付くcommentsを事前に取得するため、クエリは2回しか発行されない
foreach($article->comments as $comment) {
    echo $comment->body;
}

おわり

もくもく開発してると知見が結構貯まっていくんですが、こうやって文章化すると復習になるし自分の中で整理されていい感じに定着して良いです。

hogeOrFuga()のような特殊なクエリビルダについて、便利で使う場面が多いのでまとめておきたい。 あと最近は認証系のコアトレイト拡張とかがっつりやったりしてるので、認証周りの拡張についてもあとでまとめておきたい。