PowerCMS X ブログ

2024-06-07

モデル設計の考え方とポイント

基本的な考え方

PowerCMS X を導入する際に行うべきことの1つに、CMSで管理するデータベースの定義となるモデルの作成があります。「記事」や「ページ」「カテゴリ」などのモデルは標準で定義されておりインストール時に作成されますが、その他のコンテンツを扱う際には独自に定義する必要があります。
モデル定義は、CMS管理画面上からRDB(リレーショナルデータベース)のテーブル定義をする。と言い換えることができ、基本的にはテーブル定義の設計と同じ考え方で進めていくことになります。
今回は、PowerCMS X のモデル設計をRDBのテーブル設計の進め方から説明したいと思います。(以降、適宜テーブルをモデルと読み替えてください。)
例として自社で扱っている商品をCMSで管理する際のテーブル定義を検討していきます。

論理設計

テーブル設計をする際、はじめに論理設計を行いますが、まずはCMSで管理するデータ要素(エンティティまたはカラム)を書き出していきます。ここでは便宜的に簡略化し商品情報として以下の要素を扱います。

  • 商品名
  • 商品写真
  • 商品説明
  • カテゴリ
  • サイズ
  • 在庫数

要素を書き出したら、要素のまとまりごとにデータの集合を定義します。データの集合を定義する際には「データの正規化」や「マスタとトランザクション」を考える必要があります。

データの正規化

RDB設計を行う際の正規化とは、一言で言うとデータを集合として管理する上で冗長なデータ集合をなくすことです。
仮に今回扱う要素を全て1つの集合で管理するとデータは以下のようになります。同じデータが重複して管理されているため、例えば商品説明を更新する場合、全てのデータを更新する必要があります。

商品情報テーブル
商品名 商品写真 商品説明 カテゴリ サイズ 在庫数
商品A 写真A 商品説明A カテゴリA S 10
商品A 写真A 商品説明A カテゴリA M 5
商品A 写真A 商品説明A カテゴリA S 15
商品A 写真A 商品説明A カテゴリA M 2

これを正規化するとデータの集合は商品IDをキーに以下の2つに分かれます。

商品情報テーブル
商品ID 商品名 商品写真 商品説明 カテゴリ
1 商品A 写真A 商品説明A カテゴリA
在庫情報テーブル
商品ID サイズ 在庫数
1 S 10
1 M 5
1 S 15
1 M 2

マスタとトランザクション

もう1つ、マスタとトランザクションを区別してデータ分けるという考え方があります。
マスタデータとは、データの特性上あまり変更されることのないデータに対し、トランザクションデータはマスタデータに比べ更新頻度の高いデータとなります。
上記の例では、商品情報はマスタデータ、在庫情報はトランザクションデータとなります。カテゴリも、正規化もしくはマスタとしてテーブルを分けるという考え方もできます。

以上のプロセスを経て、結果2つのデータ集合ができました。これは管理画面でデータを編集する画面の単位とほぼイコールになり、このまとまり(集合)がそれぞれテーブルとなります。ここまでが論理設計になります。

  • 商品情報
  • 在庫情報

物理設計

次に各テーブルに定義された要素について、物理設計をしていきます。物理設計では実際にRDB上にテーブルを作る際に必要な以下の定義をしていきます。

各要素の型を定義する

各要素をテーブル上どのようなデータ形式で管理するか定義します。商品名や商品説明はテキスト型、在庫数は数値型、商品画像についてはPowerCMS X ではバイナリ型としてファイルではなく直接DBで管理します。

モデル編集画面のキャプチャ

インデックスを定義する

テーブル上一意となる要素はキーとなり、プライマリインデックスが自動的に定義されますが、CMSのビュー(テンプレート)からテーブルに登録されているデータを参照する際のキーとなる要素にはインデックスを設定することで、データ参照の際パフォーマンス改善につながります。

以上の設計過程を経て、実際にテーブルの作成を進めていくことになります。

モデル設計固有のポイント

ここまで、モデル設計はRDBのテーブル設計と同じ考え方であることをベースにその進め方を説明してきましたが、PowerCMS X のモデル定義固有のポイントもあります。ここでは代表的な2つをあげます。

管理画面のUI定義が必要

PowerCMS X のモデル定義はデータベースの作成後に管理画面のUI定義をします。
モデルの編集画面では、実際にコンテンツを新規登録する際に利用する編集画面のUIを定義できます。例えばテキスト型の要素には、1行テキストやテキストエリア、選択項目等を設定することが可能です。その他デフォルト値やバリデーションなども設定ができますので、要素に最適なUIを定義することができます。

実際に商品情報と在庫情報のモデルを定義し、作成された管理画面は以下になります。

商品情報編集画面のキャプチャ

在庫情報編集画面のキャプチャ

モデルと要素の数について

PowerCMS X ではモデルに定義された要素に対して、ビュー(テンプレート)から対象要素を操作するためのテンプレートタグが自動で定義されます。このテンプレートタグはユーザーが管理画面にアクセスするとPHPの実行コードにコンパイル後にキャッシュされます。一度キャッシュされればコンパイルはスキップされますが、要素の総数が多いとこの初期化処理がパフォーマンスのボトルネックになるケースがあります。コンテンツに必要のない要素もCMSで管理すると、必要のないテンプレートタグが初期化処理で生成されることにもなりますので、CMSで管理するデータを必要最小限にし、モデルと各モデルを構成する要素の総数を抑えることがポイントとなります。

最後に

以上、モデル設計をする際の考え方やポイントについて、最も基本的な部分に絞って記載しました。
モデルの設計は自由度が高いため、業務要件に合わせたデータ管理が可能ですが、作成したモデルがPowerCMS Xの内部でどのように利用されるか、その特性を理解することも大事になります。

カテゴリー:技術情報

投稿者:miura

2024-04-09

フォームの設問の入力(選択)状態に応じて別の設問を入力必須にする

例えば下記のキャプチャのように設問「問い合わせ種類」で「その他」を選択すると、設問「問い合わせ種類詳細」を入力必須にするケースです。これは「[フォームのバリデーション・プラグインの作成](https://powercmsx.jp/about/form_validation_plugin.html)」を参考にプラグインを実装することで実現できます。(入力必須にする、というよりは入力必須状態を作り出す、と言う方が正しいでしょうか。) 画面キャプチャ:サンプルのフォーム。設問「問い合わせ種類」で「その他」にし、設問「問い合わせ種類詳細」を空で送信したのでエラーになっている。 ## 設問の準備 以下のように設問を準備します。
設問 ベースネーム 設問タイプ その他設定
問い合わせ種類 contact_type ラジオボタン 必須にチェック
問い合わせ種類詳細 contact_type_etc_content テキスト なし
## プラグインの作成 設問「問い合わせ種類詳細」に対してカスタムバリデーションを作成します。まずconfig.jsonに定義を記述します。ここは概ねドキュメント通りで、プロジェクトに応じて適宜ラベル・メソッド名等変更してください。ポイントは`force: true`を指定することです。`force`の設定により、値がない場合でも強制的にバリデーションを実行することができます。(値がない場合、通常は必須チェック以外のバリデーションは実行の必要がないからだと思います。)
{
    "label": "ALFCustomValidation",
    "id": "alfcustomvalidation",
    "component": "ALFCustomValidation",
    "version": "1.0",
    "author": "Alfasado Inc.",
    "author_link": "https://alfasado.net/",
    "description": "Provide custom form validation.",
    "form_validations": {
        "custom_validation": {
            "component": "ALFCustomValidation",
            "label": "Sample Validation",
            "method": "contactTypeValidation",
            "force": true
        }
    }
}
プラグインのコードは特に難しくありません。2つの設問の入力値を取得し、「問い合わせ種類」が「その他」の場合かつ「問い合わせ種類詳細」が未入力の場合に`$error_msg`にメッセージをセットして`false`を返しています。
<?php

require_once LIB_DIR . 'Prototype' . DS . 'class.PTPlugin.php';
class ALFCustomValidation extends PTPlugin { public function __construct() { parent::__construct(); }
public function contactTypeValidation($app, $question, $value, &$error_msg): bool { // 設問「問い合わせ種類」の値を取得 $type = $app->param('question_contact_type');
// 入力値をチェック if ($type === 'その他') { if (!$value) { $error_msg = '問い合わせ種類詳細を入力してください'; return false; } }
return true; } }
プラグインの作成後、設問「問い合わせ種類詳細」のバリデーションをプラグインで実装したバリデーション(config.jsonの`label`に記述したラベルのもの。この例だとSample Validation)に変更してください。必須にはチェックを入れません。 画面キャプチャ:設問「問い合わせ種類詳細」の編集画面。バリデーションにSample Validationを選択している。 ## まとめ ここまでの内容でCMS(サーバーサイド)の実装は完了です。「その他」を選択した時だけ設問「問い合わせ種類詳細」を表示する・`required`属性を設定する等はJavaScriptでDOMを操作してください。バリデーションプラグインを上手く活用し、送信する人・受け取る人ともに不便を感じることのない分かりやすいフォームを作成して頂ければと思います。 ※初稿の時点では「エラーメッセージを表示する位置を変える」操作をご紹介しましたが、`force`指定により設問「問い合わせ種類詳細」に対してバリデーションが設定できるようになったため不要となりました。

カテゴリー:技術情報

投稿者:安倍

2024-04-05

Typoless (タイポレス) APIをPHPから利用する

Typoless (タイポレス) 別ウィンドウで開きますとは、朝日新聞社が提供する校正支援サービスです。新聞社のノウハウを最先端のAIで実現した新しい校正支援サービスとのことで、PowerCMS Xで校正支援機能を提供している 別ウィンドウで開きますこともあって、その存在には注目していました。

Typolessウェブサイトのスクリーンショット

今年から APIプランの提供が始まっていたこともあり、少し触ってみました。ユーザー登録画面 別ウィンドウで開きますから「API連携プランではじめる」を選択して登録すると、14日間無料(上限は20万文字)で試すことができます。API仕様書は以下にあります。校正 API、カスタム辞書編集 APIが利用できます。

校正 API ( proofread )

<?php
$endPoint = 'https://typoless.asahi.com/web-api/proofread';
$APIKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; // APIキー
$customDictId = 'ABCDEFGH-1234-5678-9IJK-LMNOPQRST'; // カスタム辞書ID
$text = 'Typoless APIのテストてす。満点の星空'; 
$requestBody = ['text' => $text, // 校正したいテキスト
                           'includeRevisedText' => true, // 校正済み文章の取得フラグ(初期値false)
                           'disableTye' => false, // TyE(AIによる校正)の無効化(初期値false)
                           'disableAsahiDict' => false, // 朝日辞書の無効化(初期値false)
                           'disableCustomDict' => false, // カスタム辞書の無効化(未指定の場合、isDefault=trueの辞書を使用する。)
                          ];
if ( $customDictId ) {
    $requestBody['customDictId'] = $customDictId; // カスタム辞書のID
}
$content = json_encode( $requestBody );
$headers = ["Content-type: application/json", "X-Api-Key: {$APIKey}"];
$curl = curl_init( $endPoint );
curl_setopt( $curl, CURLOPT_POST, true );
curl_setopt( $curl, CURLOPT_HTTPHEADER, $headers );
curl_setopt( $curl, CURLOPT_POSTFIELDS, $content );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
$json = curl_exec( $curl );
var_dump( json_decode( $json, true ) );

取得結果は以下の通りです。scoreは範囲は0~1、値が大きいほど自信度が高い、checkTypeが"tye"の場合のみ付与されるとのこと。注意点としては、candidatesは配列になっています(複数の変換候補があるケースのため)。

array(3) {
  ["results"]=>
  array(3) {
    [0]=>
    array(3) {
      ["checkType"]=>
      string(3) "tye"
      ["correction"]=>
      array(4) {
        ["position"]=>
        array(2) {
          ["start"]=>
          int(16)
          ["end"]=>
          int(17)
        }
        ["originalText"]=>
        string(3) "て"
        ["candidates"]=>
        array(1) {
          [0]=>
          string(3) "で"
        }
        ["score"]=>
        float(0.7267)
      }
      ["comment"]=>
      string(10) "て => で"
    }
    [1]=>
    array(3) {
      ["checkType"]=>
      string(10) "asahi_dict"
      ["correction"]=>
      array(3) {
        ["position"]=>
        array(2) {
          ["start"]=>
          int(19)
          ["end"]=>
          int(24)
        }
        ["originalText"]=>
        string(15) "満点の星空"
        ["candidates"]=>
        array(1) {
          [0]=>
          string(12) "満天の星"
        }
      }
      ["comment"]=>
      string(129) "満点の星空 => 満天の星
[誤字・誤用]満点→満天
「満天の星空」は重言。「満天の星」が適切"
    }
    [2]=>
    array(3) {
      ["checkType"]=>
      string(3) "tye"
      ["correction"]=>
      array(4) {
        ["position"]=>
        array(2) {
          ["start"]=>
          int(23)
          ["end"]=>
          int(24)
        }
        ["originalText"]=>
        string(3) "空"
        ["candidates"]=>
        array(1) {
          [0]=>
          string(3) "。"
        }
        ["score"]=>
        float(0.9957)
      }
      ["comment"]=>
      string(10) "空 => 。"
    }
  }
  ["message"]=>
  string(7) "success"
  ["revisedText"]=>
  string(45) "Typoless APIのテストです。満天の星"
}

※ revisedTextに最後の「。」が無いのは不具合?

修正箇所の修正位置(開始・終了)が含まれているので、これを利用して修正を自動化することもできます。ただ、修正前のテキストと修正後のテキストの文字数が同じであるとは限らないため、少し面倒です。

以下は PowerCMS Xでの修正の適用コード。

<?php
require_once( 'class.Prototype.php' );
$app = new Prototype();
$text = $app->param( 'text' );
$corrections = $app->param( 'corrections' );
$pos = 0;
foreach ( $corrections as $idx => $correction ) {
    $correction = json_decode( $correction, true );
    $original = $correction['originalText'];
    $apply = $correction['candidates'][0];
    $correction['candidates'] = $apply;
    if ( $pos !== 0 ) {
        $position = $correction['position'];
        $position['start'] = $position['start'] + $pos;
        $position['end'] = $position['end'] + $pos;
        $correction['position'] = $position;
    }
    $corrections[ $idx ] = $correction;
    $calc = mb_strlen( $apply ) - mb_strlen( $original );
    $pos += $calc;
}
foreach ( $corrections as $correction ) {
    $position = $correction['position'];
    $apply = $correction['candidates'];
    $length = $position['end'] - $position['start'];
    $pre = mb_substr( $text, 0, $position['start'] );
    $after = mb_substr( $text, $position['end'] );
    $text = $pre . $apply . $after;
}
header( 'Content-type: application/json' );
echo json_encode( ['result' => $text ] );
exit();

そのほかに、カスタム辞書(ルール)を追加したり更新したりすることもできます。PowerCMS Xのユーザー辞書と連動するなどの開発もできるかもしれません。

こうなったらいいなのメモ

  • HTMLのタグ混じりの文章をそのまま渡すことができると嬉しい。
  • もうすこし長い範囲で修正前後を拾ってくれると楽かもしれない「て」=>「で」とかだと単純な置換では済まないので(「テストてす」=>「テストです」のように)。
  • 辞書のルール取得や更新のエンドポイントが「/dictionaries/${辞書ID}/rules/${ルールID}」(ルールIDは数字ではなくUUIDのような文字列)なのですが、patternで指定できるか、検索エンドポイントがあるとありがたい。
  • エクスポートした辞書のCSVにルールIDが含まれていると連携して使う場合に便利。
  • 辞書のルール取得APIで件数が増えた時、LIMIT/OFFSETが指定できると良いかもしれない。
  • 「アクセシビリティー」「セキュリティー」など、最後に「ー」が付く形で統一されているようですが、これは、どちらのルールかを選択できると良いように思いました。
  • 利用状況(辞書へのルール登録数、上限まであと何個登録できるか)、月間利用文字数などがわかると良い(※)。

※ APIプランの価格設定的に、ウェブサービスなどの事業者も想定ユーザーになると思うのですが、その場合は利用状況などのデータが取れるとサービスを企画しやすいかもしれません。一方、WEBアプリケーションプランは月額2,200円〜とお手軽価格で APIプランと同じく14日間無料で試せますので、興味のある方はぜひお試しください 別ウィンドウで開きます

カテゴリー:技術情報

投稿者:Junnama Noda

ブログ内検索

アーカイブ