昨日の「PowerCMSのブログに登録したデータをAlgoliaで検索する」続きです。プロジェクトがPowerCMS 5なので頭の中ではPowerCMS 5が前提の話だったのですが、PowerCMS Xだと割と楽にAlgoliaと連携するプラグインが書けるのではないかと思い試してみました。
広島県オープンデータライブラリにある学校のデータがPowerCMS Xのschoolモデルに登録してありますのでそれを利用します。具体的にはschoolモデルの情報をAlgoliaのschoolインデックスに登録し、返値にあるobjectIDをschoolモデルの各オブジェクトに保存します。下記を参照して開発を進めました。
- Save Objects | Indexing | Method | API Reference | Algolia Documentation
- PHPによるプログラミング・ガイド (データベース編) | PowerCMS X
実装結果
まだ汎用的なプラグインではなく、設定画面もないし.env
を使っているなどするのですが、1時間30分ぐらいで作成できました。
schoolモデルのデータがAlgoliaのインデックスに100件登録されました。今津小学校のobjectIDは3066891002
です。
PowerCMS Xのオブジェクトのカラムに先程確認したobjectID 3066891002
が保存されています。
サンプルコード
モデルにオブジェクトを保存したときに1件ずつAlgoliaに登録する、タスクでまとめてAlgoliaに登録する、などが考えられますが、ひとまずタスクバージョンを作りました。SearchEstraierプラグインが参考になります。今回は使うのを忘れましたが「PluginStarterプラグイン」もあります。
config.json
{
"label" : "AlgoliaSupport",
"id" : "algoliasupport",
"component" : "AlgoliaSupport",
"version" : "0.1",
"author" : "Hideki Abe",
"author_link" : "https://www.anothersky.pw/",
"description" : "",
"tasks": {
"alogolia_save_objects": {
"label" : "Save objects into Algolia index.",
"component" : "AlgoliaSupport",
"priority" : 100,
"method" : "save_multiple_objects",
"frequency" : 1
}
}
}
AlgoliaSupport.php
1件ずつsave()
したら負荷がかかるかも?と思ったのですが、update_multi()
が便利でした。saveObjects()
の返値の説明に「List of objectIDs of the saved objects in order.」とあるのでfor
で回せば大丈夫なはずです(一応何件かのオブジェクトを無作為に開いて確認しました)。
<?php
require_once LIB_DIR . 'Prototype' . DS . 'class.PTPlugin.php';
require_once 'vendor/autoload.php';
class AlgoliaSupport extends PTPlugin {
function __construct() {
parent::__construct();
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
}
function save_multiple_objects($app) {
$result = false;
$model = 'school';
$app->get_scheme_from_db($model);
$db = $app->db;
$db->update_multi = true;
$records = [];
// API Clientの準備
$client = Algolia\AlgoliaSearch\SearchClient::create(
$_ENV['APP_ID'],
$_ENV['ADMIN_API_KEY']
);
$index = $client->initIndex($_ENV['INDEX_NAME']);
// モデルのオブジェクトを取得してインデックス登録
$args = [
'limit' => 100, // NOTE: とりあえず100件
];
$objects = $db->model($model)->load([], $args);
foreach ($objects as $object) {
$records[] = [
'id' => (int) $object->id,
'name' => $object->name,
'address' => $object->address,
'tel' => $object->tel,
];
}
if (empty($records)) {
return $result;
}
$algolia_result = $index->saveObjects(
$records,
[
'autoGenerateObjectIDIfNotExist' => true,
]
);
// objectIDをモデルに登録
if (
isset($algolia_result[0]) &&
isset($algolia_result[0]['objectIDs'])
) {
$objectIDs = $algolia_result[0]['objectIDs'];
$n_records = count($records);
for ($i = 0; $i < $n_records; $i += 1) {
$objects[$i]->algolia_object_id = $objectIDs[$i];
}
$result = $db->model($model)->update_multi($objects);
}
return $result;
}
}