データベースへのアクセスがModelクラスを通してできる、メソッドチェーンで条件が書ける、スコープが使える。
今はそれが「当たり前」になり、「Eloquent=ただのModel操作」という感覚に陥っていないでしょうか。
しかし、この当たり前に「無自覚な落とし穴」が潜んでいます。
- 「なぜModelを使うのか」
- 「どこまでをModelに書くのか」
これらを一度振り返ってみると、新たな気づきがあるかもしれません。
Eloquentをうまく扱うことは、コードをきれいに保つだけでなく、設計全体の質を底上げします。「😄ただ書ける」から「🧐きちんと考えて書ける」段階にステップアップしてみませんか?
ORMという視点を持つ
Eloquentを使うと、SQLを直に書かずとも、User::where('status', 'active')->get()
のように直感的な記述ができます。ここまでは多くの開発者が意識していることでしょう。
しかしEloquentの本質を「ただSQLを隠してくれるもの」と捉えてしまうと、ORM(Object-Relational Mapping)という重要な視点を見落としてしまいます。
しかし、Eloquentの便利さに慣れすぎて「なぜこれで動くのか」「この記述がどんな設計思想に支えられているのか」といった背景を意識することは少なくなりがちです。
EloquentはLaravelに組み込まれた強力なORMですが、そもそもこの「ORM」という概念そのものが、設計にどう関係してくるのでしょうか?
Eloquentを“モデルの魔法”として使うだけでなく、背後にある考え方を知っておくと、コードの見通しが格段に良くなります。
ここでは、ORMの基本思想とEloquentがどんなポジションにいるのかをざっくり見てみましょう。
ORMとは?
ORM(Object-Relational Mapping)は、「オブジェクト指向(プログラミング言語)の世界」と「リレーショナルデータベース(テーブルとカラム)の世界」を結びつけるための仕組みです。ふだん私たちがPHPでクラスやメソッドを定義するときは「オブジェクト指向の考え方」に基づいており、一方でデータベースは「テーブル」「カラム」「行」というリレーショナル(関係)モデルで動いています。ORMは、この2つの異なる概念を円滑につなげる“翻訳者”のような役割を担います。
例えば、テーブルをPHPのクラス(モデル)に見立てることで、レコードをクラスのインスタンスとして扱えるようになります。
- テーブル → クラス(モデル)
- カラム → クラスのプロパティ
- レコード → クラスのインスタンス
このアプローチによって、複数のテーブルを結合してデータを取得するといったデータベース中心の操作から、ビジネス上のオブジェクト同士のやり取りを考えるという発想へ移行しやすくなるのです。
ORMの信者、ActiveRecordとDataMapper
ORMを神とした時、その神との対話方法をどうするのか二つの考え方があります。
パターン | 特徴 | 例 |
---|---|---|
Active Record | モデル自身がDB操作の責任を持つ | Eloquent(Laravel), ActiveRecord(Rails) |
Data Mapper | モデルとDB操作の責任を分ける | Doctrine(PHP), SQLAlchemy(Python) |
ActiveRecordは実装パターンで、EloquentはActiveRecordで作成されたORMのライブラリになります。
よく分からない例えを出しててもあれなので、実装方法を紹介します。
Eloquent(ActiveRecord型)
以下のように、モデル自体がデータベースを参照します。
// app/Models/User.php
class User extends Illuminate\Database\Eloquent\Model {
protected $fillable = ['name', 'email'];
}
// 保存処理
$user = new User();
$user->name = 'Taro';
$user->email = 'taro@example.com';
$user->save(); // モデル自身がDB操作してくれる
- Model($user)から直接DBを参照できる
- ModelとDBロジックが混ざるので抽象化が難しい
Doctrine(DataMapper型)
Doctrineはドクトリンと読みます。保存処理は別の「エンティティマネージャ」が行います。ActiveRecordの方が操作しやすいですが、責務分離においては、こちらの方に軍配があります。
// src/Entity/User.php
/** @Entity @Table(name="users") */
class User {
/** @Id @GeneratedValue @Column(type="integer") */
private $id;
/** @Column(type="string") */
private $name;
/** @Column(type="string") */
private $email;
public function setName($name) { $this->name = $name; }
public function setEmail($email) { $this->email = $email; }
}
// 保存処理(Doctrine)
$user = new User();
$user->setName('Taro');
$user->setEmail('taro@****.com');
$entityManager->persist($user);
$entityManager->flush(); // ここでSQL発行
- objectをentityManagerに入力してflushでSQL発行します。
- ActiveRecordと比較して手続きが少し難しい
EloquentとDoctrineの違いまとめ
項目 | Eloquent (Active Record) | Doctrine (Data Mapper) |
---|---|---|
書き方 | モデル自身が保存 | 別のクラスが保存 |
構造 | シンプル、密結合 | 複雑、疎結合 |
学習コスト | 低(魔法っぽい) | 高(現実と向き合う) |
管理性 | 中〜低(Fat Model) | 高(でも複雑) |
ここまでが、Eloquentをもう少し俯瞰して捉えるための背景知識です。
この視点を持っておくことで、今後「Modelに何を書くべきか?」を考える際の足がかりになります。
コードを読めば設計が見える。Eloquentはそれを表現するツール
コードの中身には、開発者の意図や考えがすべて詰まっています。Eloquentの場合も同じで、「モデルに何を書くか」がすなわち「どういう設計をしているか」を表します。
モデルに何があるべきか? ただの属性だけではない
Laravelのモデルを初めて書くとき、多くの人は $fillable
や $casts
などを定義して終わりがちです。しかし、モデルは属性(フィールド)を抱えるだけの存在ではありません。
class User extends Model
{
// 属性の定義
protected $fillable = ['name', 'email', 'status'];
// リレーション:このユーザーが持つ投稿
public function posts()
{
return $this->hasMany(Post::class);
}
// スコープ:アクティブなユーザーだけを取得
public function scopeActive($query)
{
return $query->where('status', 'active');
}
// ビジネスロジック:ユーザーを退会処理する
public function deactivate()
{
$this->status = 'inactive';
$this->save();
}
}
- リレーション(関係性)
hasMany
やbelongsTo
などでモデル同士の繋がりを定義することで、「このモデルはどことどのようにやり取りするのか?」が見えてきます。
- 振る舞い(ビジネスロジックやスコープ)
- リレーションの設定だけではなく、ビジネス上の重要なロジックをモデルに閉じ込めたり、よく使うクエリをスコープとしてまとめたりすることができます。
- ビジネスロジック(
deactivate()
)
「ユーザーを退会させる」行為をコントローラに直接書かず、モデルに持たせる。

コントローラが抱える条件は、本当にその責務?
たとえばコントローラで下記のように書いていたものを、スコープやメソッドを呼ぶ形にリファクタリングすると、責務が整理されます。
// Before
$users = User::where('status', 'active')->get();
// After
$users = User::active()->get(); // スコープを呼ぶだけ
// Before
$user->status = 'inactive';
$user->save();
// After
$user->deactivate(); // ビジネスロジックをメソッド化
こうすることで、「状態や条件の管理はコントローラではなく、なるべくドメインに近い場所(モデルやサービス層)に寄せる」という方針をコードで表現できます。モデルが肥大化しそうな場合はサービス層やリポジトリ層を導入し、「それは本当にモデルの責務か?」を繰り返し検討するのがポイントです。
おわりに
Eloquentはただの「便利なModelツール」ではなく、設計と密接に関わる表現手段です。
モデルの中に“何を書くか”を意識することで、コードの意図が明確になり、保守性も上がっていきます。
コメントを残す