
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、いつものごとくLaravel Newsで情報収集をしていたところ、以下の記事を発見しました。
■Laravel Newsの記事
RestQL Data Resolution Package for Laravel
これは、RestQL
という新しいパッケージを紹介している記事なんですが、なかなか気になる内容だったのでこのブログでも紹介することにしました。
なぜ気になったかというと・・・・
Ajaxで一気にDBからデータ取得できる
からです。
この機能は「Laravel + Vue + GraphQLでデータ取得」という記事で紹介したGraphQL
にインスパイアされた機能で、よりシンプルに実装することができます。
そこで
今回は「Laravelの気になるパッケージ」としてRestQLをご紹介したいと思います。
作者のGregori Piñeres
さんありがとうございます!
「JSONを元にしてデータ取得できます」
サポートしてるバージョン: Laravel 5.8以上
目次 [非表示]
この記事を見たらできること
Ajax
でDBからデータ取得し、さらにそのデータでリスト表示や絞り込みができるようになります。
そして、今回実際に使うDBテーブルは以下の2つです。
- companies: 会社データ
- employees: 従業員データ
つまり、companies
とemployeees
は、「1:多」の関係になります。(実は、RestQL
はリレーションシップにも対応してます)
では実際にやっていきましょう
パッケージをインストールする
まずはじめにRestQLをインストールします。
以下のコマンドを実行してください。
composer require gregorip02/restql
インストールしたら、以下のコマンドで設定ファイルをLaravel
側へコピーします。
php artisan vendor:publish --tag=restql-config
では、コピーしたファイルを開いて今回利用するモデルをセットしておきましょう。
config/restql.php
<?php
return [
// 省略
'allowed_models' => [
'companies' => \App\Company::class, //
追加
'employees' => \App\Employee::class, //
追加
]
];
これでcompanies
とemployees
パラメータを送信するだけでDB
からデータ取得できるようになります。(もちろん、他のテーブルもいくつでも追加できます)
ルートを設定する
routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Restql\Restql;
use Illuminate\Database\Eloquent\Builder;
// 省略
Route::get('restql', function(Request $request){
return Restql::resolve($request)->get(function(Builder $builder){
return $builder->get(); // ここは、paginate()やpluck()でもOK!
});
});
ご注意:
web.php
ではありません。そして、URL
は「http://*****/api/restql」になります。
モデル&マイグレーションをつくる
では、今回使うモデルとマイグレーション「Company」「Employee」を作っていきます。
php artisan make:model Company -m
これでモデルとマイグレーションが同時に作成されたので、マイグレーションの中身を次のように変更します。
/database/migrations/****_**_**_******_create_companies_table.php
// 省略
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('会社名'); //
追加
$table->timestamps();
});
}
// 省略
同じく、Employee
モデル&マイグレーションです。
php artisan make:model Employee -m
今回はEmployee
モデルからリレーションシップを使うので、Employee.php
に以下のコードを追加します。
/app/Employee.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Employee extends Model
{
// リレーションシップ
public function company(): BelongsTo {
return $this->belongsTo(\App\Company::class, 'company_id', 'id');
}
}
※ここで重要なのが、返り値の種類をセットしている部分です。これはPHP 7
から使えるようになった機能ですが、RestQL 1.4からはこの形式で設定をしないとエラーになります。
そして、マイグレーションです。
/database/migrations/****_**_**_******_create_employees_table.php
// 省略
public function up()
{
Schema::create('employees', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('company_id')->comment('会社ID');
$table->string('name')->comment('従業員名');
$table->timestamps();
$table->foreign('company_id')->references('id')->on('companies');
});
}
// 省略
では、この状態でマイグレーションを実行してください。
php artisan migrate
実際のテーブルはこうなります。
テストデータをつくる
次に、RestQL
で取得するcompanies
とemployees
のテーブルにテストデータを作っていきます。
以下のコマンドを実行してください。
php artisan make:seed CompaniesTableSeeder
そして、作成されたファイルを開いて中身を次のように変更します。
/database/seeds/CompaniesTableSeeder.php
// 省略
public function run()
{
for($i = 1 ; $i <= 10 ; $i++) { //
追加
$company = new \App\Company();
$company->name = 'テスト会社名 - '. $i;
$company->save();
}
}
// 省略
同じく、employees
用のテストデータです。
php artisan make:seed EmployeesTableSeeder
中身は次のようになります。
/database/seeds/EmployeesTableSeeder.php
// 省略
public function run()
{
//
追加
$company_ids = \App\Company::pluck('id');
for($i = 1 ; $i <= 100 ; $i++) {
$employee = new \App\Employee();
$employee->company_id = $company_ids->random();
$employee->name = 'テスト従業員 - '. $i;
$employee->save();
}
}
// 省略
この中では、会社IDをランダムに振り分けていることに注目してください。
では、CompaniesTableSeeder
とEmployeesTableSeeder
をLaravelに登録します。
/database/seeds/DatabaseSeeder.php
// 省略
public function run()
{
// $this->call(UsersTableSeeder::class);
$this->call(CompaniesTableSeeder::class); //
追加
$this->call(EmployeesTableSeeder::class); //
追加
}
// 省略
では、テストデータ付きでマイグレーションを初期化してみましょう。
php artisan migrate:fresh --seed
テーブルはこうなりました。
リスト表示&絞り込み機能をつくる
では、ここからが実際にRestQL
を使う方法になります
ルートをつくる
まず実際にブラウザでアクセスするURLをつくります。
Route::get('company_employee', function(){
return view('company_employee');
});
※「http://*****/company_employee」にアクセスできるようになります。
ビューをつくる
続いて、ビューです。
ビューは少しコードが長いのでHTMLとJavaScript部分に分けて紹介します。
HTML部分
<html>
<head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app" class="p-3">
<h1 class="mb-3">RestQLでデータ取得して、リスト表示&絞り込み</h1>
<div class="row">
<div class="col-md-4">
<label>会社で絞り込み:</label>
<select class="form-control" v-model="selectedCompanyId">
<option value=""></option>
<!-- RestQLで取得した会社データで選択肢をつくる ・・・ ① -->
<option
:value="c.id"
v-for="c in companies"
v-text="c.name"></option>
</select>
</div>
</div>
<table class="table table-bordered mt-4">
<thead class="bg-info text-white">
<tr>
<th>従業員</th>
<th>会社</th>
</tr>
</thead>
<tbody>
<!-- 会社IDで絞り込んだデータをリスト表示 ・・・ ② -->
<tr v-for="e in filteredEmployees">
<td v-text="e.name"></td>
<td v-text="e.company.name"></td>
</tr>
</tbody>
</table>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
<!-- 多階層のパラメータに対応させるライブラリ ・・・ ③ -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.9.3/qs.min.js"></script>
<script>
new Vue({
// ここにVueコード
});
</script>
</body>
</html>
この中でやっているのは次のとおりです。
①RestQLで取得した会社データで選択肢をつくる
RestQL
で取得することになる会社データ(companies)でセレクトボックスを作ります。このセレクトボックスはVue
と連携して「変更したら自動で該当するデータだけ表示する」機能をもたせます。
②会社IDで絞り込んだデータをリスト表示
上のセレクトボックスと連動して、該当するデータをリスト表示します。
③多階層のパラメータに対応させるライブラリ
qs
は以下のような多階層のオブジェクトをAjax
でGET送信
する場合に必要なライブラリです。
parent: {
child: {
grandChild: {
key: 'value'
}
}
}
JavaScript部分
続いてJavaScript部分です。
new Vue({
el: '#app',
data: {
companies: [],
employees: [],
selectedCompanyId: ''
},
computed: {
filteredEmployees() { // 会社IDで絞り込みをした従業員データ ・・・ ①
let employees = [];
this.employees.forEach(employee => {
if(!this.selectedCompanyId) {
employees.push(employee); // 会社が選択されていない場合
} else if(this.selectedCompanyId > 0 && parseInt(employee.company_id) === parseInt(this.selectedCompanyId)) {
employees.push(employee); // 選択された会社IDが一致する時
}
});
return employees;
}
},
mounted() {
// GETパラメータを多階層に対応させる ・・・ ②
axios.interceptors.request.use(config => {
config.paramsSerializer = params => {
return Qs.stringify(params, {
arrayFormat: 'brackets',
encode: false
});
};
return config;
});
// RestQLでデータ取得 ・・・ ③
axios.get('/api/restql', {
params: {
companies: {
select: 'name' // 会社名だけ
},
employees: {
select: ['name', 'company_id'], // 従業員名、会社ID
with: { // リレーションシップ
company: {
select: 'name'
}
}
}
}
}).then(response => {
this.companies = response.data.companies;
this.employees = response.data.employees;
});
}
});
①会社IDで絞り込みをした従業員データ
「セレクトボックスで選択された会社」に該当する従業員データをfilteredEmployees
という変数として使えるようにしています。
なお、会社が選択されていない場合は全データを返します。
②GETパラメータを多階層に対応させる
HTML側でも少し説明しましたが、axios
のGET送信
は多階層のオブジェクトを送信する場合、qs
ライブラリなどでいったん文字列化する必要があります。
なお、この部分は何度も書くのはめんどうだと思いますので、Laravel Mix
などでapp.js
に固めておくと毎回書く必要がなくなって便利だと思います。
③RestQLでデータ取得
今回メインになるRestQL
でデータ取得する部分です。
といっても、使い方は簡単でいつものSQL作成のようにオブジェクトを送信するだけでOKです。
さらに、employees
の中で設定しているとおりwithでリレーションシップ先のデータも取得できますし、where
やsort
も使えるようになっています。
詳しくはドキュメントをご覧ください。
テストしてみる
今回はデモページを用意しましたので、そちらで体験してみてください。
上手く行っていると思います
ちなみに – その1
RestQL
パッケージのライセンスは(2020.5.2時点で)GPL 3.0
となっています。そのため、このパッケージを同梱したアプリケーションを配布、販売する場合は注意が必要です。
ちなみに – その2
GitHub
では基本的な使い方として以下の書き方が紹介されていますが、この場合、自動で取得する件数が決められてしまいますので注意が必要です。
そのため、記事中で紹介した->get(function(){ ... })
をつけるようにすることをおすすめします。
Route::get('restql', function(Request $request){
return Restql::resolve($request); // 件数が自動で設定されてしまう
});
おわりに
ということで、今回は気になるパッケージとしてRestQL
をご紹介しました。
実はですが、この記事は初めてLaravel News
で記事を読んでから結構時間が経っています。
というのも(忙しかったのも言い訳としてありますが)当初、ちなみに – その2で書いた内容に気がつかず、再度チェックした際に「うっ、マジか・・・
」となった経緯があったからです。
紹介記事が公開されてから1ヵ月ほど経っていますが、今でも頻繁にパッケージがアップデートされているようなので、今後にも期待しています。
ぜひ皆さんも、RestQL
の便利さを体験してみてくださいね。
ではでは〜
「友人の招待でSpoonの
ラジオ番組に出演させてもらいました。
楽しかったです」