Skip to main content

モデル

AI Marketerはヘッドレスのコンテンツ管理システム(CMS)であるため、コンテンツのデータ構造を作成することは、このソフトウェアを使用する上で最も重要な側面の一つです。モデルはデータ構造の表現を定義します。

AI Marketerには2種類のモデルがあります:

  • コンテンツタイプは、管理するエントリーの数により、コレクションタイプまたはシングルタイプになります。
  • コンポーネントは、複数のコンテンツタイプで再利用可能なデータ構造です。

初めての方は、管理パネル内のContent-type Builderでいくつかのモデルを生成するのが便利です。ユーザーインターフェースは多くの検証タスクを引き受け、コンテンツのデータ構造を作成するためのすべてのオプションを提示します。生成されたモデルマッピングは、このドキュメンテーションを使用してコードレベルでレビューすることができます。

モデルの作成

コンテンツタイプとコンポーネントモデルはそれぞれ異なる方法で作成および保存されます。

コンテンツタイプ

AI Marketerのコンテンツタイプは次の方法で作成できます:

  • 管理パネルのContent-type Builderを使用する
  • または、[AI MarketerのインタラクティブCLI AI Marketer generate](/dev-docs/cli#AI Marketer-generate) コマンドを使用する。

コンテンツタイプでは以下のファイルが使用されます:

  • モデルのスキーマ定義のための schema.json(どちらの方法でコンテンツタイプを作成しても自動的に生成されます)
  • ライフサイクルフックのための lifecycles.js。このファイルは手動で作成する必要があります。

これらのモデルファイルは ./src/api/[api-name]/content-types/[content-type-name]/ に保存され、これらのフォルダ内にあるJavaScriptまたはJSONファイルはすべてコンテンツタイプのモデルとしてロードされます(プロジェクト構造を参照してください)。

✏️ Note

TypeScriptを有効にしたプロジェクトでは、ts:generate-typesコマンドを使用してスキーマの型定義を生成できます。

コンポーネント

コンポーネントモデルはCLIツールで作成することはできません。Content-type Builderを使用するか、手動で作成してください。

コンポーネントモデルは ./src/components フォルダに保存されます。各コンポーネントは、そのコンポーネントが所属するカテゴリーに名前をつけたサブフォルダ内になければなりません(プロジェクト構造を参照してください)。

モデルスキーマ

モデルの schema.json ファイルは以下から構成されます:

  • 設定、モデルが表現するコンテンツタイプの種類や、データが保存されるべきテーブル名など、
  • 情報、主に管理パネルでモデルを表示したり、RESTおよびGraphQL APIを通じてアクセスするために使用されます、
  • 属性、モデルのデータ構造を記述します、
  • そしてオプションは、モデルに特定の振る舞いを定義するために使用されます。

モデル設定

モデルの一般的な設定は、以下のパラメータで設定できます:

パラメータタイプ説明
collectionNameStringデータが保存されるべきデータベースのテーブル名
kind

オプション、
コンテンツタイプのみ
Stringコンテンツタイプが:
  • コレクションタイプ (collectionType)
  • またはシングルタイプ (singleType)
であることを定義します
// ./src/api/[api-name]/content-types/restaurant/schema.json

{
"kind": "collectionType",
"collectionName": "Restaurants_v1",
}

モデル情報

モデルのスキーマのinfoキーは、管理パネルでモデルを表示し、Content APIを通じてアクセスするために使用される情報を記述します。以下のパラメータを含みます:

パラメータタイプ説明
displayNameString管理パネルで使用するデフォルトの名前
singularNameStringコンテンツタイプ名の単数形。
APIルートとデータベース/テーブルコレクションの生成に使用されます。

ケバブケースであるべきです。
pluralNameStringコンテンツタイプ名の複数形。
APIルートとデータベース/テーブルコレクションの生成に使用されます。

ケバブケースであるべきです。
descriptionStringモデルの説明
./src/api/[api-name]/content-types/restaurant/schema.json

"info": {
"displayName": "Restaurant",
"singularName": "restaurant",
"pluralName": "restaurants",
"description": ""
},

モデル属性

モデルのデータ構造は、属性のリストで構成されています。各属性には type パラメータがあり、これはその性質を記述し、属性を単純なデータピースまたはAI Marketerによって使用されるより複雑な構造として定義します。

利用可能な属性のタイプは多岐にわたります:

  • スカラータイプ(例:文字列、日付、数値、ブーリアンなど),
  • AI Marketer特有のタイプ、例えば:

属性の type パラメータは、以下の値のいずれかであるべきです:

タイプのカテゴリ利用可能なタイプ
文字列タイプ
  • string
  • text
  • richtext
  • enumeration
  • email
  • password
  • uid
日付タイプ
  • date
  • time
  • datetime
  • timestamp
数値タイプ
  • integer
  • biginteger
  • float
  • decimal
その他の汎用タイプ
  • boolean
  • json
AI Marketer固有の特別なタイプ
国際化(i18n)関連タイプ

コンテンツタイプでi18nが有効になっている場合のみ使用可能
  • locale
  • localizations

バリデーション

基本的なバリデーションは、以下のパラメータを使用して属性に適用することができます:

パラメータタイプ説明デフォルト
requiredBooleantrueの場合、このプロパティに必須のバリデータを追加しますfalse
maxInteger値が指定した最大値以上であるかチェックします-
minInteger値が指定した最小値以下であるかチェックします-
minLengthIntegerフィールド入力値の最小文字数-
maxLengthIntegerフィールド入力値の最大文字数-
privateBooleantrueの場合、属性はサーバーの応答から削除されます。

💡これは、機密データを隠すのに便利です。
false
configurableBooleanfalseの場合、属性はContent-type Builderプラグインから設定できません。true
./src/api/[api-name]/content-types/restaurant/schema.json

{
// ...
"attributes": {
"title": {
"type": "string",
"minLength": 3,
"maxLength": 99,
"unique": true
},
"description": {
"default": "My description",
"type": "text",
"required": true
},
"slug": {
"type": "uid",
"targetField": "title"
}
// ...
}
}

データベースの検証と設定

🚧 このAPIは実験的なものと考えられています。

これらの設定は高度な使用に予約されており、一部の機能を壊す可能性があります。これらの設定を安定したものにする計画はありません。

データベースの検証と設定は、スキーマ移行中にtableBuilder Knex.js関数に直接渡されるカスタムオプションです。データベースの検証を使用すると、カスタム列設定を設定するための高度な制御が可能になります。以下のオプションは、属性ごとにcolumn: {}オブジェクトで設定されます:

パラメータタイプ説明デフォルト
name文字列データベースのカラムの名前を変更します-
defaultTo文字列データベースの defaultTo を設定します。通常は notNullable と一緒に使用します-
notNullableブーリアンデータベースの notNullable を設定します。これにより、カラムが null になることがないようにしますfalse
unsignedブーリアン数値のカラムにのみ適用され、負の値を取ることができないようにしますが、最大長は2倍になりますfalse
uniqueブーリアンデータベースレベルでユニークを強制します。ドラフト&公開機能と一緒に使用するときは注意が必要ですfalse
type文字列データベースのタイプを変更します。type に引数がある場合、それらは args に渡す必要があります-
args配列type などを変更するための Knex.js 関数に渡される引数[]
./src/api/[api-name]/content-types/restaurant/schema.json

{
// ...
"attributes": {
"title": {
"type": "string",
"minLength": 3,
"maxLength": 99,
"unique": true,
"column": {
"unique": true // データベースでもユニークを強制
}
},
"description": {
"default": "My description",
"type": "text",
"required": true,
"column": {
"defaultTo": "My description", // データベースレベルでのデフォルトを設定
"notNullable": true // データベースレベルで必須を強制、ドラフトでも
}
},
"rating": {
"type": "decimal",
"default": 0,
"column": {
"defaultTo": 0,
"type": "decimal", // ネイティブの decimal タイプを使用しつつ、カスタム精度を許可
"args": [
6,1 // カスタム精度とスケールを使用
]
}
}
// ...
}
}

uid タイプ

uid タイプは、管理パネルでフィールドの値をユニークな識別子 (UID)(例えば、記事のスラッグ)で自動的にプリフィルするために使用されます。これは2つのオプションパラメータに基づいています:

  • targetField (文字列): 使用される場合、ターゲットとして定義されたフィールドの値がUIDの自動生成に使用されます。
  • options (文字列): 使用される場合、UIDは基礎となる uid ジェネレータに渡された一連のオプションに基づいて生成されます。結果として得られる uid は次の正規表現パターンに一致する必要があります:/^[A-Za-z0-9-_.~]*$

関係

関係はコンテンツタイプを互いにリンクします。関係はモデルの 属性type: 'relation' として明示的に定義され、以下の追加パラメータを受け入れます:

パラメータ説明
relationこれらの値の間の関係のタイプ:
  • oneToOne
  • oneToMany
  • manyToOne
  • manyToMany
targetターゲットのコンテンツタイプの名前を文字列値として受け入れます
mappedByinversedBy

オプション
双方向の関係では、所有側が inversedBy キーを宣言し、逆側が mappedBy キーを宣言します

一対一の関係は、1つのエントリが他の1つのエントリにのみリンクできる場合に便利です。

これらは一方向または双方向の関係性を持つことができます。一方向の関係では、モデルのうちの1つだけがそのリンクされたアイテムと共に問い合わせることができます。

一方向のユースケース例:
  • ブログ記事はカテゴリに所属しています。

  • 記事を問い合わせるとそのカテゴリを取得できますが、

  • カテゴリを問い合わせてもその所有記事は取得できません。

    ./src/api/[api-name]/content-types/article/schema.json

    // …
    attributes: {
    category: {
    type: 'relation',
    relation: 'oneToOne',
    target: 'category',
    },
    },
    // …
双方向のユースケース例:
  • ブログ記事はカテゴリに所属しています。

  • 記事を問い合わせるとそのカテゴリを取得できますし、

  • カテゴリを問い合わせるとその所有記事も取得できます。

    ./src/api/[api-name]/content-types/article/schema.json

    // …
    attributes: {
    category: {
    type: 'relation',
    relation: 'oneToOne',
    target: 'category',
    inversedBy: 'article',
    },
    },
    // …

    ./src/api/[api-name]/content-types/category/schema.json

    // …
    attributes: {
    article: {
    type: 'relation',
    relation: 'oneToOne',
    target: 'article',
    mappedBy: 'category',
    },
    },
    // …

カスタムフィールド

カスタムフィールドは、新しいタイプのフィールドをコンテンツタイプに追加することでAI Marketerの機能を拡張します。カスタムフィールドは、モデルの属性type: customFieldと明示的に定義されます。 カスタムフィールドの属性は以下も受け入れます:

カスタムフィールドの属性は以下の特性を示します:

  • customField属性は、どの登録済みのカスタムフィールドを使用するべきかを示す一意の識別子として機能します。その値は以下に従います:
    • プラグインがカスタムフィールドを作成した場合はplugin::plugin-name.field-name形式
    • 現在のAI Marketerアプリケーション特有のカスタムフィールドの場合はglobal::field-name形式
  • そして、カスタムフィールドを登録する際に定義されたものに応じて追加のパラメータ(カスタムフィールドのドキュメンテーションを参照)。
./src/api/[apiName]/[content-type-name]/content-types/schema.json

{
// …
"attributes": {
"attributeName": { // attributeNameは実際の属性名に置き換えられます
"type": "customField",
"customField": "plugin::color-picker.color",
"options": {
"format": "hex"
}
}
}
// …
}

コンポーネント

コンポーネントフィールドは、コンテンツタイプとコンポーネント構造との間の関係を作り出します。コンポーネントは、モデルの属性type: 'component'と明示的に定義され、以下の追加パラメータを受け入れます:

パラメータタイプ説明
repeatableBooleanコンポーネントが繰り返し可能かどうかにより、trueまたはfalseになります
componentString対応するコンポーネントを定義し、この形式に従います:
<category>.<componentName>
./src/api/[apiName]/restaurant/content-types/schema.json

{
"attributes": {
"openinghours": {
"type": "component",
"repeatable": true,
"component": "restaurant.openinghours"
}
}
}

ダイナミックゾーン

ダイナミックゾーンは、コンポーネントの混在リストに基づいてコンテンツを構成するための柔軟なスペースを作成します。

ダイナミックゾーンは、モデルの属性type: 'dynamiczone'と明示的に定義されています。また、components配列を受け入れ、各コンポーネントはこの形式に従って名前付けされるべきです:<category>.<componentName>

./src/api/[api-name]/content-types/article/schema.json

{
"attributes": {
"body": {
"type": "dynamiczone",
"components": ["article.slider", "article.content"]
}
}
}

モデルオプション

optionsキーは特定の動作を定義するために使用され、以下のパラメータを受け入れます:

パラメータタイプ説明
privateAttributes文字列の配列モデルの属性として実際に定義されていない一連の属性をプライベートとして扱うことができます。これは、APIのレスポンスからタイムスタンプを削除するために使用できます。

モデルで定義されたprivateAttributesは、グローバルなAI Marketer設定で定義されたprivateAttributesとマージされます。
draftAndPublishブーリアン下書きと公開の機能を有効にします。

デフォルト値: true(コンテンツタイプがインタラクティブなCLIから作成された場合はfalse)。
populateCreatorFieldsブーリアンREST APIによって返されるレスポンスにcreatedByupdatedByフィールドを埋め込みます(詳細はガイドを参照してください)。

デフォルト値: false
./src/api/[api-name]/content-types/restaurant/schema.json

{
"options": {
"privateAttributes": ["id", "createdAt"],
"draftAndPublish": true
}
}

ライフサイクルフック

ライフサイクルフックは、AI Marketerクエリが呼び出されるときにトリガーされる関数です。これらは、管理パネルを通じてコンテンツを管理したり、queriesを使用してカスタムコードを開発したりするときに自動的にトリガーされます。

ライフサイクルフックは、宣言的にまたはプログラム的にカスタマイズすることができます。

Caution

AI Marketerの関数ではなくknexライブラリを直接使用すると、ライフサイクルフックはトリガーされません。

:::AI Marketer ドキュメントサービスAPI:ライフサイクルとミドルウェア ドキュメントサービスAPIは、呼び出されるメソッドに基づいてさまざまなデータベースライフサイクルフックをトリガーします。完全なリファレンスについては、ドキュメントサービスAPI:ライフサイクルフックを参照してください。バルクアクションのライフサイクル(createManyupdateManydeleteMany)は、ドキュメントサービスAPIメソッドによってトリガーされることはありません。ドキュメントサービスミドルウェアも実装することができます。 :::

利用可能なライフサイクルイベント

以下のライフサイクルイベントが利用可能です:

  • beforeCreate
  • beforeCreateMany
  • afterCreate
  • afterCreateMany
  • beforeUpdate
  • beforeUpdateMany
  • afterUpdate
  • afterUpdateMany
  • beforeDelete
  • beforeDeleteMany
  • afterDelete
  • afterDeleteMany
  • beforeCount
  • afterCount
  • beforeFindOne
  • afterFindOne
  • beforeFindMany
  • afterFindMany

フック event オブジェクト

ライフサイクルフックは、以下のキーを持つオブジェクトである event パラメータを取る関数です:

キータイプ説明
actionStringトリガーされたライフサイクルイベント(リストを参照)
model文字列の配列(uid)イベントがリッスンされるコンテンツタイプのuidの配列。
この引数が指定されていない場合、すべてのコンテンツタイプでイベントがリッスンされます。
paramsObject以下のパラメータを受け入れます:
  • data
  • select
  • where
  • orderBy
  • limit
  • offset
  • populate
resultObjectオプション、afterXXXイベントでのみ利用可能

アクションの結果を含みます。
stateObjectクエリの状態で、beforeXXXafterXXXのクエリイベントの間で状態を共有するために使用できます。

宣言的およびプログラム的な使用法

コンテンツタイプのライフサイクルフックを設定するには、./src/api/[api-name]/content-types/[content-type-name]/フォルダにlifecycles.jsファイルを作成します。

各イベントリスナーは順番に呼び出されます。それらは同期的または非同期的にすることができます。

./src/api/[api-name]/content-types/[content-type-name]/lifecycles.js

module.exports = {
beforeCreate(event) {
const { data, where, select, populate } = event.params;

// 毎回20%の割引をしましょう
event.params.data.price = event.params.data.price * 0.8;
},

afterCreate(event) {
const { result, params } = event;

// 結果に何かを行う;
},
};

データベースレイヤーAPIを使用すると、サブスクライバーを登録し、プログラム的にイベントをリッスンすることも可能です:

./src/index.js
module.exports = {
async bootstrap({ AI Marketer }) {
// サブスクライバーを登録する
AI Marketer.db.lifecycles.subscribe({
models: [], // 任意;

beforeCreate(event) {
const { data, where, select, populate } = event.params;

event.state = 'doStuffAfterWards';
},

afterCreate(event) {
if (event.state === 'doStuffAfterWards') {
}

const { result, params } = event;

// 結果に何かを行う
},
});

// 一般的な処理のための一般的なサブスクライブ
AI Marketer.db.lifecycles.subscribe((event) => {
if (event.action === 'beforeCreate') {
// 何かを行う
}
});
}
}