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

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

  この記事で使用するソースコードは、[FileMaker Data API を使う 2025年版 vol.12#残りの HTML ソースコードの PHP 化](https://qiita.com/RemixWorksLLC/items/f04d4b7ed441e38a54cb#残りの-html-ソースコードの-php-化) にまとめてあります。

  その後の変更(Find Records のテストと JSON ファイル)は、[FileMaker Data API を使う 2025年版 vol.13](https://qiita.com/RemixWorksLLC/items/1353124d7ef044bee7df) を参照してください。

  現在の構造は以下の通りです。
```
.
├── css
│   ├── bootstrap-common.css
│   └── fmda-form.css
├── find-records-test.php ※ vol.13 で追加
├── find-records-test2.php ※ vol.13 で追加
├── html
│   └── edit-record.html
├── index.php
├── js
│   ├── fmda-form-check.js
│   └── fmda-select-page.js
├── json
│   ├── html-contents.json
│   ├── standings-al-east-2024.json ※ vol.13 で追加
│   └── standings-all-2024.json ※ vol.13 で追加
└── php
    ├── bs-builder-class.php
    ├── bs-frame-class.php
    ├── filemaker-data-api-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

## 割り切った global キーワードの使用

 global キーワードは、グローバルスコープの変数をローカルスコープで操作するためのキーワードで、無闇に使用すると、プログラムのメンテナンス性に問題が出ることもあります。

 しかし、開発段階では、割り切って、一定のルールの元に使用すると、プログラムの構造が把握しやすくなります。
 ここで採用するルールは、以下のものです。
 - 原則、ブロック単位で仮に関数化する
 - 仮の関数は、別ファイルに置く
 - 仮の関数で、必要なグローバルスコープの変数を global キーワードで設定する
 - 仮の関数は引数を与えない
 - 仮の関数は戻り値を返さない
 - 引数、戻り値が必要になったら、正規の関数として、別ファイルに移す
 - 正規の関数は、原則、global キーワードを持たない

 といってもイメージが全然、湧かないと思いますので、上記、ルールで書き換えた `find-records-test3.php` を示します。
 前回の [find-records-test2.php](https://qiita.com/RemixWorksLLC/items/1353124d7ef044bee7df#find-records-test2php) は、HTML 出力部分を除いて、今回やろうとしていることと同じですので、比較してみてください。

## find-records-test3.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/temporary-functions.php');

authorization_data();

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

auth_login();
auth_validate_session();

$request_body_json_file = __DIR__ . '/json/standings-all-2024.json';
$request_body           = json_get_element_raw($request_body_json_file);
records_find_records();

auth_log_out();

```

　大変、短くなって、処理の流れが想像しやすくなったのではないでしょうか。
 同様に、`index.php` も書き換えます。

 ## index.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/temporary-functions.php');

authorization_data();

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

if (!isset($result)) {
    // 最初のアクセス
    auth_login();
    auth_validate_session();

    $request_body_json_file = __DIR__ . '/json/standings-all-2024.json';
    $request_body           = json_get_element_raw($request_body_json_file);
    records_find_records();

    auth_log_out();
}

BsFrame::HtmlBegin($color_modes_js, $description, $author, $title, $bootstrap_css, $bs_css_integrity, $bs_frame_css, $custom_css);
BsFrame::LoadColorModesSvg();
BsFrame::ColorModes();

BsBuilder::MainBegin($logo_svg, $logo_svg_width, $page_heading[$page_indentity], $page_lead[$page_indentity]);

BsBuilder::InfoItem($info_heading, $info_number_of_items, $info_item_heading, $info_item_content);
BsBuilder::GetInfo();

BsBuilder::CreateForm($form_preferences, $form_controls);
BsBuilder::CreatePagination($page_indentity);
BsBuilder::MainEnd();
BsBuilder::CreateFooter($copyright_year, $copyright_holder, $link_items);

BsFrame::HtmlEnd($bootstrap_js, $bs_js_integrity, $custom_js);

```

 要するに、ソースコードの流れを把握しやすくするために、処理を隠しているだけのことです。
 隠した処理は、`temporary-functions.php` に移っています。

 ## temporary-functions.php
```
<?php

function authorization_data( ): void
{
    global $host, $version;
    global $database, $username, $password;
    global $layout, $bearer_session_token;
    // FileMaker Server 情報
    $host       = '（FileMaker Server ドメイン名）';
    $version    = 'vLatest';
    // FileMaker ソリューション情報
    $database   = '（FileMaker ソリューション名）';
    $username   = '（FileMaker ユーザ名）';
    $password   = '（パスワード）';
    // リクエスト情報
    $layout     = 'standings';
    $bearer_session_token   = null;
}

function auth_login( ): void
{
    global $fmda, $response, $bearer_session_token, $database, $username, $password;

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

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

function auth_validate_session( ): void
{
    global $fmda, $response, $bearer_session_token;

    // セッションの検証
    $response   = $fmda->validateSession($bearer_session_token);
}

function records_find_records( ): void
{

    global $fmda, $response, $bearer_session_token, $database, $layout, $request_body;
    global $result, $data_info, $team_data;
    global $info_item_content;
    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'];
        }
    } else {
        // セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
        echo "<div class=\"alert alert-warning\" role=\"alert\">セッションが切れました。再ログインしてください。</div>\n";
    }
}

function auth_log_out( ): void
{
    global $fmda, $response, $bearer_session_token, $database;
    // ログアウト
    $response = $fmda->logOut($database, $bearer_session_token);
}

```

　この作業をしていないと、`temporary-functions.php` とほぼ同じ長さだけ `index.php` が長くなってしまうということです。

 正規の関数に格上げした段階で、`temporary-functions.php` が短くなっていくわけですが、理想は、`temporary-functions.php` なくなってしまうことです。

## dataInfo ブロック

　前回の `find-records-test2.php` のデータ表示をしたいわけですが、まず、Find Records で取得したデータをここで元々使われている `$info_item_content` 配列の中身を、仮データから正規のものに変更する必要があります。
 この処理は、`temporary-functions.php` の `records_find_records()` 関数に追加します。

 ### records_find_records() 関数
```
function records_find_records( ): void
{

    global $fmda, $response, $bearer_session_token, $database, $layout, $request_body;
    global $result, $data_info, $team_data;
    global $info_item_content;
    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'];

            // 追加部分
            array_push($info_item_content, $data_info['database']);
            array_push($info_item_content, $data_info['layout']);
            array_push($info_item_content, $data_info['table']);
            array_push($info_item_content, $team_data[0]['recordId']);
            array_push($info_item_content, $team_data[0]['modId']);
            array_push($info_item_content, $data_info['totalRecordCount']);
            array_push($info_item_content, $data_info['foundCount']);
            array_push($info_item_content, $data_info['returnedCount']);
        }
    } else {
        // セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
        echo "<div class=\"alert alert-warning\" role=\"alert\">セッションが切れました。再ログインしてください。</div>\n";
    }
}
```

　現時点での状態は、最初のレコードを表示する前提で、他のことは考慮していませんので、`$team_data[]` 配列のインデックスは 0 になっています。

 この変更に伴い、`preferences.php` にも変更点があります。
### preferences.php 変更部分(46行目から)
```
$info_item_heading  = [];
$info_item_content  = [];
foreach ($temp_array['infoItems'] as $key => $value) {
  array_push($info_item_heading, $value['heading']);
}
```

　foreach の中にあった `array_push($info_item_content, $value['content']);` を削除しているだけです。

  この変更に伴い dateInfo の見出しとラベルも変更が必要になります。❻ については後回しにします。
  テキストコンテントは、`html-contents.json` に入っていますので、該当部分を変更します。

### "contents" JSON オブジェクトの "infoHeading"
```
"infoHeading" : "FileMaker 情報",
```

### "infoItems" JSON 配列
```
"infoItems" : [
        {
            "heading" : "ソリューション"
        },
        {
            "heading" : "レイアウト"
        },
        {
            "heading" : "テーブル"
        },
        {
            "heading" : "レコード ID"
        },
        {
            "heading" : "修正 ID"
        },
        {
            "heading" : "テーブルのレコード数"
        },
        {
            "heading" : "現在のレコード数"
        },
        {
            "heading" : "取得したレコード数"
        }
    ],
```

 これで、dataInfo ブロック 改め、FileMkaer 情報ブロックに表示したい情報が表示されるようになりました。

## 今回、手をつけていない部分

- FileMaker 情報ブロックの❻

 これは、単純に削除する予定です。

- 機能判別

 今回は、ファーストアクセスしか考慮していません。
 フッタのリンクをクリックした際の処理は、フォームデータ表示が出来てから、追加する予定です。

- フォームデータ表示

 Find Records で、`$team_data` 配列には、既に、フォームに表示したい情報が入っています。
 これについては、次回、追加したいと思います。