はじめに
お仕事で、Zend Frameworkのバージョンアップをしなければならなくなった・・と思ったら、Zend Frameworkはもうなくて、Laminas Projectに移って新たなフレームワークとして公開されている。 しかし、Laminas MVCでは必要な要件を満たさないことが分かってとん挫していた。
そこで、次の候補としてLaravelを挙げて、必要な要件を満たせるかどうかを一歩ずつ調査していく。
要件(6)
6つ目の要件は、「DBのテーブルに対してJOINクエリが発行できること」。
Zend Frameworkでは、クエリビルダーがあったので、それでJOINクエリを書いていたが、Laravelではどうなっているのかを調査していく。
導入
こちらでセットアップした環境を(コピーして)使っていく。
私は以下のようにコピーを作成。
cp -pr laravel-setup-5-multiple-databases laravel-setup-6-join-queries cd laravel-setup-6-join-queries
DBへの追加
今回、テナントDBの方がメインになるので、テナントDBの方でJOINクエリを試していく。 以下のようにテナントDBに新たにテーブルを追加する。
\c tenant_0001 tenant_0001_user CREATE TABLE messages( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, title VARCHAR(128) NOT NULL, content TEXT NOT NULL); INSERT INTO messages(user_id, title, content) VALUES(1, 'テナント1ー1さんへのメッセージ1', 'メッセージ1の内容'); INSERT INTO messages(user_id, title, content) VALUES(2, 'テナント1ー2さんへのメッセージ1', 'メッセージ1の内容'); INSERT INTO user_master(user_name, real_name) VALUES('tenant0002', 'テナント1 次郎');
\c tenant_0002 tenant_0002_user CREATE TABLE messages( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, title VARCHAR(128) NOT NULL, content TEXT NOT NULL); INSERT INTO messages(user_id, title, content) VALUES(1, 'テナント2ー1さんへのメッセージ1', 'メッセージ1の内容'); INSERT INTO messages(user_id, title, content) VALUES(2, 'テナント2ー2さんへのメッセージ1', 'メッセージ1の内容'); INSERT INTO user_master(user_name, real_name) VALUES('tenant0001', 'テナント2 太郎');
想定するクエリ
先に追加したテーブルを使って、「実名に"太郎"を含むユーザーのメッセージ一覧」を取得するクエリを書いてみる。 SQL文で書くと以下のような感じになる。
SELECT m.id, m.user_id, m.title, m.content FROM messages m JOIN user_master u ON m.user_id = u.id WHERE u.real_name LIKE '%太郎%' ORDER BY m.id LIMIT 10 OFFSET 0
設定・実装
ここでは、DBファサードを使って問い合わせを行なう場合を想定する。
まず、app/Http/Controllers/TenantController.phpを以下のように編集する。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; class TenantController extends Controller { public function tenant(Request $request) { $tenantCode = $request->get('tenant_code'); $result = DB::table('db_master_2')->where('tenant_code', $tenantCode)->first(); return view('tenant.tenant', ['db_name' => $result->db_name]); } public function users(Request $request) { $tenantCode = $request->get('tenant_code'); $result = DB::connection('tenant-' . $tenantCode)->table('user_master')->get(); return view('tenant.users', ['users' => $result]); } public function messages(Request $request) { $tenantCode = $request->get('tenant_code'); $allResult = DB::connection('tenant-' . $tenantCode)->table('messages')->get(); $userResult = DB::connection('tenant-' . $tenantCode) ->table('user_master')->join('messages', 'user_master.id', '=', 'messages.user_id') ->whereLike('real_name', '%太郎%')->get(); return view('tenant.messages', [ 'all_messages' => $allResult, 'user_messages' => $userResult, ]); } }
次に、ビューテンプレート。ファイルパスはresources/views/tenant/messages.tpl。
全メッセージ <ul> {foreach from=$all_messages item='message'} <li>{$message->id|escape:"html"}:{$message->user_id|escape:"html"}({$message->title|escape:"html"})</li> {/foreach} </ul> ユーザーメッセージ <ul> {foreach from=$user_messages item='message'} <li>{$message->id|escape:"html"}:{$message->user_id|escape:"html"}({$message->title|escape:"html"})</li> {/foreach} </ul>
最後に、routes/web.phpに以下の行を追記する。
Route::get('/tenant/messages', [\App\Http\Controllers\TenantController::class, 'messages']);
動作確認
以下のURLにアクセスして、ページが表示されるかを確認する。
http://<your-ip-address>/laravel-setup-6-join-queries/public/tenant/messages?tenant_code=0001
以下のようなテキストが画面に表示されればOK。
全メッセージ ・1:1(テナント1ー1さんへのメッセージ1) ・2:2(テナント1ー2さんへのメッセージ1) ユーザーメッセージ ・1:1(テナント1ー1さんへのメッセージ1)
まとめ
- DBファサードの機能が充実しているので、たいていのクエリは書けそう
- WHERE条件も、述語メソッドが一通り用意されており、困ることはなさそう