Laravel でデータベース操作を簡単なサンプルを通して学びます。
データベース接続
Laravel で RDB を扱う方法は、大きく分けて 3 つあります。
- Query Builder(クエリビルダ)
- Eloquent (エレクエント) ORM
- SQL クエリ
それぞれの方法でテーブルからデータを取得する方法をみていきましょう。
クエリビルダ
クエリビルダを使えば、データベースへの問い合わせを簡易に行えます。 たとえば、下記のクエリビルダでは、tasks テーブルのすべての行を取得します。
todo/app/Http/Controllers/BasicController.php
の showTasksA
メソッド
(ソースは、Slackにて配布)
public function showTasksA(Request $request) {
$tasks = DB::table('tasks')->get();
return view('show-tasks', compact('tasks'));
}
生の SQL では、SELECT * FROM tasks
という文を記述することになります。一方、クエリビルダは、SQL 文ではなく、メソッドにてデータベースへの問い合わを行います。
SQL を使いこなしている方々にとっては、回りくどく思われる事でしょう。もちろん SQL 文を直接発行する方法もあります。
DB::table
というのは、Laravle の特徴であるファサードが使われています。
DB ファサードの実体は、Illuminate\Database\DatabaseManager
になります。
そして、table
というメソッドは下記のクラスのものになります。
\Illuminate\Database\Connection
戻り値は\Illuminate\Database\Query\Builder
になります。
API仕様を見れば、SQL に相当するメソッドがいくつもあることがみてとれます。
部分的に生 SQL を使用するためのメソッドもあります。
また、下記のようにメソッドチェインで where 句をつけることができます。
DB::table('tasks')->where('status',1)->get();
最後に get()メソッドを呼ぶことで SQL を発行します。
戻り値は連想配列ではなくcollection
になります。
collection
の子要素は、PHP のstdClass
オブジェクトになります。
Tinker で確認してみます。
$ php artisan tinker
Psy Shell v0.10.4 (PHP 7.4.0 — cli) by Justin Hileman
>>> $result = DB::table('tasks')->get();
=> Illuminate\Support\Collection {#3305
all: [#3314
+"id": 2,
+"title": "サンフランシスコ旅行",
+"status": 1,
+"description": "サンノゼ空港からパロ・アルトへの行き方を調べる",
+"created_at": null,
+"updated_at": null,
},
],
}
>>> $result[1] instanceof stdClass
=> true
>>>exit
Exit: Goodbye
クエリビルダの公式ドキュメントの日本語訳は下記にあります。
https://readouble.com/laravel/7.x/ja/queries.html
Eloquent ORM
Eloquent ORMは、Active Record パターンを実装した ORMです。 Active Record パターンは、Enterpise Application Patterns の一種で、テーブルとクラスを 1 対 1 で紐付けたものです。 Active Record パターンの実装はいくつかあり、Ruby 言語の Web フレームワークである Ruby on Rails の ORMが有名です。
定義 https://www.martinfowler.com/eaaCatalog/activeRecord.html
定義訳 https://bliki-ja.github.io/pofeaa/ActiveRecord/
ORMというものは、オブジェクト指向言語と RDB の間を仲介するものです。 オブジェクト指向言語からすると、データはオブジェクト。RDB では、データを表として扱うので両者の間に隔たりができます。 その隔たりを解消してくれるのが ORMです。 しかし、ORMにも限界があリます。効率よく使うには、SQL の知識が不可欠です。
Eloquent ORMを使っていきます。
モデルクラスの生成
モデルはテーブルに対して 1 対 1 に対応したものです。
tasks
テーブルに対応したtask
モデルを作ります。
モデルのひな型は、下記のコマンドで作れます。
$ php artisan make:model <モデル名>
ちなみにモデルの名称は、単数形で、テーブルの名称が複数形とするのが Laravel の標準です。
複数形を調べるには、Str::plural
を使用しhます。
$ php artisan tinker
>>> echo Str::plural('task');
tasks⏎
Laravel の標準機能は、上記のコマンドでモデルのテンプレートを生成してくれますが、中身は空のため実装が必要となってきます。
テーブルがすでにある場合は、テーブルからモデルを生成します。生成ツールとして下記を使用します。 https://github.com/krlove/eloquent-model-generator
モデル生成ツールのインストール
$ cd /var/www/html/todo
$ composer require krlove/eloquent-model-generator --dev
モデル生成
$ php artisan krlove:generate:model Task
app 以下に Task.php が できています。
app
└── Task.php
データベースの内容を表示
Eloquent ORM でのタスクの表示のソースは下記になります。
クエリビルダーでは、DB::table('tasks')->get()
と記述していたところが、Task::all()
となります。
todo/app/Http/Controllers/BasicController.php
の showTaskB
メソッド
(ソースは、Slackにて配布)
public function showTaskB(Request $request) {
$tasks = Task::all();
return view('show-tasks', compact('tasks'));
}
Illuminate/Database/Eloquent/Model
のstaticメソッド
であるall
の呼び出しています。
戻り値は、Illuminate\Database\Eloquent\Collection
が返されます。
子要素はApp\Task
になります。
tinkerで戻り値を確認します。
$ php artisan tinker
>>> App\Task::all()
=> Illuminate\Database\Eloquent\Collection {#4099
all: [
App\Task {#3632
id: 2,
title: "サンフランシスコ旅行",
status: 1,
description: "サンノゼ空港からパロ・アルトへの行き方を調べる",
created_at: null,
updated_at: null,
},
],
}
>>>exit
Exit: Goodbye
Eloquent ORMの公式ドキュメントの日本語訳は下記にあります。
https://readouble.com/laravel/7.x/ja/eloquent.html
SQLクエリ
複雑なテーブル構成の場合、Eloquent
どころか、Query Builder
でも問い合わせがつらくなります。
特に業務システムなんてものは、そもそも複雑で、生の SQL で記述した方がベターとなることが多いです。
そういう場合は、下記のように SQL 文を発行します。
public function showTaskC(Request $request) {
$states = DB::select('SELECT * from tasks');
return view('show-tasks', compact('states'));
}
select メソッドの引数は、SQL 文といっても、文字列です。 長い SQL 文の場合は、別ファイルに記述して読み込ませるようにするということもできます。
select メソッドの戻り値は配列になります。
tinkerで戻り値を確認します。
$ php artisan tinker
>>> DB::select('SELECT * from tasks')
=> [
{#3326
+"id": 2,
+"title": "サンフランシスコ旅行",
+"status": 1,
+"description": "サンノゼ空港からパロ・アルトへの行き方を調べる",
+"created_at": null,
+"updated_at": null,
},
]
>>> $result instanceof Illuminate\Support\Collection
=> false
>>> is_array($result)
=> true
>>> $result[1] instanceof stdClass
=> true
>>>exit
Exit: Goodbye
Query Builder
、Eloquent
とは戻り値が異なることに注意してください。
Query Builder
、Eloquent
は、Illuminate\Support\Collection
を返すので、後続の処理方法が異なってくることに注意してください
配列の子要素は、PHP のstdClass
オブジェクトになります。
Eloquent model
のhydrateメソッド
を使えば、モデルに変換ができます。
$ php artisan tinker
>>> $result = DB::select('SELECT * from tasks')
>>> App\Task::hydrate($result)
Illuminate\Database\Eloquent\Collection {#4318
all: [
App\Task {#4319
id: 1,
title: "bitcoinの半減期を調べる",
status: 2,
description: "bitcoinの半減期と価格の相関性を調べる",
created_at: null,
updated_at: null,
},
>>>exit
Exit: Goodbye
また、SQL 文に引数を渡す事もできます。
$results = DB::select('select * from tasks where id = :id', ['id' => 1]);
この引数の渡し方は、SQL インジェクションを防ぐために提供されています。 下記のような SQL 文の書き方は、推奨されません。
DB::select("select * from tasks where id = $id");
DB::select('select * from tasks where id =' . $id);
SQLクエリの公式ドキュメントの日本語訳は下記にあります。