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

 サンプルデータの作成は [FileMaker Data API を使う 2025 年版 vol.1](https://qiita.com/RemixWorksLLC/items/0e5f2741e7f50547b427) を参照してください。

 ## 利用環境

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

 - 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)

## スクリプトを使う

 FileMaker Pro では、ユーザが行う操作をスクリプトステップとして捉え、スクリプトとしてまとめることができます。FileMaker Data API でも、使えるスクリプトステップが減りますが、基本的な考え方は同じです。

 Get Records では、リクエストの処理前、ソートの実行前、及びリクエストの処理後の３段階でスクリプトの実行が可能です。
 前回の`_offset`、`_limit` 及び `_sort`と合わせて実行順序を以下に示します。
 1. `script.prerequest`（リクエストの処理前のスクリプト実行）
 1. リクエストの処理（現在の場合、Get Records）
 1. `script.presort`（`_sort` で指定したソートの実行前のスクリプト実行）
 1. `_sort` で指定したソートの実行
 1. `script`（リクエストの処理後のスクリプト実行）
 1. `_offset` 及び `_limit` で指定された結果セットを返す

　リクエストで処理の種類は、以下のものがあります。
 - 取得
 - 作成
 - 編集
 - 削除
 - 複製
 - 検索

　以上の処理の前・後と、後処理ならば、ソート前なのか後なのかで使い分けるということです。

　それでは、まず、スクリプトに対応するため、`getRecords()` メソッドを差し替え、ファイル名を `filemaker-data-api-v2.1.php` とします。

 ### getRecords() メソッド
```
	// レコード範囲の取得
	public function getRecords(
		string $database,
		string $layout,
		string $bearer_session_token,
		array &$script_name_array,
		array &$script_param_array,
		int $_offset = 1,
		int $_limit = 100,
		string $_sort = ''
		): string
    {
		$this->layout		= $layout;

		$authorization      = 'Authorization: Bearer ' . $bearer_session_token;
		$curlopt_httpheader = array($authorization);

		// ソートの設定
		$_sort_string		= !empty($_sort) ? '&_sort=' . urlencode($_sort) : '';

        $script_prerequest			= '';
    	$script_prerequest_param	= '';
    	$script_presort				= '';
    	$script_presort_param		= '';
    	$script						= '';
    	$script_param				= '';
		// リクエスト処理前のスクリプト
		if ($script_name_array[0] !== '') {
			$script_prerequest	= '&script.prerequest=' . $script_name_array[0];
			$script_prerequest_param = '&script.prerequest.param=' . urlencode(json_encode($script_param_array[0]));
		}
		
		// ソート前のスクリプト
		if ($script_name_array[1] !== '') {
			$script_presort	= '&script.presort=' . $script_name_array[1];
			$script_presort_param = '&script.presort.param=' . urlencode(json_encode($script_param_array[1]));
		}

		// リクエスト処理後のスクリプト
		if ($script_name_array[2] !== '') {
			$script	= '&script=' . $script_name_array[2];
			$script_param = '&script.param=' . urlencode(json_encode($script_param_array[2]));
		}
		
		$endpoint        	= "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/records?_offset={$_offset}&_limit={$_limit}{$_sort_string}{$script_prerequest}{$script_prerequest_param}{$script_presort}{$script_presort_param}{$script}{$script_param}";
		return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
	}
    
```

　実験として、何の脈略もありませんが、スクリプトに渡した引数を、そのまま返すというスクリプトを作ってみたいと思います。
 FileMaker Pro で、以下の３つのスクリプトを作成してください。
 内容はすべて同じです。

- script_prerequest_Test
- script_presort_Test
- script_Test

 ### script_prerequest_Test、script_presort_Test、script_Test
```
変数を設定 [ $json ; 値: Get ( スクリプト引数 ) ]
# 
# 処理を行う
# 
現在のスクリプト終了 [ テキスト結果: 

Let ([
    ~name	= JSONGetElement ( $json ; "name" ) ;
    ~team	= JSONGetElement ( $json ; "team" )
    ] ;
    JSONSetElement (
        "{}" ;
        [ "name" ; ~name ; JSONString ] ;
        [ "team" ; ~team ; JSONString ]
    )
)

]

```

　スクリプト引数は、文字列を渡しますが、JSON を渡し、JSON を返すということに統一してしまった方が良いと思います。

　メインプログラムは、以下の通りです。

### get_records-v2.1.php
```
<?php

require_once(__DIR__ . '/filemaker-data-api-v2.1.php');

$host                   = 'FileMaker Server ドメイン名';
$version                = 'vLatest';
$database               = 'FileMaker ソリューション名';
$username               = 'FileMaker ユーザ名';
$password               = 'パスワード';
$layout                 = 'player_batting_basic';
$bearer_session_token   = null;

$fmda   = new FileMaker_Data_API($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') {
    // セッション有効なら、行いたいリクエスト実行
    $_offset    = 31;   // 31 件目から
    $_limit     = 30;   // 30 件取得

    $field_name = 'on_base_percent';    // ソート対象フィールド名
    $sort_order = 'descend';    // 昇順 -> ascend、降順 -> descend、値一覧 -> 値一覧名
    $_sort      = [['fieldName' => $field_name, 'sortOrder' => $sort_order]];   // _sort パラメータの配列作成
    $_sort      = json_encode($_sort);  // それを JSON化

    // リクエスト処理前のスクリプト
    $prerequest_script          = 'script_prerequest_Test';
    $prerequest_script_param    = ["name" => "大谷翔平", "team" => "LAD"];

    // ソート実行前のスクリプト
    $presort_script             = 'script_presort_Test';
    $presort_script_param       = ["name" => "鈴木誠也", "team" => "CHC"];

    // リクエスト処理後のスクリプト
    $postrequest_script         = 'script_Test';
    $postrequest_script_param   = ["name" => "ダルビッシュ有", "team" => "SD"];
    
    $script_name_array  = [$prerequest_script, $presort_script, $postrequest_script];
    $script_param_array = [$prerequest_script_param, $presort_script_param, $postrequest_script_param];

    $response   = $fmda->getRecords($database, $layout, $bearer_session_token, $script_name_array, $script_param_array, $_offset, $_limit, $_sort);
    
    $result = mb_convert_encoding($response, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
    $result = json_decode($result, true);
    print_r($result);
    // レコード取得
} else {
    // セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
    echo "再ログインしてください。\n";
}

// （何らかの処理）

// ログアウト

$response = $fmda->logOut($database, $bearer_session_token);

```

　`getRecords()` メソッドのスクリプト関連のパラメータは二つの配列を参照する形にしました。
 その配列を作っている部分を抜き出します。
```
    // リクエスト処理前のスクリプト
    $prerequest_script          = 'script_prerequest_Test';
    $prerequest_script_param    = ["name" => "大谷翔平", "team" => "LAD"];

    // ソート実行前のスクリプト
    $presort_script             = 'script_presort_Test';
    $presort_script_param       = ["name" => "鈴木誠也", "team" => "CHC"];

    // リクエスト処理後のスクリプト
    $postrequest_script         = 'script_Test';
    $postrequest_script_param   = ["name" => "ダルビッシュ有", "team" => "SD"];
    
    $script_name_array  = [$prerequest_script, $presort_script, $postrequest_script];
    $script_param_array = [$prerequest_script_param, $presort_script_param, $postrequest_script_param];
    
```

 どのタイミングで実行されるスクリプトであっても、名前の文字列とパラメータの連想配列を作成します。
 
 作った名前文字列とパラメータ連想配列を、それぞれ配列にまとめます。

 名前文字列(`$prerequest_script`、`$presort_script`、`$postrequest_script`)が空の場合、そのタイミングのスクリプトは実行されません。
  それらを収めた名前配列(`$script_name_array`)の順序は、リクエスト処理前、ソート実行前、リクエスト処理後の順で固定されていて、インデックスは 0, 1, 2 となります。
  同じ順序で、パラメータの連想配列(`$prerequest_script_param`、`$presort_script_param`、`$postrequest_script_param `)を配列 `$script_param_array` に収めます。連想配列は、JSON 化されて渡されます。

 このプログラムを実行すると、レスポンスにスクリプト関係のものが入ってきます。
 - **scriptResult.prerequest** リクエスト処理前スクリプトの戻り値
 - **scriptError.prerequest** リクエスト処理前スクリプトのエラーコード。成功なら 0
 - **scriptResult.presort** ソート実行前スクリプトの戻り値
 - **scriptError.presort** ソート実行前スクリプトのエラーコード。成功なら 0
 - **scriptResult** リクエスト処理後スクリプトの戻り値
 - **scriptError** リクエスト処理後スクリプトのエラーコード。成功なら 0

## シナリオ

**2024年の選手データを `on_base_percent` で降順ソートして、10件取得する。（2024年の出塁率ベスト10を取得する）**

 流れは以下のようになります。
1. リクエスト処理前スクリプトで、2024年データに絞り込み
1. リクエスト処理
1. `on_base_percent` で降順ソート
1. `_offset=1`、`_limit=10`の結果セットを取得

 まず、FileMaker Pro で2024年データに絞り込むスクリプト `Extracts_by_year` を作成します。

### Extracts_by_year
```
変数を設定 [ $json ; 値: Get ( スクリプト引数 ) ]
# 
変数を設定 [ $year ; 値: JSONGetElement ( $json ; "year" ) ]
検索実行 [ 記憶する ]
# 
現在のスクリプト終了 [ テキスト結果: Let ([ 	~error	= Get ( 最終エラー ) ] ; JSONSetElement ( 	"{}" ; 	[ "error" ; ~error ; JSONString ])) ]

```

`検索実行` スクリプトステップの内容は、`player_batting::year: [$year]` となっています。

　引数は、JSON で、絞り込むシーズンをキー year で渡しています。
　戻り値は、スクリプト実行中に起きた最終エラーを返します。エラーがなければ 0 が戻ります。

　メインプログラムの流れは、結果セットの表示方法を少し弄ってあるくらいで、先ほどとほぼ一緒です。

 ### get_records-obp.php
```
<?php

require_once(__DIR__ . '/filemaker-data-api-v2.1.php');

$host                   = 'FileMaker Server ドメイン名';
$version                = 'vLatest';
$database               = 'FileMaker ソリューション名';
$username               = 'FileMaker ユーザ名';
$password               = 'パスワード';
$layout                 = 'player_batting_basic';
$bearer_session_token   = null;

$fmda   = new FileMaker_Data_API($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') {
    // セッション有効なら、行いたいリクエスト実行
    $_offset    = 1;   // 1 件目から
    $_limit     = 10;   // 200 件取得

    $field_name = 'on_base_percent';    // ソート対象フィールド名
    $sort_order = 'descend';    // 昇順 -> ascend、降順 -> descend、値一覧 -> 値一覧名
    $_sort      = [['fieldName' => $field_name, 'sortOrder' => $sort_order]];   // _sort パラメータの配列作成
    $_sort      = json_encode($_sort);  // それを JSON化

    // リクエスト処理前のスクリプト
    $prerequest_script          = 'Extracts_by_year';
    $prerequest_script_param    = ["year" => 2024];

    // ソート実行前のスクリプト
    $presort_script             = '';
    $presort_script_param       = [];

    // リクエスト処理後のスクリプト
    $postrequest_script         = '';
    $postrequest_script_param   = [];
    
    $script_name_array  = [$prerequest_script, $presort_script, $postrequest_script];
    $script_param_array = [$prerequest_script_param, $presort_script_param, $postrequest_script_param];

    // レコード取得
    $response   = $fmda->getRecords($database, $layout, $bearer_session_token, $script_name_array, $script_param_array, $_offset, $_limit, $_sort);
    
    // 結果セット処理
    $result = mb_convert_encoding($response, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
    $result = json_decode($result, true);
    
    if ($fmda->getMessagesCode($response) === '0') {
        $player_data    = $result['response']['data'];
        foreach ($player_data as $key => $value) {
            echo $value['fieldData']['last_name_ first_name'] . ' - ';
            echo $value['fieldData']['on_base_percent'], PHP_EOL;
        }
    }

    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);

```

　次のような結果が表示されます。
```
Judge, Aaron - .458
Soto, Juan - .419
Guerrero Jr., Vladimir - .396
Alvarez, Yordan - .392
Ohtani, Shohei - .390
Witt Jr., Bobby - .389
Profar, Jurickson - .380
Freeman, Freddie - .378
Ozuna, Marcell - .378
Harper, Bryce - .373
総レコード数: 1375
現在レコード数: 129
取得レコード数: 10
```