Laravel 5.5 + Vue 2.1でSPA的なものを作っている話
月2回更新を目標としながら丸1ヶ月ブログの更新をサボってしまいました…
気を取り直して更新を再開していきます…
最近、個人的にLaravelとVue.jsを組み合わせてSPA的なサイトを作っています。
LaravelもVue.jsも初めて扱うのでそこそこ苦労していますが、新しい技術を学ぶのはやっぱり楽しいものです。
以前、「Vagrant上にLaravelの開発環境を作る」という記事を書きましたが、これからしばらくはLaravelとVue.jsでサイトを作りながら気付いたことや学んだことを書いていこうと思います(たぶん他のことも書くけど)。
今日は手始めにLaravelのmodelのリレーションあたりについて書いてみようと思います。
modelの生成
まずはmodelを作るところからスタートです。
DBにあらかじめ以下のような2つのtableが用意されているとします。
銭湯の基本情報と銭湯の位置情報の2つのテーブルです。1件のレコードに対して1件のレコードが対応する最もシンプルなhasOneのパターンです。
sento_info←銭湯の基本情報
カラム名 | 型 | 長さ | データ例 | 備考 |
---|---|---|---|---|
sento_code | int | 7 | 1 | primaryKey |
name | varchar | 50 | テルマー湯 | |
address | varchar | 100 | 東京都新宿区歌舞伎町1-1-2 | |
tel | varchar | 15 | 03-5285-1726 |
sento_map←銭湯の位置情報
カラム名 | 型 | 長さ | データ例 | 備考 |
---|---|---|---|---|
sento_code | int | 7 | 1 | sento_info.sento_codeのforeignKey |
lat | double | 10,6 | 35.694535 | |
lng | double | 10,6 | 139.705160 |
これもLaravelのmigrateで作ればOKですが、長くなるので今回は割愛します。 モデルは職人さんが作ってくれます。
php artisan make:model SentoInfo
同様にSentoMapも作ります。
なお、デフォルトではappのすぐ下にmodelが生成されるのですが、以下のようにパスを追加してやるとちゃんとフォルダの下に入れてくれます。
php artisan make:model Models/SentoMap
modelの修正
次に生成したモデルをDBと紐付ける必要があります。
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class SentoInfo extends Model { protected $table = 'sento_info'; protected $primaryKey = 'sento_code'; }
鍵となるのは最後の2行です。
Laravelはデフォルトではテーブル名としてmodel名の複数形(この場合はsento_infos)、primaryKeyとしてidを指定してくれます。
今回のように別名を付けている場合は必ずこのように明示してやる必要があります。
SentoMap.phpの方も同じようにDBと紐付けておきます。
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class SentoMap extends Model { protected $table = 'sento_map'; protected $primaryKey = 'sento_code'; } }
リレーションを設定する
ようやく本題のリレーションの設定です。
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class SentoInfo extends Model { protected $table = 'sento_info'; protected $primaryKey = 'sento_code'; public function sentoMap() { return $this->hasOne('App\Models\SentoMap', 'sento_code'); } }
こんな感じ。hasOneの第1引数に紐付けるモデルのパス、第2引数にforeignKeyを設定します。
特にforeignKeyの方を忘れるとControllerから引っ張る時に正しいクエリを生成してくれなくてエラーになります。
Controllerから呼び出してみる
<?php use Illuminate\Http\Request; /* 中略 */ Route::group(['middleware' =>'api'], function() { Route::get('sento/{sento_code?}', 'SentoController@detail'); }) ;
今回はルーティングが本題ではないので詳しく書きませんが、/api/sento/2 とかを叩くとsento_code=2でAPIが返ってきます。
このAPIをVue側で取得してテンプレートに埋め込んで表示するわけですが、そのあたりはまた次回にでも書こうと思います。
次にSentoController.phpです。コントローラーも職人さんが生成してくれます。
php artisan make:controller SentoController
で、生成されたSentoController.phpにdetailメソッドを書き加えます。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\SentoInfo; class SentoController extends Controller { public function detail($sento_code) { $sento = SentoInfo::with('sentoMap')->find($sento_code); return $sento; } }
with('リレーション名')はeager loadingと呼ばれるもので、SentoInfoをロードする段階でSentoMapも先に取得してしまう処理を指しています。
このやり方をしないとsento_mapの列の数だけクエリが発行されることになるため無駄な負荷がかかってしまうようです。
今回は1対1のhasOneなのでこだわる必要性は薄いかもしれませんが、スピード面やクエリの発行回数で課金されるような状況を考えると、このやり方をしておいた方が良さそうです。
find(primaryKey)でそのprimaryKeyを持ったレコード1件を取得できます。
さて、 /api/sento/1を叩いてみると…
{ sento_code: 1, sento_name: "テルマー湯", address: "東京都新宿区歌舞伎町1-1-2", tel: "03-5285-1726", sento_map: { sento_code: 2, lat: 35.694535, lng: 139.705160 } }
こんな感じでjsonが返ってくれば成功です。
今日はとりあえずこんなところで。次回は返ってきたjsonをVue.jsの方で扱う記事でも書きたいと思います。
→次の記事はこちら