Exmentのプラグインでバッチ処理を作るには~エンジニアがソースコードを解説~
こんにちは。本日はExmentのバッチ処理プラグインの実装方法をご紹介したいと思います。(Exmentとはなにか知りたい方はこちらの記事をご覧ください)
私が以前、業務でExmentを利用することになった際、会員の年齢を自動で更新する処理を求められましたが、公式ドキュメントを読んだだけではあまり理解できませんでした。
そこでSQL記述方法などを調べなんとか実装までこぎつけたので、復習も兼ねて今回の記事を作成しました。
バッチの作成手順
ここから本題です。
今回は例として、私がExmentで作成した「会員情報(member_info)」テーブルから「生年月日(birthday)」を見て「年齢(age)」を更新する日次バッチの作成手順をお伝えします。
「XAMPP」と「Laravel」のインストール
ディレクトリの作成
設定ファイルの編集
プラグイン本体の編集
アップロード、設定
1.「XAMPP」と「Laravel」のインストール
実装には「XAMPP」に「Laravel」をインストールして実行できる環境が必要になります。
詳細は下記リンクを参照ください。
2.ディレクトリの作成
任意のディレクトリ(今回はTestBatch)を作成し、その中に「config.json」と「Plugin.php」のファイルを作成します。
TestBatch
└config.json
└Plugin.php
3.設定ファイルの編集
設定はconfig.jsonに記載、下記のようにします。
config.json
{
"uuid": "441effbb-a23d-93ca-140d-daaa160e6d48",
"plugin_name": "TestBatch",
"plugin_view_name": "テスト",
"description": "テストバッチです",
"author": "",
"version": "1.0.0",
"plugin_type": "batch",
"batch_hour": 0,
"batch_cron": ""
}
uuid:同一環境内での重複はNGです、uuidジェネレーターなどで発行してください。
plugin_type は batch にしてください。
上記以外は任意でOKです。
4.プラグイン本体の編集
つづいてPlugin.phpでプラグインの処理を記載します。
流れとしましては
ライブラリ読込み
try/catch定義
DBから条件に一致するデータの取得
取得したデータの編集、更新
となります。
Plugin.php
<?php
namespace App\Plugins\TestBatch; // ネームスペースは大文字開始でないとエラーになります
// ライブラリ読込み
use Carbon\Carbon;
use Exceedone\Exment\Model\CustomTable;
use Exceedone\Exment\Services\Plugin\PluginBatchBase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class Plugin extends PluginBatchBase
{
private const FUNCTION_NAME = '更新バッチ';
/**
* ボタンから呼ばれるメソッド
*/
public function execute()
{
try{
Log::info(self::FUNCTION_NAME.'を開始します'); // ログを出力`~\exment\storage\logs\laravel.log` に書かれます
DB::beginTransaction(); // トランザクションを開始
$exe_md = date('m-d'); // 現在月日を取得
$member_info = CustomTable::getEloquent('member_info'); // 会員情報
$queryMI = $member_info->getValueModel()->query(); // クエリビルダーの定義
$rsMI = $queryMI
->where('value->birthday', 'like', '%' . $exe_md) // 生年月日に現在年月を含んでいる
->whereNotNull('value->birthday') // かつ生年月日NotNull
->get(); // 条件一致にしたものを全件取得
if (!$rsMI->isEmpty()) { // ↑の条件でデータが取得できた場合のみ続きの処理を実行
foreach ($rsMI as $recMI) { // 取得結果を1件ずつ処理
$id = $recMI->id; // 更新対象のID(主キー)を取得
$birthday = $recMI->getValue('birthday');// 生年月日を取得
$age = Carbon::parse($birthday)->age; // Carbonライブラリを使って生年月日から現在の年齢を算出 ①
// 年齢更新
$value = CustomTable::getEloquent('member_info')->getValueModel($id); // IDで更新する対象を取得
$value->setValue('age', $age); // 年齢に①で算出した値をセット
$value->save(); // 結果を保存する
unset($id, $birthday, $age); // 初期化
}
}
DB::commit(); // コミット
Log::info(self::FUNCTION_NAME.'を終了します');
return true;
} catch (\Exception $e) {
DB::rollBack();
Log::error(self::FUNCTION_NAME.'が異常終了しました:'.$e);
return false;
}
}
}
上記コードから各処理を抜粋して説明します。
4.1.ライブラリ読込み
必要なライブラリを記述します。
Carbon
日付処理ライブラリExceedone\Exment
Exmentのライブラリ。テーブル操作とバッチ処理を行うIlluminate\Support\Facades
Laravelのライブラリ。DB操作とログの出力を行う
namespace App\Plugins\TestBatch; // ネームスペースは大文字開始でないとエラーになります
// ライブラリ読込み
use Carbon\Carbon;
use Exceedone\Exment\Model\CustomTable;
use Exceedone\Exment\Services\Plugin\PluginBatchBase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
4.2.try/catch定義
バッチ開始ログ出力後にトランザクション処理を開始します。
バッチが正常終了した場合は、DBをコミットし正常ログを、
異常終了した場合はDBをロールバックして異常ログを書き出します。
class Plugin extends PluginBatchBase
{
private const FUNCTION_NAME = '更新バッチ';
/**
* ボタンから呼ばれるメソッド
*/
public function execute()
{
try{
Log::info(self::FUNCTION_NAME.'を開始します'); // ログを出力`~\exment\storage\logs\laravel.log` に書かれます
DB::beginTransaction(); // トランザクションを開始
~~~
DB::commit(); // コミット
Log::info(self::FUNCTION_NAME.'を終了します');
return true;
} catch (\Exception $e) {
DB::rollBack();
Log::error(self::FUNCTION_NAME.'が異常終了しました:'.$e);
return false;
}
}
}
4.3.DBから条件に一致するデータの取得
$exe_md = date('m-d'); // 現在月日を取得
現在日を変数「$exe_md」に入れます。
$member_info = CustomTable::getEloquent('member_info'); // 会員情報
Exmentライブラリで物理テーブル名を指定し、変数「$member_info」に入れます。
$queryMI = $member_info->getValueModel()->query(); // クエリビルダーの定義
テーブル情報が入った「$member_info」に対してクエリを呼び出せるようにしてから「$queryMI」に入れます。
$rsMI = $queryMI
->where('value->birthday', 'like', '%' . $exe_md) // 生年月日に現在年月を含んでいる
->whereNotNull('value->birthday') // かつ生年月日NotNull
->get(); // 条件一致にしたものを全件取得
「$queryMI」に条件を付与し、get();の取得結果を「$rsMI」に入れます。
発行されるSQLとしては
SELECT * FROM member_info WHERE birthday like '%03-31' AND birthday IS NOT NULL;
のようなイメージです。
※Exmentは特殊なテーブル構造のため上記SQLをそのまま発行することはできません。
結果は配列で入ります。
4.4.取得したデータの編集、更新
if (!$rsMI->isEmpty()) { // ↑の条件でデータが取得できた場合のみ続きの処理を実行
~~~
}
「$rsMI」の取得結果が空じゃない(1件以上)場合に処理を継続します。
foreach ($rsMI as $recMI) { // 取得結果を1件ずつ処理
~~~
}
「$rsMI」の結果を1件ずつ「$recMI」に格納し、順に処理していきます。
$id = $recMI->id; // 更新対象のID(主キー)を取得
「$recMI」の中にある「id」(Exment側でデータを登録した際に自動で割り振られる連番の主キーです)を取得し「$id」に入れます。
$birthday = $recMI->getValue('birthday');// 生年月日を取得
「$recMI」の中にある「birthday」を取得し「$birthday」に入れます。
(ユーザーが作成したカラムは getValue('カラム物理名') で取得します)
$age = Carbon::parse($birthday)->age; // Carbonライブラリを使って生年月日から現在の年齢を算出
Carbon::parseで生年月日から現在の年齢を計算して「$age」に入れます。
// 年齢更新
$value = CustomTable::getEloquent('member_info')->getValueModel($id); // IDで更新する対象を取得
member_infoテーブルから「$id」に一致するデータを取得し「$value」に入れます。
$value->setValue('age', $age); // 年齢に①で算出した値をセット
「$value」にある「age」を更新した「$age」に置き換えます。
「$value->setValue(物理カラム名, 更新後の値); 」なのでバッチの目的に合わせてカラム名を変更してください。
$value->save(); // 結果を保存する
置き換えた結果を保存します。
unset($id, $birthday, $age); // 初期化
利用した変数を初期化します。
5.アップロード、設定
TestBatchをzip化し、Exmentのプラグインの画面からアップロードします。
アップロードされたら一覧から選択し、詳細画面に遷移します。
「有効フラグ」を「ON」に設定し、自動起動したい時間帯を設定、保存で完了です。
この画像の設定の場合、毎日AM1:00に起動します。
バッチを実行してみる
ここからは作成したバッチを実行して更新内容を確認してみましょう。
会員情報テーブル(member_info)の構成と実行前のデータです。
今回はすぐ動かしたいので手動で実行しています。
※②の紫のボタンを押下で手動実行となります。 実行日「2023-03-31」
デバッグ実行で止めて変数の中身を確認します。
実行日は「2023-03-31」ですので条件に一致する2件を取得しています。
($rsMI items:array(2))1件目の中身は下記のようになっています。
$valueは更新用の値です。
「年齢」が変更されています。この値で保存します。
実行後のテーブルです。
条件に一致した2件の年齢が更新されています。
おわりに
以上がExmentでのプラグイン実装方法となります。
Laravelでのクエリの書き方がやや特殊なので慣れが必要です。
今回はバッチでしたが、プラグインでは入力画面も作成でき、より便利に使えると思いますのでその足がかりになれば幸いです。
おすすめ記事
データ管理ができる「Exment」って何がいいの?
企業SNSの炎上を最小限に抑える3つのコツ!
KARTEのABテストの実現方法に悩んでいる方に向けて
UIデザイナーとの連携をスムーズにする、3つの工夫
エンジニアとUXディレクターが感じるもやもやは、何故うまれるのか
月1回の振り返りを若手と先輩で3年間続けた結果・・・