0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2025-02-12

サンプルソリューションのデータは、新しいサンプルデータを作る を参照してください。

この記事で使用するソースコードは、PHP 化の叩き台にする HTML ソースコード 以下にある次のソースコードです。

  • edit-record.html
  • bootstrap-common.css
  • fmda-form.css
  • fmda-form-check.js

以上を、前回記事で、変更しており、以下の構成になっています。

.
├── css
│   ├── bootstrap-common.css
│   └── fmda-form.css
├── html
│   └── edit-record.html
├── index.php
├── js
│   └── fmda-form-check.js
├── json
│   └── html-contents.json
└── php
    ├── bs-frame-class.php
    ├── php-functions.php
    └── preferences.php

ページの識別

 現在のプランでは、共通の骨組みを使って、FileMaker Data API の作成・編集・削除・複製のリクエストを実行するページを作るという方針になっています。
しかし、ほとんど同じなのに、作成・編集・削除・複製で4つもページを作るのは、なんだか面倒な気がします。
それよりもシングルページで4つの機能を持っている方が、現在は、PHP ですが、後々、JavaScript で非同期スタイルに改めたときを考えると良さそうです。

しかし、4つの機能は、前後の処理や、FileMaker Data API のリクエストが異なりますので、なんらかの方法で判別させなければいけません。
大昔の CGI プログラムなら、GET で、?page=1 のような URL で解決したと思います。
同じような考え方で、GET ではなく、POST でやる想定をしておきましょう。

最初のアクセス、またはフッタ部分のリンクのクリックで、機能を選べるようにページの識別子を仕込んでおくことにします。

ページの識別
ページの識別子 機能 FileMaker Data API リクエスト
0 新規作成 records - Create Record
1 編集 records - Edit Record
2 削除 records - Delete Record
3 複製 records - Duplicate Record

 以上のように規定し、デフォルトを 1 とします。
これをname="page-identity" で POST で送信し、$_POST['page-identity'] を調べます。
これがエラーになった場合は、デフォルトの 1 を選択したと解することにして、index.php の冒頭に、この処理を preferences.php を読み込む前に追加します。

index.php 冒頭部分

<?php

require_once(__DIR__ . '/php/bs-frame-class.php');

require_once(__DIR__ . '/php/php-functions.php');

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

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

 これで、識別子を取得できれば、ページの機能の特定はできそうです。

残りの HTML ソースコードの PHP 化

 残りは、固有のコンテンツ部分になります。
手法としては、前回と同様、

  • preferences.php に設定項目を持たせて
  • その実際の内容は、html-contents.json に書き、
    将来の FileMaker Pro からの更新に対応させる
  • HTML の出力部分は、クラスのスタティックメソッドとする

 このような方針で、前述のページ識別を含め、一気に以下の条件で PHP 化してしまいます。

  • FileMaker Data API のリクエストのコードはまだ書かない
  • FileMaker ソリューションから得るべきデータは仮
  • フッタ部分のリンクは、ページ識別に対応させる
  • それ用に、JavaScript のコードを追加する
  • コンテンツ固有の HTML ソースコードは、別のクラスファイルにしておく

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

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

bootstrap-common.css

fmda-form.css

bs-builder-class.php

<?php

class BsBuilder {

    static function MainBegin (
      string $logo_svg,
      string $logo_svg_width,
      string $heading,
      string $lead
    ): void
    {
      echo <<<_HTML_
  <div class="container">
    <main>
      <div class="py-5 text-center">
        <img class="d-block mx-auto mb-4" src="{$logo_svg}" alt="" width="{$logo_svg_width}">
        <h2>{$heading}</h2>
        <p class="lead">{$lead}</p>
      </div> <!-- / .py-5 .text-center -->
  
      <div class="row g-5">
  
  _HTML_;
  
    }
  
    static function InfoItem (
      string $info_heading,
      int $info_number_of_items,
      array &$info_item_heading,
      array &$info_item_content
    ): void
    {
      echo <<<_HTML_
  <div class="col-md-5 col-lg-4 order-md-last">
    <h4 class="d-flex justify-content-between align-items-center mb-3">
      <span class="text-primary">{$info_heading}</span>
      <span class="badge bg-primary rounded-pill">{$info_number_of_items}</span>
    </h4>
  
    <ul class="list-group mb-3">
  
  _HTML_; // begin
  
      for ($i = 0 ; $i < count($info_item_heading) ; $i++) {
  
        echo <<<_HTML_
  <li class="list-group-item d-flex justify-content-between lh-sm">
    <div>
      <h6 class="my-0">{$info_item_heading[$i]}</h6>
  
  _HTML_;
  
        if (is_numeric($info_item_content[$i])) {
          echo <<<_HTML_
    </div>
    <span class="text-success">$info_item_content[$i]</span>
  </li>
  
  _HTML_;
  
        } else {
          echo <<<_HTML_
      <small class="text-body-secondary">standings</small>
    </div>
  </li>
  
  _HTML_;
  
        } // if (is_numeric($info_item_content[$i]))
      } // for ($i = 0 ; $i < count($info_item_heading) ; $i++)
  
      echo "</ul>\n"; // end
    }
  
    static function GetInfo ( ): void {
      echo <<<_HTML_
    <form action="{$_SERVER['PHP_SELF']}" method="POST" class="card p-2">
      <div class="input-group">
        <input type="text" class="form-control" name="recordId" placeholder="recordId">
        <input type="hidden" class="visually-hidden" name="getInfo" value="true">
        <button type="submit" class="btn btn-secondary">取得する</button>
      </div>
    </form>
  </div>
  
  _HTML_;
  
    }
  
    static function CreateForm (
      array &$form_prefernces,
      array &$form_controls
    ): void {
  
      echo <<<_HTML_
  <div class="col-md-7 col-lg-8">
    <h4 class="mb-3">{$form_prefernces[0]}</h4>
      <form action="{$form_prefernces[1]}" method="POST" class="needs-validation" novalidate>
        <div class="row g-3">
      
  _HTML_; // begin
  
      foreach ($form_controls as $key => $value) {
        $required         = '';
        $secondary_label  = '';
        if ($value['required'] === '1')
          $required         = 'required';
        else
          $secondary_label  = '<span class="text-body-secondary">(任意)</span>';
  
        if ($value['type'] === 'select') {
          echo <<<_HTML_
  <div class="col-sm-6">
    <label for="{$value['id']}" class="form-label">{$value['label']}{$secondary_label}</label>
    <select class="form-select" id="{$value['id']}" name="{$value['name']}" {$required} {$value['disabled']}>
      <option value="">選択...</option>
  
  _HTML_;
  
          foreach ($value['option'] as $option_key => $option_value) {
            echo "<option>{$option_value['value']}</option>\n";
          }
          echo "</select>\n";
  
        } else {
          echo <<<_HTML_
  <div class="col-sm-6">
    <label for="{$value['id']}" class="form-label">{$value['label']}{$secondary_label}</label>
    <input type="{$value['type']}" class="form-control" id="{$value['id']}" name="{$value['name']}" placeholder="{$value['placeholder']}" {$required} {$value['disabled']}>
  _HTML_;
  
        } // if ($value['type'] === 'select')
  
        if (!empty($required)) {
          echo <<<_HTML_
  <div class="invalid-feedback">
    {$value['feedback']}
  </div>
  
  _HTML_;
  
        } // if (!empty($required))
  
        echo "</div>\n";
      } // foreach ($form_controls as $key => $value)
  
    echo <<<_HTML_
    </div> <!-- / .row -->
  
    <hr class="my-4">
  
    <button class="w-100 btn {$form_prefernces[2]} btn-lg" type="submit">{$form_prefernces[3]}</button>
  </form> <!-- / .needs-validation -->
  
  _HTML_;
  
    }
  
    static function CreatePagination (
      int $page_identity
    ): void
    {

      if ($page_identity !== 0) {
        echo <<<_HTML_
  <hr class="my-4">
  
  <nav class="container text-center my-4" aria-label="Search results pages">
    <div class="row justify-content-md-center">
      <div class="col-auto text-center">
        <ul class="pagination">
          <li class="page-item disabled">
            <a class="page-link">前</a>
          </li>
  
          <li class="page-item active" aria-current="page">
            <a class="page-link" href="#">1</a>
          </li>
  
          <li class="page-item"><a class="page-link" href="#">2</a></li>
          <li class="page-item"><a class="page-link" href="#">3</a></li>
          <li class="page-item"><a class="page-link" href="#">4</a></li>
          <li class="page-item"><a class="page-link" href="#">5</a></li>
          <li class="page-item"><a class="page-link" href="#">6</a></li>
          <li class="page-item"><a class="page-link" href="#">7</a></li>
          <li class="page-item"><a class="page-link" href="#">8</a></li>
          <li class="page-item"><a class="page-link" href="#">9</a></li>
          <li class="page-item"><a class="page-link" href="#">10</a></li>
  
          <li class="page-item">
            <a class="page-link" href="#">次</a>
          </li>
        </ul>
      </div>
    </div> <!-- / .row -->
  </nav>
  
  _HTML_;

      } // if ($page_identity !== 0)
  
    }
  
    static function CreateFooter (
      string $copyright_year,
      string $copyright_holder,
      array &$link_items
    ): void
    {
      echo <<<_HTML_
      <footer class="my-5 pt-5 text-body-secondary text-center text-small">
        <p class="mb-1">Copyright &copy; {$copyright_year} {$copyright_holder}. All rights reserved.</p>
        <ul class="list-inline">
  
  _HTML_;

      foreach ($link_items as $key => $value) {
        echo <<<_HTML_
<li class="list-inline-item"> 
  <form id="{$value['formId']}" method="POST">
    <input type="hidden" name="page-identity" value="{$value['pageIdentity']}">
  </form>
  <a href="#" id="{$value['anchorId']}">{$value['textContent']}</a>
</li>

_HTML_;

      }

      echo <<<_HTML_
    </ul>
  </footer>
</div> <!-- / .container -->
  
_HTML_;
  
    }
}

bs-frame-class.php

filemaker-data-api-class.php

<?php

class FileMakerDataApi
{
    public $host, $version, $database, $username, $password, $layout;
    public $bearer_session_token;

    function __construct (string $host, string $version)
    {
        $this->host     = $host;
        $this->version  = $version;
    }

    /**
     * リクエスト
     **/

    // ログイン
    public function login (string $database, string $username, string $password): string
    {
		$this->database	= $database;
		$this->username = $username;
		$this->password = $password;

		$auth_value         = $username . ':' . $password;
		$authorization      = 'Authorization: Basic ' . base64_encode($auth_value);
		$content_type       = 'Content-Type: application/json';
		$curlopt_httpheader = array($authorization, $content_type);

		$endpoint        	= "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions";
		
		return self::executeCurl($endpoint, 'POST', $curlopt_httpheader);
	}

    // ログアウト
    public function logOut(string $database, string $bearer_session_token): string
    {
		$endpoint    = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions/{$bearer_session_token}";

		return self::executeCurl($endpoint, 'DELETE');
	}

    // データベースセッションの検証
	public function validateSession (string $session_token): string
    {
		$authorization      = 'Authorization: Bearer ' . $session_token;
		$curlopt_httpheader = array($authorization);
		$endpoint        	= "https://{$this->host}/fmi/data/{$this->version}/validateSession";

		return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
	}

	// レコード範囲の取得
	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);
	}

	// 検索の実行
	public function findRecords(
		string $database,
		string $layout,
		string $bearer_session_token,
		string $request_body
		): string
	{
		$authorization      = 'Authorization: Bearer ' . $bearer_session_token;
		$content_type       = 'Content-Type: application/json';
		$curlopt_httpheader = array($authorization, $content_type);
		$endpoint        	= "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/_find";

		return self::executeCurl($endpoint, 'POST', $curlopt_httpheader, $request_body);
	}

	// スクリプトの実行
	public function executeScript(
		string $database,
		string $layout,
		string $bearer_session_token,
		string $script_name,
		string $script_parameters = ''
		): string
	{
		$authorization      = 'Authorization: Bearer ' . $bearer_session_token;
		$curlopt_httpheader = array($authorization);
		$script_parameters	= !empty($script_parameters) ? '?script.param=' . json_encode(json_decode($script_parameters)) : '';
		$endpoint        	= "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/script/{$script_name}{$script_parameters}";
		
		return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
	}

    /**
     * ユーティリティ
     **/

    // レスポンスコードの取得
	public function getMessagesCode (string $response): string
    {
		$response_array = self::json2array($response);
		return $response_array['messages'][0]['code'];
	}

    // Bearer Session Token 取得
    public function getBearerSessionToken (string $response): string
    {
		$response_array = self::json2array($response);
		$this->bearer_session_token = $response_array['response']['token'];

		return $this->bearer_session_token;
	}

    // JSON を 配列へ変換
	public function json2array (string $json): array
    {
		$json   = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
		return json_decode($json, true);
	}

    // cURL 実行
    static function executeCurl(string $curlopt_url, string $curlopt_customrequest, array $curlopt_httpheader = [], string $current_postfields = ''): string
    {
		$current_postfields	= !empty($current_postfields) ? json_encode(json_decode($current_postfields)) : '{}';

		$curl   = curl_init();
	
		curl_setopt_array($curl, array(
			CURLOPT_URL => $curlopt_url,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_ENCODING => '',
			CURLOPT_MAXREDIRS => 10,
			CURLOPT_TIMEOUT => 0,
			CURLOPT_FOLLOWLOCATION => true,
			CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
			CURLOPT_CUSTOMREQUEST => $curlopt_customrequest,
			CURLOPT_POSTFIELDS => $current_postfields,
			CURLOPT_HTTPHEADER => $curlopt_httpheader,
		));
	
		$response   = curl_exec($curl);
	
		curl_close($curl);
		return $response;
	}
}

php-functions.php

preferences.php

<?php

$html_contents_json_file  = __DIR__ . '/../json/html-contents.json';
$temp_array               = json_get_element($html_contents_json_file);

// for HtmlBegin(), LoadColorModesSvg(), ColorModes()
$color_modes_js   = $temp_array['contents']['colorModesJs'];
$description      = $temp_array['contents']['description'];
$author           = $temp_array['contents']['author'];
$title            = $temp_array['contents']['title'];
$bootstrap_css    = $temp_array['contents']['bootstrapCss'];
$bs_css_integrity = $temp_array['contents']['bsCssIntegrity'];
$bs_frame_css     = $temp_array['contents']['bsFrameCss'];
$custom_css       = [];
foreach ($temp_array['contents']['customCss'] as $key => $value) {
  array_push($custom_css, $value['location']);
}

// for MainBegin()
$logo_svg       = $temp_array['contents']['logoSvg'];
$logo_svg_width = $temp_array['contents']['logoSvgWidth'];
$page_heading   = [];
$page_lead      = [];
foreach ($temp_array['pageContents'] as $key => $value) {
    array_push($page_heading, $value['heading']);
    array_push($page_lead, $value['lead']);
}

$form_heading       = [];
$form_action        = [];
$form_button_color  = [];
$form_button_text   = [];
foreach ($temp_array['formContents'] as $key => $value) {
    array_push($form_heading, $value['heading']);
    if ($value['action'] === 'PHP_SELF')
        $value['action'] = "\$_SERVER['PHP_SELF']";
    array_push($form_action, $value['action']);
    array_push($form_button_color, $value['buttonColor']);
    array_push($form_button_text, $value['buttonText']);
}

// for InfoItem(), GetInfo()
$info_heading         = $temp_array['contents']['infoHeading'];
$info_number_of_items = $temp_array['contents']['infoNumberOfItems'];

$info_item_heading  = [];
$info_item_content  = [];
foreach ($temp_array['infoItems'] as $key => $value) {
  array_push($info_item_heading, $value['heading']);
  array_push($info_item_content, $value['content']);
}

// for CreateForm(), CreatePagination(), MainEnd()
$form_controls           = $temp_array['formControls'];

for ($i = 0; $i < count($form_controls); $i++) {
  $form_controls[$i]['disabled']  = $page_indentity >= 2 ? 'disabled' : '';
}

$form_preferences = [
  $form_heading[$page_indentity],
  $form_action[$page_indentity],
  $form_button_color[$page_indentity],
  $form_button_text[$page_indentity]
];

// for CreateFooter()
$copyright_year   = $temp_array['contents']['copyrightYear'];
$copyright_holder = $temp_array['contents']['copyrightHolder'];

$link_items       = $temp_array['linkItems'];

// for HtmlEnd()
$bootstrap_js     = $temp_array['contents']['bootstrapJs'];
$bs_js_integrity  = $temp_array['contents']['bsJsIntegrity'];
$custom_js        = [];
foreach ($temp_array['contents']['customJs'] as $key => $value) {
  array_push($custom_js, $value['location']);
}

html-contents.json

{
    "contents" : {
        "colorModesJs" : "https://getbootstrap.com/docs/5.3/assets/js/color-modes.js",
        "description" : "FileMaker Data API テスト 及び サンプル",
        "author" : "",
        "title" : "records - Edit Record",
        "bootstrapCss" : "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css",
        "bsCssIntegrity" : "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH",
        "bsFrameCss" : "./css/bootstrap-common.css",
        "customCss" :
        [
            {
                "location" : "./css/fmda-form.css"
            }
        ],
        "infoHeading" : "dataInfo",
        "infoNumberOfItems" : 6,
        "copyrightYear" : "2025",
        "copyrightHolder" : "FileMaker Data API を使う",
        "bootstrapJs" : "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js",
        "bsJsIntegrity" : "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
        "customJs" :
        [
            {
                "location" : "./js/fmda-form-check.js"
            },
            {
                "location" : "./js/fmda-select-page.js"
            }
        ],
        "logoSvg" : "https://www.mlbstatic.com/team-logos/league-on-dark/1.svg",
        "logoSvgWidth" : "72"
    },
    "pageContents" : [
        {
            "heading" : "records - Create Record",
            "lead" : "Claris FileMaker Data API のリクエスト records - Create Record のテスト。フォームから PHP を実行して、FileMaker Server へリクエストを送信して新規レコードを作成します。"
        },
        {
            "heading" : "records - Edit Record",
            "lead" : "Claris FileMaker Data API のリクエスト records - Edit Record のテスト。フォームから PHP を実行して、FileMaker Server へリクエストを送信してレコードを更新します。"
        },
        {
            "heading" : "records - Delete Record",
            "lead" : "Claris FileMaker Data API のリクエスト records - Delete Record のテスト。フォームから PHP を実行して、FileMaker Server へリクエストを送信してレコードを削除します。"
        },
        {
            "heading" : "records - Duplicate Record",
            "lead" : "Claris FileMaker Data API のリクエスト records - Dupulicate Record のテスト。フォームから PHP を実行して、FileMaker Server へリクエストを送信して現在のレコードを複製します。"
        }
    ],
    "formContents" : [
        {
            "heading" : "チーム - レコード作成",
            "action" : "PHP_SELF",
            "buttonColor" : "btn-primary",
            "buttonText" : "新規レコード作成"
        },
        {
            "heading" : "チーム - レコード編集",
            "action" : "PHP_SELF",
            "buttonColor" : "btn-warning",
            "buttonText" : "レコード更新"
        },
        {
            "heading" : "チーム - レコード削除",
            "action" : "PHP_SELF",
            "buttonColor" : "btn-danger",
            "buttonText" : "レコード削除"
        },
        {
            "heading" : "チーム - レコード複製",
            "action" : "PHP_SELF",
            "buttonColor" : "btn-warning",
            "buttonText" : "レコード複製"
        }
    ],
    "infoItems" : [
        {
            "heading" : "ソリューション",
            "content" : "MLB サンプル"
        },
        {
            "heading" : "レイアウト",
            "content" : "standings"
        },
        {
            "heading" : "テーブル",
            "content" : "standings"
        },
        {
            "heading" : "テーブルのレコード数",
            "content" : "27"
        },
        {
            "heading" : "現在のレコード数",
            "content" : "27"
        },
        {
            "heading" : "取得したレコード数",
            "content" : "27"
        }
    ],
    "formControls" :
    [
        {
            "id" : "mlb_site_id",
            "label" : "MLB 公式サイト ID",
            "type" : "text",
            "name" : "mlb_site_id",
            "placeholder" : "100",
            "required" : "1",
            "disabled" : "",
            "feedback" : "MLB 公式サイトの チーム ID を入力してください。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "year",
            "label" : "シーズン",
            "type" : "text",
            "name" : "year",
            "placeholder" : "2024",
            "required" : "1",
            "disabled" : "",
            "feedback" : "シーズン(西暦)を入力してください。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "league",
            "label" : "リーグ",
            "type" : "select",
            "name" : "league",
            "placeholder" : "",
            "required" : "1",
            "disabled" : "",
            "feedback" : "リーグを選択してください。",
            "option" : [
                {
                    "value" : "アメリカン・リーグ"
                },
                {
                    "value" : "ナショナル・リーグ"
                }
            ]
        },
        {
            "id" : "division",
            "label" : "地区",
            "type" : "select",
            "name" : "division",
            "placeholder" : "",
            "required" : "1",
            "disabled" : "",
            "feedback" : "地区を選択してください。",
            "option" : [
                {
                    "value" : "東地区"
                },
                {
                    "value" : "中地区"
                },
                {
                    "value" : "西地区"
                }
            ]
        },
        {
            "id" : "team",
            "label" : "チーム名",
            "type" : "text",
            "name" : "team",
            "placeholder" : "",
            "required" : "1",
            "disabled" : "",
            "feedback" : "チーム名を入力してください。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "wins",
            "label" : "勝利数",
            "type" : "text",
            "name" : "wins",
            "placeholder" : "81",
            "required" : "1",
            "disabled" : "",
            "feedback" : "レギュラーシーズンの勝利数を入力してください。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "losses",
            "label" : "敗戦数",
            "type" : "text",
            "name" : "losses",
            "placeholder" : "81",
            "required" : "1",
            "disabled" : "",
            "feedback" : "レギュラーシーズンの敗戦数を入力してください。。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "winning_percentage",
            "label" : "勝率",
            "type" : "text",
            "name" : "winning_percentage",
            "placeholder" : ".500",
            "required" : "",
            "disabled" : "",
            "feedback" : "",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "runs_scored",
            "label" : "得点",
            "type" : "text",
            "name" : "runs_scored",
            "placeholder" : "",
            "required" : "1",
            "disabled" : "",
            "feedback" : "レギュラーシーズンの得点を入力してください。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "runs_allowed",
            "label" : "失点",
            "type" : "text",
            "name" : "runs_allowed",
            "placeholder" : "",
            "required" : "1",
            "disabled" : "",
            "feedback" : "レギュラーシーズンの失点を入力してください。",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "winning_percentage",
            "label" : "ピタゴラス勝率",
            "type" : "text",
            "name" : "pythagorean_expectation",
            "placeholder" : "",
            "required" : "",
            "disabled" : "",
            "feedback" : "",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "expected_win_loss",
            "label" : "X-W/L",
            "type" : "text",
            "name" : "expected_win_loss",
            "placeholder" : "",
            "required" : "",
            "disabled" : "",
            "feedback" : "",
            "option" : [
                {
                    "value" : ""
                }
            ]
        },
        {
            "id" : "winning_percentage_difference",
            "label" : "勝率差分",
            "type" : "text",
            "name" : "winning_percentage_difference",
            "placeholder" : "",
            "required" : "",
            "disabled" : "",
            "feedback" : "",
            "option" : [
                {
                    "value" : ""
                }
            ]
        }
    ],
    "linkItems" : [
        {
            "pageIdentity" : 0,
            "formId" : "gotoCreateRecord",
            "anchorId" : "createRecord",
            "textContent" : "レコード作成"
        },
        {
            "pageIdentity" : 1,
            "formId" : "gotoEditRecord",
            "anchorId" : "editRecord",
            "textContent" : "レコード編集"
        },
        {
            "pageIdentity" : 2,
            "formId" : "gotoDeleteRecord",
            "anchorId" : "deleteRecord",
            "textContent" : "レコード削除"
        },
        {
            "pageIdentity" : 3,
            "formId" : "gotoDuplicateRecord",
            "anchorId" : "duplicateRecord",
            "textContent" : "レコード複製"
        }
    ]
}

fmda-form-check.js

fmda-select-page.js

'use strict';

const createRecordForm = document.querySelector('#gotoCreateRecord');
const editRecordForm = document.querySelector('#gotoEditRecord');
const deleteRecordForm = document.querySelector('#gotoDeleteRecord');
const duplicateRecordForm = document.querySelector('#gotoDuplicateRecord');

const createRecord = document.querySelector('#createRecord');
const editRecord = document.querySelector('#editRecord');
const deleteRecord = document.querySelector('#deleteRecord');
const duplicateRecord = document.querySelector('#duplicateRecord');

createRecord.addEventListener('click', function( ) {
    createRecordForm.submit();
});
editRecord.addEventListener('click', function( ) {
    editRecordForm.submit();
});
deleteRecord.addEventListener('click', function( ) {
    deleteRecordForm.submit();
});
duplicateRecord.addEventListener('click', function( ) {
    duplicateRecordForm.submit();
});

フッタのリンク部分

 フッタ部分は、bs-builder-class.phpBsBuilder クラス、スタティックメソッド CreateFooter() に記述されています。
id 付きの <a> タグの前に、type="hidden" の form コントロールを持つ、フォームが仕込まれており、こちらにもそれぞれ id が設定されていて、ページの識別子と紐付けています。

id は、html-contents.jsonlinkItems JSON配列内で設定されており、これを、preferences.php で、$link_items 配列として展開しています。

 これを fmda-select-page.js でクリックを監視。クリックされた id に基づいて、name="page-identity" の値を、POST で送信しています。

これに、index.php の以下が反応し、ページを識別します。

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

 これで、リクエスト機能なしのページは完成です。シングルページで、4つのフォームを表示できるようになりました。

 次回から、FileMaker Data API のリクエストを追加していきます。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?