Laravelの気になるパッケージ「RestQL」

こんにちは❗フリーランス・エンジニアの 九保すこひ です。

さてさて、いつものごとく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: 従業員データ

つまり、companiesemployeeesは、「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, // 👈 追加
    ]
];

これでcompaniesemployeesパラメータを送信するだけで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で取得するcompaniesemployeesのテーブルにテストデータを作っていきます。

以下のコマンドを実行してください。

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をランダムに振り分けていることに注目してください。

では、CompaniesTableSeederEmployeesTableSeederを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は以下のような多階層のオブジェクトをAjaxGET送信する場合に必要なライブラリです。

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側でも少し説明しましたが、axiosGET送信は多階層のオブジェクトを送信する場合、qsライブラリなどでいったん文字列化する必要があります。

なお、この部分は何度も書くのはめんどうだと思いますので、Laravel Mixなどでapp.jsに固めておくと毎回書く必要がなくなって便利だと思います。

③RestQLでデータ取得

今回メインになるRestQLでデータ取得する部分です。
といっても、使い方は簡単でいつものSQL作成のようにオブジェクトを送信するだけでOKです。

さらに、employeesの中で設定しているとおりwithでリレーションシップ先のデータも取得できますし、wheresortも使えるようになっています。

詳しくはドキュメントをご覧ください。

テストしてみる

今回はデモページを用意しましたので、そちらで体験してみてください。

デモページ

上手く行っていると思います😊✨

ちなみに – その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の
ラジオ番組に出演させてもらいました。
楽しかったです😊✨」

今回の技術をつかった開発のご依頼、お待ちしております😊✨ お問い合わせ また、個人レッスンや、わかりにくい部分がありましたらからお気軽にご連絡ください。 どうぞよろしくお願いいたします!
このエントリーをはてなブックマークに追加       follow us in feedly