🙆‍♀️

Eloquent ORMを分かりやすく説明してみる

2024/10/02に公開

はじめに

Laravelで採用されているEloquent ORMについて書いていきます。
というのも、最近Laravelの案件に入りましてEloquentだのクエリビルダだのデータベースとのやり取りをする手段が複数あってどれを選択するべきかと少し混乱しました。
自分の脳内を整理すると同時に私と同じようなLaravel入門者のお役に立てればと思います。
※当記事ではLaravelバージョン11を前提として進めていきます。

ORMとは

そもそもORMってなんだっけ? というところから。
ORMとは「Object-Relational Mapping」の略で、オブジェクト指向プログラミング言語とリレーショナルデータベースの間のやり取りをいい感じに取りまとめてくれる技術のことです。
わざわざ生のSQL文を書かなくても容易にデータを取り出せたり、加工できたりするのはこのORMのおかげなわけです。
ORMには様々な種類があってLaravelではEloquent ORMが採用されています。

https://e-words.jp/w/O-Rマッピング.html

Eloquentとは

では、本題のEloquentとは?についてですが、先述の通りLaravelで採用されているORMのことです。
筆者の感想ですが、Eloquentの特徴は「簡単」であることです。

itemsテーブルを例に挙げて説明していきます。
まず、itemsテーブルをEloquentで扱う際には普段のモデルの作成手順と同じように以下コマンドを実行します。

php artisan make:model Item

上記のコマンドを実行するだけで、作成したModelに以下の記述が加わります。

use Illuminate\Database\Eloquent\Model;

なので、意識せずとも勝手に使ってたなんてことがよくあるかもしれませんね。
これくらいEloquentは「簡単」に使えるんです。

他にも例えば「DBから値を取得したい!」と思ったら、

$items = Item::get();

こんな感じで書いてあげると簡単に値が取れます。
SQL文をかかずに直感的で容易に使えるのが初心者にも分かりやすくて、いいですよね。

他にも手軽にテーブル間のリレーションが設定できたり、N+1問題を解決できたりと初心者泣かせの問題たちを片っ端から解決してくれます。

Eloquentの特徴

Eloquent Collection

Eloquent ORMではEloquent Collectionというヘルパー関数が使用できます。
そもそもCollectionとは何かと言うと、手軽にデータ操作ができるように設計されたLaravelで用意されているオブジェクトのことです。
配列やDBクエリの結果をcollection化することができ、collection化するとcollectionで用意されている150種類にも及ぶヘルパー関数が使えるようになります。

https://readouble.com/laravel/11.x/ja/collections.html#collection-method-list

そんな便利なCollectionという機能がありながら、モデルの操作に特化したCollectionをまた別で用意してくれているのがEloquent Collectionです。
ちなみに、Eloquent CollectionはCollectionを継承して作られているので、CollectionのインスタンスにはEloquent Collectionの関数が使用できますが、反対は不可能なのでエラーになります。

//IDが1のItemを取得
$item = Item::find(1);

//EloquentモデルからノーマルCollectionで値を取得する例
$items = Item::get();

//ノーマルCollectionからEloquent Collectionで値を取得する例
$item_collections = collect([1,2,3]);
$item = $item_collections->find(1);
//Method Illuminate\Support\Collection::find does not exist.

20種類近くの関数が用意されているので、用途に合わせて使用してください。

https://readouble.com/laravel/11.x/ja/eloquent-collections.html

リレーション

Eloquentを用いると容易にリレーションが組めます。
リレーションの詳細な説明は割愛しますが、DB内のテーブル同士の関係性を定義するものです。

リレーションにはテーブルが二つ必要なのでStoreテーブルを定義していると仮定します。
今回は仮のテーブルなので中身については考えず、リレーションの組み方だけ参考にしていただければと思います。

//1対1のリレーション
class Item extends Model
{
    public function store() 
    {
        return $this->hasOne(Store::class);
    }
}

class Store extends Model
{
    public function item() 
    {
        return $this->belongsTo(Item::class);
    }
}

リレーションを組むと該当のモデルからのデータの取得が容易になります。

$item = Item::first();
$store_name = $item->store->name;
echo $store_name;
// Aショップ

https://readouble.com/laravel/11.x/ja/eloquent-relationships.html

Eager Loading

N+1問題を解決してくれるのがEagerLadingと呼ばれるクエリの操作方法。
リレーションを組んだモデル間であれば関連するデータを一度のクエリで取得することができます。
Eloquentではwith関数を用いてEager Loadingを実現できます。

//Storeと関連するitemが一度のクエリで取得できる
$stores = Store::with('items')->get();

ちなみに、with関数では以下のようなSQL文が発行されています。

SELECT * FROM stores;

SELECT * FROM items WHERE store_id IN (1, 2, 3, ...);

with関数を使用しないと以下のように大量のSQL文が発行され、システムの処理スピードが下がります。

SELECT * FROM stores;

SELECT * FROM items WHERE store_id = 1;
SELECT * FROM items WHERE store_id = 2;
SELECT * FROM items WHERE store_id = 3;
...
SELECT * FROM items WHERE store_id = 10;

詳しくはこちらの記事を参照してください。

https://readouble.com/laravel/11.x/ja/eloquent-relationships.html#eager-loading

クエリビルダとの違い

Eloquentと混合しがちな機能としてクエリビルダがあります。
混合していてもコードが書けてしまうほど類似した機能なので意識せずに使っている人もいる印象です。
異なる点をざっくり記載していきます。

記述方法

まず記述方法が異なります。
見てもらうと分かる通り、Eloquentの方が手軽に書けます。

//クエリビルダの記述法
DB::table('items')->where('name','pen')->get(); 
//Eloquentの記述法
Item::where('name','pen')->get(); 

戻り値

戻り値も異なります。

データ型 メソッド
クエリビルダ Collectionオブジェクト Collectionのメソッドが使用可能
Eloquent Eloquent Collectionオブジェクト Eloquent Collectionが使用可能

クエリビルダのメリット

書き方も複雑で戻り値も扱いづらい印象を受けたのではないかと思います。
しかしクエリビルダは複雑なクエリを書きたい場合に活躍します。
サブクエリを発行したり、パフォーマンスを重視する場面ではクエリビルダの方が優秀です。

他ORMと比較

Eloquent以外のPHPのORMとも比較してみました。
扱える関数はどのORMでも大差はなかったですが、Eloquentがその他二つに比べて若干多いかなという印象です。

Laravel Eloquent CodeIgniter Cake PHP
リレーション ×
Eager Loading × 自動で実行
アクセサ・ミューテタ

最後に

EloquentORMについて解説しました。
ORMをうまく活用できるとコードの記述量が減り可読性が上がると思います。
ここには記載されていない機能も多くあると思うので、引き続き勉強していこうと思います。

Discussion