さて、この回から実際の開発に入っていくのだが、まずはローカルPCなどに開発環境を準備する必要がある。開発環境用のサーバを利用しても良いのだが、今回はVue.jsを利用するために、都度ソースのトランスパイル・ビルドが発生することになる。このビルドはPC側に結構なパフォーマンスを求めるので、比較的搭載メモリが多いローカルPCの方がビルド時間の短縮になり、開発効率が上がる。
 各社クラウドプラットフォームの無料枠等で準備した最小構成のサーバ・インスタンス等の場合、トランスパイルするソース量にもよるが、ビルドに1分以上かかることもある。その場合、軽微なソース修正のたびに待ち時間が発生してしまい、効率がかなり悪いのだ。ある程度のメモリ(8GB以上は欲しいかも)が搭載されたPCであれば、アプリケーション開発用のマシンとして、ストレスなく稼働してくれるはずだ。
 ちなみに、私の開発環境および公開環境は下記のようになっている。

デスクトップ(メインPC) ラップトップ(サブPC) 公開環境
OS Windows 10 macOS Catalina Cent OS 7
CPU 4コア(Core i7) 3.40GHz 4コア(Core i5) 2.3GHz 共用(最大28コア)
メモリ 20GB 8GB 共用(最大384GB)
仮想環境 XAMPP 8.0.3 MANP
PHP 8.0.3 8.0.0 8.0.0
MySQL 5.7.33/8.0.23(スイッチ可能) 5.7.32 5.7.32
Apache 2.4.46(XAMPPバンドル版) 2.4.46 2.4.46
Node.js 12.16.3 12.6.0 14.15.5
npm 6.14.4 6.14.5 6.14.11
yarn 1.17.3 1.17.3 1.22.10
git 2.31.1.windows.1 2.21.0 1.8.3.1
Composer 2.0.12 2.0.12 2.0.12

 ※ XAMPPはバージョン8以降で、MANPなら最新の6.3で、PHP 8が使用できる。
 ※ XAMPPにバンドルされているデータベースはMySQL互換の「MariaDB」となる。MariaDBでもJSON型は取り扱えるが、内部的にBlob型のバイナリデータとして扱われるため、応答値がエスケープされていたりして、カラムに投入されたJSONデータの正当性を担保できないケースが生じる。正しいJSONデータのやり取りを担保するには、MySQL 5.7以降のバージョンを使うのが望ましい。XAMPP環境下でMySQL 5.7を利用する方法は、下記の記事を参考にして欲しい。

XAMPP環境で MySQL 5.7 を動かす

 ちなみに、私の主力機のデスクトップは10年前(2011年)に発売された「DELL XPS8300」で、だいぶ年季の入った機体なんだが、メモリ増強してストレージをSSDに換装してあるので、全くストレスを感じることなく稼働している。

プロジェクトを作る

 では、今回の開発用にローカルPCの仮想環境下にプロジェクト用のディレクトリを作成する。今回はフロントエンドをVue.jsで開発するので、Vueプロジェクトのアプリケーションとして始動させることにする。まずVue.jsのコマンドラインツールをインストールする。

yarn global add @vue/cli

──そして、vueコマンドからプロジェクトを作成する。

vue create mhr-simulator

 すると、プロジェクトのVue環境を聞かれるので、Default ([Vue 2] babel, eslint)を選ぶ。今回はフロントエンドにVuetifyを使うので、Vueのバージョンは2にしておく必要があるのだ。

Vue CLI v4.5.12
? Please pick a preset: (Use arrow keys)
> Default ([Vue 2] babel, eslint)
  Default (Vue 3 Preview) ([Vue 3] babel, eslint)
  Manually select features   

 少し待てば、基本ファイルセットが含まれたプロジェクト用のディレクトリmhr-simulatorが生成される。なお、この段階では、これ以上Vue.js側に手を加えない。
 次に、このプロジェクト用ディレクトリ内にPHPの環境を追加していく。ディレクトリ内に移動して、Composerインストール用にJSONファイルを作る。

cd mhr-simulator
touch composer.json

 出来上がった空ファイルのcomposer.jsonに、PHPクラスのオートローダをインストールするように設定を追加する。

{
    "autoload": {
        "psr-4": {
            "MHRise\\SkillSimulator\\": "apps/"
        }
    }
}

 あとは、下記のコマンドでオートローダをインストールするだけだ。もしComposer本体をインストールしていないならば、そちらを先にやる必要がある。Composer自体のインストール方法はいたるところで紹介されているので、ここでは省略する。

composer install

 vendorディレクトリが作成されて、その中にオートローダスクリプトがインストールされているはずだ。これでPHP側の準備も完了だ。

アプリケーションのエンドポイントを決める

 今回のアプリケーションに対するユーザー導線を考えてみると、3つの経路が想定される。

END POINT

 エンドポイントとは、ユーザーが直接アクセスするアプリケーションの出入口のことだ。WEBサイトで云えば、エントリーページとなるindex.htmlhome.html等がエンドポイントと云えるだろう。今回のアプリケーションでは、アプリケーションの利用者となるエンドユーザ用のエンドポイントとしてindex.phpを準備し、データ管理者用にadmin.phpを、一括データ投入用にbulk.phpをそれぞれ設置する。admin.phpbulk.phpはいわゆる管理画面的な位置づけになり、エンドユーザからのアクセスを許可しない制限されたエンドポイントとなる想定だ。なお、bulk.phpについては、特にGUIを準備する必要性が乏しいので、コマンドラインから直接データを一括投入できるようなもので事足りると考えている。

コアクラスの製造

 エンドポイントが決まったら、まずはバルクユーザ向けの経路を作って行くことにする。この経路が動くようになれば、データベースに初期データを投入するのが楽になり、その後の開発がしやすくなるからだ。
 そのために真っ先にやらなければならないのが、PHPでデータベースと接続して、PHPからデータベースを操作できるようにすることだ。そこで、アプリケーションの中核として、コアクラスを作り、そのメソッドとしてデータベースハンドラを準備する。

抽象クラスを使う

 アプリケ―ションのコアクラスを作る前に、前段として抽象クラス(Abstract Class)を準備する。抽象クラスとはそれを継承するクラスのひな形となるスキーマ的なクラスで、同様の機能を持っているインターフェースよりも縛りが緩いものだ、という解釈で大まかにはイイと思う。もっと詳しく云うと、抽象クラスやインターフェースで宣言されたメソッドは、継承先のクラスで実装が強制される。さらに抽象クラスでは、通常のメソッドも定義できるため、アプリケーション全体で共通的に使用するような処理をあらかじめ定義しておくことができる。一方で、インターフェースはメソッドの定義はできないが、複数のインターフェースを継承させる「多重継承」ができる。
 アプリケーションの建付け的に、エンドポイントごとにファイナルクラスを準備する予定なので、それらで共通利用するデータベースハンドラについては抽象クラスに定義しておいた方が効率的なのである。他に、データベースハンドラ系の処理はトレイトにしてしまい、各クラスでそのトレイトをuseするという手段もある。今回のアプリケーションの場合、抽象クラスを継承した方が、コードの見通しが良いだろうという判断だ。

 前述のPHPクラスのオートローダ設定にて、PHPのクラスはappsディレクトリから読み込まれるようになっているので、appsディレクトリを作り、抽象クラスとバルクユーザ用のコアクラスのファイルを作成しよう。

mkdir apps
cd apps
touch abstractClass.php bulkCore.php

 とりあえず、実践あるのみだ。抽象クラスとコアクラスを使ったDB接続の試験をしてみよう。最初に抽象クラス側を下記のようにする。

abstractClass.php:

<?php
namespace MHRise\SkillSimulator;

if ( !class_exists( 'abstractClass' ) ) :

abstract class abstractClass {
    protected string $cmd;

    public function __construct(
        private string $dbname,
        private string $dbuser,
        private string $dbpass,
        private int    $dbport = 3306,
    ) {
        $this->cmd = sprintf( 'mysql -u %s -p%s -P %d -D %s', $this->dbuser, $this->dbpass, $this->dbport, $this->dbname );
    }

    abstract public function execute( string $query );
}

endif;

 ちょっとだけ解説しておこう。コンストラクタの部分は、PHP 8で導入されたプロパティ・プロモーションで書いているので、PHP7以前のバージョンではエラーになる。抽象クラスでは、コンストラクタとしてデータベースの接続情報(DSN: Data Source Name)を引数で受けてクラスのプロパティに展開している。抽象メソッドとして、データベースクエリを実行するためのexecute()が宣言されているので、継承先のクラスではこのメソッドの定義が強制される。

抽象クラスを継承するコアクラス

 次に、抽象メソッドを継承するコアクラス側のサンプルをコーディングする。

bulkCore.php:

<?php
namespace MHRise\SkillSimulator;

if ( !class_exists( 'bulkCore' ) ) :

class bulkCore extends abstractClass {
    public function execute( string $query ) {
        $fixed_cmd = $this->cmd . sprintf( ' -t -e "%s"', $query );
        system( $fixed_cmd );
    }
}

endif;

 コアクラスでは、抽象クラスで強制された抽象メソッドexecute()を必ず定義しなければならない。その際、アクセス修飾子(publicprotectedprivate)や、引数の数と型も抽象クラス側で定義されたものと一致させる必要がある。
 このサンプルコードでは、文字列としてSQLクエリを受け取って、コマンドラインからSQLクエリを実行するためのコマンドを生成し実行する流れだ。あくまで動作テスト用のサンプル処理なので、値の検証や例外処理等は入れていない。

エンドポイント用ファイルの作成と実行

 そして最後に、エンドポイント用のファイルを準備する。

cd ..
touch bulk.php

 エンドポイントのファイルでは、コアクラスをインスタンス化して、必要なメソッドを実行することになる。

bulk.php:

<?php
require_once( __DIR__ . '/vendor/autoload.php' );

use MHRise\SkillSimulator\bulkCore;

if ( class_exists( 'MHRise\SkillSimulator\bulkCore' ) ) {
    $instance = new bulkCore( 'mhr_simulator_db', 'username', 'password', 3306 );
    $instance->execute( 'show tables' );
} else {
    exit;
}

 クラスをインスタンス化する際に、受け渡すデータベースに接続するためのユーザ名やパスワード、ポート番号等は稼働する環境に準じて変更する必要がある。この例では、接続したデータベースに存在するテーブルの一覧を表示するためのクエリshow tablesを実行する想定だ。
 では、実際にエンドポイントのPHPファイルをコマンドラインから実行してみよう。

> php bulk.php
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------------------+
| Tables_in_mhr_simulator_db |
+----------------------------+
| armors                     |
| decorations                |
| talismans                  |
| weapons                    |
+----------------------------+

 無事に今回のアプリケーション用に作ったデータベースのテーブル一覧が表示された。なお、MySQLが警告を出しているのは、PHPが内部で実行しているコマンドライン上のmysqlコマンドにパスワードが直接引数で渡されているからだ。

 この一連の処理の流れが、今回のアプリケーションのバックエンドの基本となる。どのエンドポイントを辿って来ても基本的に同じようなクラス連携を経て、データベースとのやり取りが行われるのだ。
 ということで、今回はここまで。

 次回は、バルクユーザ用のエンドポイントbulk.phpを仕上げる。