11. Eloquent
ORM
ORMとは
ORM(オブジェクトリレーショナルマッパー)は、ソフトウェア開発において、データベースとオブジェクト指向プログラミングの間でデータを効果的にマッピングするための設計パターンです。
オブジェクトとテーブルのマッピング
ORMはデータベーステーブルとプログラム内のEntity(エンティティ)の間で、フィールド(プロパティ)の対応関係を定義します。
CRUD操作
CRUDにより、データ作成、読み込み、更新、削除などのデータ操作がオブジェクト指向プログラムで簡単に実行できます。
クエリ言語の抽象化
ORMは、プログラミングでSQLなどのクエリを書かずにデータ操作できます。また異なるテーブル間のリレーションシップに対応し、関連データを取得できます。
SQLとORMの比較
SQLの場合
DB操作するにはSQLが必要です。以下は「users」テーブルのデータを取得するSQLです。
SELECT * FROM users;
このSQLを実行するには、DB接続プログラミングを作成しなければいけません。
$db_connection = 'mysql';
$db_name = 'my_shop';
$db_host = 'localhost';
$db_user = 'root';
$db_password = '';
$dsn = "{$db_connection}:dbname={$db_name};host={$db_host}";
try {
$pdo = new PDO($dsn, $db_user, $db_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $e) {
echo "接続失敗: " . $e->getMessage();
exit;
}
$sql = 'SELECT * FROM users;';
$stmt = $pdo->query($sql);
$users = $pdo->fetchAll(PDO::FETCH_ASSOC);
ORMの場合
データベース接続やSQL実行などをORMに委任することで、プログラムのソースコードが削減できます。
Eloquent
$users = User::all();
QueryBuilder
QueryBuilderとは
QueryBuilder(クエリビルダー)は、SQL文を直接記述するのではなく、直感的なメソッドチェーンを使ってデータベース操作するライブラリです。直接SQLを実行することも可能で、比較的高速に処理できるのがメリットです。
PDOベース
QueryBuilderはPHPのDBライブラリにPDO( PHP Data Objects)ベースで設計されているため、面倒なDBまわりの処理を隠蔽しながらプログラミングできます。SQLインジェクションに対応しているため、アプリのフォームから悪意のあるリクエストを送信しても、クエリの誤動作を防ぎます。
DBファサード
DBファサードはデータベース操作するための抽象化レイヤーです。DBファサードを使用することで、CRUD処理をはじめとするDBクエリ操作を、Staticな構文で実行できます。
DBファサードの利用
QueryBuilderを利用するには、DBファサードIlluminate\Support\Facades\DB で読み込みます。
use Illuminate\Support\Facades\DB;
DBファサードの種類
DBファサードのはSQLライクな構文です。
$users = DB::table('users')->get(); // usersテーブルからデータを取得
$newUser = DB::table('users')->insert([
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => bcrypt('secret'),
]); // 新しいユーザーを挿入
$updatedUser = DB::table('users')
->where('id', 1)
->update(['name' => 'Jane Doe']); // IDが1のユーザーの名前を更新
$deletedUser = DB::table('users')
->where('id', 1)
->delete(); // IDが1のユーザーを削除
table()
table() はDBテーブルを指定して、オブジェクトを取得します。
DB::table(テーブル名);
get()
get() はテーブルのレコードをすべて取得します。
// SELECT * FROM items;
DB::table('items')->get();
count()
count() はレコード件数を取得します。
// SELECT count(*) FROM items;
$count = DB::table('items')->count();
max(), min()
max(), min() は指定したカラムの最大値、最小値を取得します。
// SELECT max(price) FROM items;
$max_price = DB::table('items')->max('price');
// SELECT min(price) FROM items;
$min_price = DB::table('items')->min('price');
Eloquent
Eloquentとは
Eloquent(エロクエント)は、Laravelで最も簡単なORMライブラリで、QueryBuilderをベースに拡張したライブラリです。artisasnコマンドでモデル作成すれば、Eloquentをすぐ利用できるように設計されています。
- Eloquent:DB操作が高機能で簡単だが、自由度が低い
- QueryBuilder:DB操作が比較的高速で、自由度が高い
Eloquentの基本
モデルファイルは「Model」クラスを継承しており、Eloquentを簡単に利用できます。クラスにプロパティやメソッドを追加して、より柔軟なDB操作ができます。
App/Models/Item.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Item extends Model
{
use HasFactory;
}
テーブル名
もう一度、現在のテーブルを確認しておきます。
itemsテーブル
項目 | カラム名 | データ型 | NOT NULL | オプション |
---|---|---|---|---|
ID | id | bigint unsigned | Yes | Primary Key, auto_increment |
商品名 | name | varchar(255) | Yes | |
値段 | price | int | Yes | |
作成日 | created_at | timestamp | Yes | |
更新日 | updated_at | timestamp | Yes |
テーブル名自動認識
Eloquentでは、パスカルケースのクラス名に対して、スネークケース複数形のテーブル名として自動認識するようになっています。
- クラス名:パスカルケース「Item」
- テーブル名:スネークケースの複数形「items」
テーブル名の任意指定
テーブル名を任意で指定したいときは、クラスプロパティ「$table」にテーブル名を指定します。
protected $table = "テーブル名";
fillableとguarded
fillable
fillableは、明示的にデータを代入するためのテーブルカラムの配列で、ホワイトリスト化ともいいます。例えば「name」「price」のデータをユーザが任意に代入するときに設定します。
protected $fillable = [
'name',
'price',
];
- テーブルカラムの配列
- ホワイトリスト化
guarded
guardedはfillableとは逆にデータを代入させないブラックリストのテーブルカラムです。例えば「id」「created_at」「updated_at」などのデータは、フレームワークのプログラムやSQLで自動更新させず、ユーザに設定はさせません。
protected $guarded = [
'id',
'created_at',
'updated_at',
];
- テーブルカラムの配列
- ブラックリスト化
レコード挿入
Eloquentのメソッド
Eloquentの機能は、インスタンス経由やモデルクラス経由(Facade)で実行できます。
インスタンス経由
$model = new Model();
$model->method();
モデルクラス経由(Facade)
Model::method();
実行されるSQL
Eloquentを利用すると、SQLを直接コーディングしなくても実行できます。
Eloquent
$posts = ['name' => 'Alice', 'age' => 20];
User::create($posts);
$user = User::find(1);
SQL
INSERT INTO users (name, age) VALUES('Alice', 20);
SELECT * FROM users WHERE id = 1;
- create()
- save()
save()
save() はモデルインスタンスを生成して、fill() でデータを代入してDB保存します。
$posts = ['name' => 'Alice', 'age' => 20];
$user = new User();
$user->fill($posts);
$user->save();
create()
create() はモデルクラスのStaticメソッドでDB保存します。データは連想配列を代入します。
$posts = ['name' => 'Alice', 'age' => 20];
User::create($posts);
商品データ追加
モデル利用
「ItemController」で「Item」モデルをuseします。
ItemController.php
use App\Models\Item;
「use Item」と入力して、コードアシスタント機能を使うと便利です。
レコード追加
ItemControllerのstore() に「items」テーブルのレコード追加処理を実装します。
ItemController.php
public function store(Request $request)
{
$posts = $request->all();
Item::create($posts);
return redirect()->route('item.index');
}
レコード取得
get()
get() はすべてのレコードを取得するメソッドです。
Item::get();
「items」レコード取得
ItemControllerの*index()* で「items」テーブルのレコードをすべて取得します。取得したデータは、dd() でデバッグします。
ItemController.php
public function index()
{
$items = Item::get();
dd($items);
return view('item.index');
}
ブラウザで確認すると、「items::array」で「items」データが確認できます。
結果
データ取得
「items」テーブルからレコードを取得し、データをViewに受け渡します。
ItemController.php
public function index()
{
$items = Item::get();
$data = ['items' => $items];
return view('item.index', $data);
}
foreachディレクティブ
Bladeでは、データの繰り返しは foreachディレクティブで記述できます。
@foreach (配列 as 変数)
処理
@endforeach
foreachディレクティブで、データはモデルクラスのオブジェクトとしてアクセスします。
@foreach ($items as $item)
$item->id
$item->name
$item->price
@endforeach
商品一覧表示
foreachディレクティブで商品一覧表示します。
item/index.blade.php
@extends('layouts.app')
@section('content')
<h2>商品</h2>
<div>
<a href="{{ route('item.create') }}">新規追加</a>
</div>
<div>
<table class="table">
<tr>
<th></th>
<th>商品名</th>
<th>価格</th>
</tr>
@foreach ($items as $item)
<tr>
<td><a href="{{ route('item.edit', $item->id) }}">編集</a></td>
<td>{{ $item->name }}</td>
<td>{{ $item->price }}</td>
</tr>
@endforeach
</table>
</div>
@endsection
「item/」にアクセスして、「Item」モデルのデータが一覧表示できるか確認してみましょう。