FileMaker Data API を使う 2025年版 vol.13

 サンプルソリューションのデータは、[新しいサンプルデータを作る](https://qiita.com/RemixWorksLLC/items/04a5e616e59eb062bba9#新しいサンプルテーブルを作る) を参照してください。

 この記事で使用するソースコードは、[前回記事#残りの HTML ソースコードの PHP 化](https://qiita.com/RemixWorksLLC/items/f04d4b7ed441e38a54cb#残りの-html-ソースコードの-php-化) にまとめてあります。

 ディレクトリ構造は、以下の通りです。
```
.
├── css
│   ├── bootstrap-common.css
│   └── fmda-form.css
├── html
│   └── edit-record.html
├── index.php
├── js
│   ├── fmda-form-check.js
│   └── fmda-select-page.js
├── json
│   └── html-contents.json
└── php
    ├── bs-frame-class.php
    ├── php-functions.php
    └── preferences.php

```

## 利用環境

 以下の環境を前提に説明しています。

 - Claris FileMaker Pro 21.1.1.41 macOS
 - Claris FileMaker Server 21.1.1.40 Ubuntu 22(AMD)
 - サーバ: Ubuntu 22.04.5 LTS
 - SSL 証明書
 - リクエストする側のサーバ（任意）

 開発段階では、以下を使用した方が楽でしょう。

 - [Postman](https://www.postman.com)

 Web ページの作成は、以下を条件とします。
 - Bootstrap v5.3.3
 - [Bootstrap Examples Checkout](https://getbootstrap.com/docs/5.3/examples/checkout/) を土台にしています。
 - PHP 8.2.22

## 再び、Find Records

 `index.php` で表示されるメインのブロックの右側（画像）は、元々は、[Checkout](https://getbootstrap.com/docs/5.3/examples/checkout/) のカートの内容と金額を表示するというような目的でデザインされたものです。

　![スクリーンショット 2025-02-13 12.36.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833520/886ded35-c874-430a-b242-3bb23d5c922e.png)

　この部分は、FileMaker ソリューションの現在情報を表示するということにしました。右肩にある❻は不必要ですね。

　この部分のプランは、
 - 全件取得して、1件をカレント情報として、以下の情報を表示する
 - 全体情報の FileMaker ソリューション名
 - 全体情報のレイアウト名
 - 全体情報のテーブル名
 - 全体情報のレコード総数
 - 全体情報の現在レコード数
 - 全体情報の取得レコード数
 - カレント情報のレコード ID
 - カレント情報の修正 ID

 `index.php` にアクセスした段階で、以上を取得して表示させます。
 この時、ページネーションでページを移動した時、カレント情報だけを更新すればいいので、いちいち、全件取りにいくのは無駄です。

  本来ならば、ブラウザの `IndexedDB` や `SQLite3` にテンポラリーデータとして保存しておきたいところですが、対象データは 2024年の MLB 球団のチームなので、最大でも30件（現在27件）しかありません。カレント情報で必要なのは、レコード ID、修正 ID だけですので、とりあえず、配列に入れておくことにして、全件取得に集中しましょう。

 FileMaker Data API の レコードの範囲を取得する方法は、Get Records と Find Records の２種類がありますが、Find Records の方が扱いやすいので、こちらを使うことにします。
 Find Records については、[こちらの記事](https://qiita.com/RemixWorksLLC/items/829f963fea79ac53abe4#find-records)を参照してください。

 Find Records のリクエストを考えるときは、まず、どのようなデータが欲しいのか、JSON で考えます。
 例えば、2024年のアメリカン・リーグ、かつ、東地区のデータを勝利数の降順で欲しい場合は、

 ### standings-al-east-2024.json
```
{
    "query" :
    [
        {
            "year" : 2024,
            "league" : "アメリカン・リーグ",
            "division" : "東地区",
            "omit" : "false"
        }
    ],
    "sort" :
    [
        {
            "fieldName" : "wins",
            "sortOrder" : "descend"
        }
    ],
    "offset" : "1",
    "limit" : "30"
}
```

 この JSON ファイルを読み込んで、リクエストボディとします。
 リクエスト内容が変わった場合、プログラム本体ではなく、JSON を修正すればいいということです。

 Web サーバ上の JSON で管理していれば、FileMaker Pro からも扱いやすくなります。
 また、蛇足ですが、JavaScript を使った FileMaker とのコミュニケーションは JSON 形式になるので、後々、都合が良いという可能性もあります。
 
 このリクエストの result は以下のようになります。
```
{
    "response": {
        "dataInfo": {
            "database": "（FileMaker ソリューション名）",
            "layout": "standings",
            "table": "standings",
            "totalRecordCount": 27,
            "foundCount": 5,
            "returnedCount": 5
        },
        "data": [
            {
                "fieldData": {
                    "mlb_site_id": 147,
                    "year": 2024,
                    "league": "アメリカン・リーグ",
                    "division": "東地区",
                    "team": "ニューヨーク・ヤンキース",
                    "wins": 94,
                    "losses": 68,
                    "winning_percentage": "",
                    "runs_scored": 815,
                    "runs_allowed": 668,
                    "pythagorean_expectation": "",
                    "expected_win_loss": "",
                    "winning_percentage_diﬀerence": ""
                },
                "portalData": {},
                "recordId": "3",
                "modId": "0"
            },
            {
                "fieldData": {
                    "mlb_site_id": 110,
                    "year": 2024,
                    "league": "アメリカン・リーグ",
                    "division": "東地区",
                    "team": "ボルチモア・オリオールズ",
                    "wins": 91,
                    "losses": 71,
                    "winning_percentage": "",
                    "runs_scored": 786,
                    "runs_allowed": 699,
                    "pythagorean_expectation": "",
                    "expected_win_loss": "",
                    "winning_percentage_diﬀerence": ""
                },
                "portalData": {},
                "recordId": "1",
                "modId": "0"
            },
            {
                "fieldData": {
                    "mlb_site_id": 111,
                    "year": 2024,
                    "league": "アメリカン・リーグ",
                    "division": "東地区",
                    "team": "ボストン・レッドソックス",
                    "wins": 81,
                    "losses": 81,
                    "winning_percentage": "",
                    "runs_scored": 751,
                    "runs_allowed": 747,
                    "pythagorean_expectation": "",
                    "expected_win_loss": "",
                    "winning_percentage_diﬀerence": ""
                },
                "portalData": {},
                "recordId": "2",
                "modId": "0"
            },
            {
                "fieldData": {
                    "mlb_site_id": 139,
                    "year": 2024,
                    "league": "アメリカン・リーグ",
                    "division": "東地区",
                    "team": "タンパベイ・レイズ",
                    "wins": 80,
                    "losses": 82,
                    "winning_percentage": "",
                    "runs_scored": 604,
                    "runs_allowed": 663,
                    "pythagorean_expectation": "",
                    "expected_win_loss": "",
                    "winning_percentage_diﬀerence": ""
                },
                "portalData": {},
                "recordId": "4",
                "modId": "0"
            },
            {
                "fieldData": {
                    "mlb_site_id": 141,
                    "year": 2024,
                    "league": "アメリカン・リーグ",
                    "division": "東地区",
                    "team": "トロント・ブルージェイズ",
                    "wins": 74,
                    "losses": 88,
                    "winning_percentage": "",
                    "runs_scored": 671,
                    "runs_allowed": 743,
                    "pythagorean_expectation": "",
                    "expected_win_loss": "",
                    "winning_percentage_diﬀerence": ""
                },
                "portalData": {},
                "recordId": "5",
                "modId": "0"
            }
        ]
    },
    "messages": [
        {
            "code": "0",
            "message": "OK"
        }
    ]
}

```

　各 `recordId` と `modId` は、上と同じとは限りません。これはレコードの作成タイミング、更新タイミングで変わります。

 それでは、ターミナルで実行するテストプログラムを作ってみましょう。
 まず、`php-function.php` に JSON を読み込む関数を追加します。これまで使ってきた JSON 読み込みの関数は、戻り値を配列しにして戻しているので、生データで返すものを追加します。
### php-functions.php へ追加 
```
function json_get_element_raw(string $json_file): string
{  
  return $json_object    = file_get_contents($json_file, true);
}
```

 次に、テストプログラム `find-records-test.php` を作成します。

 冒頭部分は、index.php をコピー＆ペーストして構いません。
### find-records-test.php 冒頭部分
```
<?php

require_once(__DIR__ . '/php/bs-frame-class.php');
require_once(__DIR__ . '/php/bs-builder-class.php');
require_once(__DIR__ . '/php/php-functions.php');
require_once(__DIR__ . '/php/filemaker-data-api-class.php');

@$page_indentity    = $_POST['page-identity'];
$page_indentity     = $page_indentity === null ? 1 : $page_indentity;

require_once(__DIR__ . '/php/preferences.php'); 
```
 ここで、本当に必要なのは、以下だけですが、まあ、いいでしょう。
```
require_once(__DIR__ . '/php/php-functions.php');
require_once(__DIR__ . '/php/filemaker-data-api-class.php');
```

 続けて、FileMaker の情報を書きます。
```
// FileMaker Server 情報
$host       = '（FileMaker Server ドメイン名）';
$version    = 'vLatest';
// FileMaker ソリューション情報
$database   = '（FileMaker ソリューション名）';
$username   = '（FileMaker ユーザ名）';
$password   = '（パスワード）';
// リクエスト情報
$layout     = 'standings';
$request_body_json_file = __DIR__ . '/json/standings-al-east-2024.json';
$request_body           = json_get_element_raw($request_body_json_file);
$bearer_session_token   = null;

```

　これで、必要な情報が揃ったので、あとは、クラスを使って、以前の記事で説明している流れで、以下の順序で書いていきます。
 1. ログイン
 1. トークン検証
 1. Find Records
 1. ログアウト

　尚、player_batting で使っていた、FileMaker Data API のクラスと、こちらのクラスはクラス名を変えています。内容は、現時点では同じです。

　順番に、見ていきましょう。

 クラスのインスタンスを作って、ログインします。
```
$fmda   = new FileMakerDataApi($host, $version);

// ログイン
$response = $fmda->login($database, $username, $password);

// ログイン成功？
if ($fmda->getMessagesCode($response) === '0') {
    // ログイン成功なら、Bearer Session Token を取得する
    $bearer_session_token   = $fmda->getBearerSessionToken($response);
} else {
    // ログイン失敗の処理を書く
    echo "FileMaker Data API へのログインに失敗しました。\n";
}

```

　エラーの場合の処理は特に書いていません。

　Bearer Session Token を検証し、有効なら、Find Records リクエストを実行、成功したら、結果セットを処理します。
```
// セッションの検証
$response   = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
    // セッション有効なら、行いたいリクエスト実行

    // レコードの検索
    $response   = $fmda->findRecords($database, $layout, $bearer_session_token, $request_body);

    // 結果セット処理
    $result = $fmda->json2array($response);
    
    if ($fmda->getMessagesCode($response) === '0') {
        $data_info  = $result['response']['dataInfo'];
        $team_data  = $result['response']['data'];

        echo "ソリューション: {$data_info['database']}\n";
        echo "レイアウト: {$data_info['layout']}\n";
        echo "テーブル: {$data_info['table']}\n\n";
        foreach ($team_data as $key => $value) {
            echo $value['fieldData']['team'],PHP_EOL;
            echo "\tレコード ID: {$value['recordId']}\n";
            echo "\t修正 ID: {$value['modId']}\n\n";
        }
        echo "総レコード数: {$result['response']['dataInfo']['totalRecordCount']}\n";
        echo "現在レコード数: {$result['response']['dataInfo']['foundCount']}\n";
        echo "取得レコード数: {$result['response']['dataInfo']['returnedCount']}\n";
    }
} else {
    // セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
    echo "再ログインしてください。\n";
}

```

 リクエスト処理が終わったら、ログアウトします。
```
// ログアウト
$response = $fmda->logOut($database, $bearer_session_token);
```

 結果は、以下のよう表示されます。
```
ソリューション: FileMaker ソリューション名
レイアウト: standings
テーブル: standings

ニューヨーク・ヤンキース
	レコード ID: 30
	修正 ID: 0

ボルチモア・オリオールズ
	レコード ID: 28
	修正 ID: 0

ボストン・レッドソックス
	レコード ID: 29
	修正 ID: 0

タンパベイ・レイズ
	レコード ID: 31
	修正 ID: 0

トロント・ブルージェイズ
	レコード ID: 32
	修正 ID: 0

総レコード数: 27
現在レコード数: 5
取得レコード数: 5
```

　ページのメイン右ブロックに表示したい情報が揃っています。長くなるので、結果は載せませんが、実際に使う全球団（現在は、27球団）の情報を取得する JSON ファイルを作って、読み込みファイルの指定を変更しましょう。

 ### standings-all-2024.json
```
{
    "query" :
    [
        {
            "year" : 2024,
            "omit" : "false"
        }
    ],
    "sort" :
    [
        {
            "fieldName" : "league",
            "sortOrder" : "ascend"
        },
        {
            "fieldName" : "wins",
            "sortOrder" : "descend"
        }
    ],
    "offset" : "1",
    "limit" : "30"
}
```

### find-records-test2.php
```
<?php

require_once(__DIR__ . '/php/bs-frame-class.php');
require_once(__DIR__ . '/php/bs-builder-class.php');
require_once(__DIR__ . '/php/php-functions.php');
require_once(__DIR__ . '/php/filemaker-data-api-class.php');

@$page_indentity    = $_POST['page-identity'];
$page_indentity     = $page_indentity === null ? 1 : $page_indentity;

require_once(__DIR__ . '/php/preferences.php');

// FileMaker Server 情報
$host       = '（FileMaker Server ドメイン名）';
$version    = 'vLatest';
// FileMaker ソリューション情報
$database   = '（FileMaker ソリューション名）';
$username   = '（FileMaker ユーザ名）';
$password   = '（パスワード）';
// リクエスト情報
$layout     = 'standings';
$request_body_json_file = __DIR__ . '/json/standings-all-2024.json';
$request_body           = json_get_element_raw($request_body_json_file);
$bearer_session_token   = null;

$fmda   = new FileMakerDataApi($host, $version);

// ログイン
$response = $fmda->login($database, $username, $password);

// ログイン成功？
if ($fmda->getMessagesCode($response) === '0') {
    // ログイン成功なら、Bearer Session Token を取得する
    $bearer_session_token   = $fmda->getBearerSessionToken($response);
} else {
    // ログイン失敗の処理を書く
    echo "FileMaker Data API へのログインに失敗しました。\n";
}

// （何らかの処理があり、リンクでページ遷移した想定）


// セッションの検証
$response   = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
    // セッション有効なら、行いたいリクエスト実行

    // レコードの検索
    $response   = $fmda->findRecords($database, $layout, $bearer_session_token, $request_body);

    // 結果セット処理
    $result = $fmda->json2array($response);
    
    if ($fmda->getMessagesCode($response) === '0') {
        $data_info  = $result['response']['dataInfo'];
        $team_data  = $result['response']['data'];

        echo "ソリューション: {$data_info['database']}\n";
        echo "レイアウト: {$data_info['layout']}\n";
        echo "テーブル: {$data_info['table']}\n\n";
        foreach ($team_data as $key => $value) {
            echo $value['fieldData']['team'],PHP_EOL;
            echo "\tレコード ID: {$value['recordId']}\n";
            echo "\t修正 ID: {$value['modId']}\n\n";
        }
        echo "総レコード数: {$result['response']['dataInfo']['totalRecordCount']}\n";
        echo "現在レコード数: {$result['response']['dataInfo']['foundCount']}\n";
        echo "取得レコード数: {$result['response']['dataInfo']['returnedCount']}\n";
    }
} else {
    // セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
    echo "再ログインしてください。\n";
}

// （何らかの処理）

// ログアウト
$response = $fmda->logOut($database, $bearer_session_token);

```

　このように、Find Records では、JSON の内容を変更するだけで、様々な結果セットを取得できます。この例では、リーグ別の勝利数順に表示されますが、リーグ・地区ごとの順位表も作ることができますよね。

 次回は、これを元にして、ページのメイン右ブロックを表示させてみましょう。