Chapter 2
データベースへのクエリーと一覧表示

まず最初にシンプルなページを作りながら、設定した内容がどのように機能するのかを少しずつ見ていくことにしましょう。この章と次の章は、主に、データベースにあるデータをWebページの上に展開するための設定を見ていきます。また、VirtualBoxによるINTER-Mediator-Server VMの利用方法を詳しく説明し、次の章以降は、VMの使用方法についてはあまり触れません。この章の中で十分に理解してから次に進むようにしてください。

2-1データベースからの取り出し設定

データベースからのクエリ(あるいは読み出し)の処理は、データベースを利用する基本でもあります。加えて、単に読み出し結果をブラウザー上に表示するだけでなく、見やすく表示させるということも重要です。レイアウトを厳密に構成できることがHTMLの特徴ですから、データベースの内容をきれいに構成してWebブラウザーで表示させることが可能になります。MVCモデルのView部分をHTML関連技術で構成するのは、とても重要な意味を持つことなのです。それでは、最初に、さまざまな設定のための基本について解説します。

INTER-Mediatorとデータベース

 INTER-Mediatorは、データベースを利用したWebアプリケーション開発のためのフレームワークです。INTER-Mediatorとデータベースは別々の存在として、インストール等されている必要があります。また、INTER-Mediatorでのアプリケーションを作る上では、データベース上にアプリケーションの稼働が可能なテーブル設計等(一般には「スキーマ設計とその適用」)が完了している必要があります。テーブルの作成など、データベース側の運用を直接サポートする機能は現在のVer.5.0のINTER-Mediatorには含まれていません。

 利用可能なデータベースは大きく分けて2種類があります。PHP言語でのデータベース抽象化レイヤーのひとつである「PDO(PHP Data Objects)」を利用する方法と、FileMaker Serverを利用する方法です。PDOでは、さらにデータベースエンジンごとにドライバーが内部で用意されていますが、Ver.5.7現在、MySQL、PostgreSQL、SQLite、SQL Serverの4つのデータベースに関して、開発時にテストケースを適用して確認をしています。PDOがサポートするその他のデータベースエンジン(例えば、Oracleなど)は、理論上は利用可能ですが、開発側でテストを実施していないために実際にサンプル等での動作保証はできません。原則、いずれもSQLデータベースである点での違いは薄いのですが、細かな点での記述方法の違いなどもあり、INTER-Mediatorで提供された素材そのままで運用することを誰も確認していない状況と考えてください。Ver.5.0以降では、FileMaker ServerはVer.11以降をサポートします。

 なお、本コースでは、原則として、INTER-Mediator-Server VMに搭載されているMySQLを利用して演習を進め、データベースエンジンごとに違いがある部分については、その都度説明をします。実際にデータベースを利用して開発をされた方はご存知の通り、同じSQLデータベースでも、けっこう違いが大きいものです。INTER-Mediatorでのデータベースの扱いとしては、ひとつの考え方として、「INTER-Mediatorが必要なSQLステートメントを生成してデータベースに投げる」というイメージを考えてください。そのため、INTER-Mediator側の作業に入ると、データベースは完全に抽象化されて、データベースごとの違いを意識せずとも使えるようになっています。概念的に同じ特性を持つデータベースとして考えて差し支えないものになっています。INTER-Mediatorがデータベースエンジンの間の細かな違いを吸収していると考えてけっこうです。特に、基本的にSQLデータベースではないFileMakerとMySQLを、同じような手法で利用できるようになっています。

PDOでの接続に必要な情報

 MySQLを始めとするPDOを利用した接続で必要になる情報は、必要な設定を行う前に確認しておく必要があります。MySQLとPostgreSQLについては、ソケット経由での接続と、TCP/IPのポートに対して接続する方法があります。データベースとWebサーバーが同一のホストの場合、どちらでも利用できます。異なるホストの場合は、ポート接続を行います。SQLiteについては、ファイルを直接読み書きしているので、同一のホストである必要があります。

 いずれのデータベースについても、データベースエンジン自体の指定だけでなく、「データベース名」の指定が必要になります。一般に、データベースエンジンは、データベースを運用するソフトウェアを示す用語ですが、ひとつのデータベースエンジンは、同時に複数のデータベースを運用することが可能です。SQLデータベースでは、ひとつのデータベースの中に、複数のテーブルやビューといったエンティティを定義でき、テーブルには複数のフィールドが定義されていて、データの記録ができるようになっています。

 INTER-MediatorでPDOを利用する場合、合計5つの設定項目を確定させる必要があります。これらの実際の設定方法は、この後に、演習の中で行うことにします。コロン(:)の左側が設定の種類を示すキーワードで、右側はその設定値です。キーワードはINTER-Mediatorで決められたものですが、値は状況により変わります。PDOを使う場合には、db-classに対する値は「PDO」で一定です。dsnは、データベースに接続するためのさまざまな情報をひとまとめにしたもので、すぐ後に説明します。userとpasswordは、データベースを利用するために必要なアカウントの情報で、データベースのセットアップ時に指定しているものです。optionsには、一般には設定はなにもしなくてもかまいません。

リスト2-1-1 MySQLを利用する場合のデータベース設定
(ソケットを利用する接続の場合)
db-class:PDO
dsn:mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=test_db;charset=utf8mb4
user:web
password:password
options:(設定不要)

(ホスト名を指定する接続の場合)
dsn:mysql:host=localhost;dbname=test_db;charset=utf8mb4

 dsnについて説明をします。dsnは、半角のセミコロン(;)で区切った文字列で、それぞれは「キーワード=値」の形式のデータが含まれたものです。dsnはData Source Nameの略ですが、単に名前だけでなく、さまざまな情報を指定します。最初の「mysql」は、データベースエンジンの種類であり、MySQLの場合は常に「mysql」です。

 ソケットを使う場合には、「unix_socket=パス」の形式で記述します。パスは、セットアップの方法やあるいは設定ファイルの書き方で変わってきます。TCP/IPのポートに接続する場合には、「host=ホスト名」によってデータベースエンジンが稼働しているホストのIPアドレスやホスト名、FQDN等を指定します。通常は、MySQLはポート番号3306で稼働していますが、既定のポート番号の場合はポート番号の指定は不要です。サーバーの設定により異なるポートで運用している場合には「port=ポート番号」の記述も追加します。unix_socketとhostの指定は両立せず、どちからのみを指定するのが原則です。

 接続先のデータベースは「dbname=データベース名」で指定します。データベース名は、実際に使うデータベース名に変更します。本コースでは、サンプルアプリケーションを稼働するためのデータベース「test_db」をそのまま利用しますので、常に「dbname=test_db」で利用します。

 データベースで利用する文字セットを「charset=文字セット名」で記述します。MySQLの場合は、このdsnの設定に文字セットを可能な限り設定することをお勧めします。一般には、文字セット名は「utf8」でかまいませんが、絵文字や一部の漢字にあるような4バイトのUnicode文字もサポートするために「utf8mb4」という文字セットをMySQL Ver.5.5.3以降でサポートする記述を利用します。これ以前のMySQLでは、utf8しか使えません。4バイトの文字というのは、32ビットコードという意味ではなく、UTF-8での文字表現で4バイトを使用する文字ということです。従来からよく利用されてきた一般的な文字列の多くは日本語の場合UTF-8では3バイトになります。しかしながら、「𥔎」という文字は、Unicodeでは、U+2550Eというコードが割り当てられており、UTF-8でエンコードした場合、F0 A5 94 8Eという4バイトでの表現となります。OSがサポートする文字種が増えているだけに、可能な限りutf8mb4で運用する方が望ましいと言えます。

 MySQLとの接続に必要なアカウントの作成と、アクセス権の設定は、例えばリスト2-1-2のように行います。このユーザー「web」はlocalhost経由での接続が許されており、さらにGRANTステートメントで指定されたステートメントの実行のみが、データベースtest_dbに対して定義されています。

リスト2-1-2 MySQLでユーザーに対してデータ処理権限を与える
CREATE USER 'web'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, DELETE, UPDATE ON TABLE test_db.* TO 'web'@'localhost';

 PostgreSQLを利用する場合の設定はリスト2-1-3の通りです。MySQLと原則同一ですが、データベースエンジンが違うので、dsnの書き方が異なり、「pgsql」で始めます。userとpasswordは、データベース側に定義した利用可能なアカウントを指定します。文字セットの指定は、INTER-Mediator側の指定では行わないでも一般には大丈夫です。データベースの設定でエンコード指定が行われているのが一般的です。なお、PDOを利用したPostgreSQL利用時に、ソケット接続のための、dsnを「pgsql:user=web dbname=test_db password=password」のように記述すれば良いとなっていますが、INTER-Mediatorでは利用しているAPIの都合上、Ver.5.0現在、この方法での接続はできません。hostを利用して接続先を指定してください。

リスト2-1-3 PostgreSQLを利用する場合のデータベース設定
db-class:PDO
dsn:pgsql:host=localhost;port=5432;dbname=test_db
user:web
password:password
options:(設定不要)
リスト2-1-4 PostgreSQLでのユーザー定義とアクセス権設定の例
CREATE USER web PASSWORD 'password';
GRANT ALL PRIVILEGES ON SCHEMA im_sample TO web;
GRANT ALL PRIVILEGES ON im_sample.person TO web;
GRANT ALL PRIVILEGES ON im_sample.postalcode TO web;
		:

 SQLiteを利用する場合、データベース自体はファイルとして提供され、ドライバーがそのファイルに直接的にやりとりすることになります。リスト2-1-5に設定をまとめますが、ファイルアクセスということが原則のため、データベース自体にアカウントの仕組みはなく、userとpasswordは指定する必要がありません。dsnには、SQLiteを使用することを示す「sqlite:」の文字列と、それに続いてデータベースファイルの絶対パスを記述します。設定はこれだけです。エンコードについても、SQLite Ver.3ではデータベース自体がUTF-8を前提としているため、特に指定する必要はありません。

リスト2-1-5 SQLiteを利用する場合のデータベース設定
db-class:PDO
dsn:sqlite:/var/db/im/sample.sq3
user:(設定不要)
password:(設定不要)
options:(設定不要)

 SQL Serverでのデータベース設定はdsnはシンプルにserverキーでホストを指定し、databaseキーでデータベース名を指定するだけで可能です。また、GRANTも現在のデータベース内のオブジェクトにまとめて設定することができるので、シンプルな記述で可能です。

リスト2-1-6 SQL Serverを利用する場合のデータベース設定
db-class:PDO
dsn:sqlsrv:server=localhost;database=test_db
user:web
password:password
options:(設定不要)
リスト2-1-7 SQL Serverでのアクセス権の設定例
CREATE DATABASE test_db COLLATE Japanese_CI_AI;
USE test_db;
CREATE LOGIN web WITH PASSWORD='password', CHECK_POLICY=OFF;
CREATE USER web;
GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE TO web;
GO

FileMaker Serverへの接続

 FileMaker Serverは、Web共有の設定をしておく必要があります。単にサーバーをインストールするだけではなく、Web共有可能にセットアップしなければなりません。特に、FileMaker Server 13以降では、OSに含まれているWebサーバーとの協調動作が難しくなっており、インストール時に注意すべき点が数多くあります。なお、本コースの購入者の方々に対しては、FileMaker Serverそのもののサポートも行いますので、うまく稼働ができない場合には、筆者まで連絡を取ってください。

図2-1-1 FileMaker Serverの管理コンソールでWeb共有を有効にする

 そして、サーバーソフトウェアの管理コンソールで、XML共有とPHP共有を有効にしておく必要があります。また、WebDirectについては、有効にしておく必要はありません。もちろん、PHP共有やWebDirectをINTER-Mediatorとは別に利用するのであれば、オンにしておきます。

図2-1-2 FileMaker Serverの管理コンソールでXML共有を有効にする
図2-1-3 FileMaker Serverの管理コンソールでPHP公開を有効にする

 FileMaker Serverで公開するデータベースについては、XML共有からのアクセスができるようにしておく必要があります。「ファイル」メニューの「管理」の「セキュリティ」を選択して、初期状態にあるadmin以外に、新たにユーザーを作成するのが良いでしょう。また、ゲストでの運用も可能な限り行わない方が良いでしょう。ここでは、webという名前のユーザーを選択しています。そして、このユーザーはデータの入出力ができればいいので、最大でも「データ入力のみ」のアクセス権セットを選択しておきます。可能であれば、より権限の狭いアクセス権セットにする方が好ましいでしょう。

図2-1-4 INTER-Mediatorから利用する専用のユーザーを定義する

 そして、INTER-Mediatorから利用するユーザーのアクセス権セットについては、FileMaker Pro上で拡張アクセス権の設定を行います。「XML Web共有でのアクセス - FMSのみ」の拡張アクセス権を設定します。このように、アクセス権の設定が変わるので、「データ入力のみ」のアクセス権セットを既定値のまま保持したい場合は、このアクセス権セットを複製して、複製した方のセットをINTER-Mediatorから利用するユーザーに割り当ています。さらに、このデータベースをFileMaker Proから開くには、「FileMakerネットワークによるアクセス」もチェックを入れます。INTER-Mediatorに付属しているTestDB.fmp12では、adminユーザーにのみ「FileMakerネットワークによるアクセス」のチェックを入れてあります。

図2-1-5 データベースのユーザーに対するXML利用を許可する

 FileMaker Serverおよびデータベースに関して以上の準備をすれば、INTER-Mediator側の設定を決めることができます。FIleMakerデータベースについては、リスト2-1-8のような項目を設定します。設定項目は多くなりますが、FileMaker ServerのXML共有を利用するための設定を基本的にすべて設定可能にしているためです。

リスト2-1-8 FileMaker Serverを利用する場合のデータベース設定
db-class:FileMaker_FX
database:TestDB
user:web
password:password
server:192.168.56.1
port:80
protocol:http
datatype:FMPro13

 db-classは、INTER-MediatorにFileMaker Server用の機能を利用するように指定する部分と考えてください。databaseは、FileMaker Serverで公開されているデータベースのファイル名を指定します。拡張子はあってもなくてもかまいません。userとpasswordは、FileMakerのデータベースに定義した、データの読み書き可能なアカウントのものを指定します。serverは、FileMaker Serverが稼働しているホストのIPアドレスや、あるいはホスト名を指定します。同一のサーバーであればlocalhostや127.0.0.1を指定します。portは、FileMaker Serverの設定に依存します。FileMaker Server 13以降の場合は、一般には80になると思われます。そして、protocolもFileMaker Serverの設定に依存しますが、一般にはhttpになると思われます。datatypeについては、サーバーのバージョンに応じたものを指定するような雰囲気もあるかもしれませんが、FMPro12以降は特に動作に違いはありませんので、あまり気にすることはありません。「FMPro12」等を設定しておけば当面は問題ないと思われます。

 以上のように、FileMakerでは、基本的にデータベース名、サーバーのIPアドレス、そしてデータベースに設定したXML共有が可能なアカウントを、INTER-Mediatorに指定する必要があるということです。

このセクションのまとめ

 このセクションでは、INTER-Mediatorで使用するデータベースに関して、INTER-Mediatorに設定する情報にどのようなものがあるかを紹介しました。ここで集めた情報を実際に設定する方法は、この後引き続いて説明を行います。

2-2ページ構築のための基本設定

 サンプルデータベースにある郵便番号のテーブルからその一覧を表示するWebページを作成します。フィールドの値をページ上に表示させることや、複数のレコードが取得された場合の繰り返し処理を説明します。ここでは、さまざまな設定をひとつひとつ追っていくことにします。

Webページの基本構成

 INTER-Mediatorで作成するWebページは、最終的にはブラウザーでアクセスした結果、データベースの内容が表示されたり、あるいはデータベースへの入力や編集ができるようになっている必要があります。そうした働きの全体像を示したのが図2-2-1です。Webアプリケーションとして共通の処理をフレームワークとして提供し、用途によって異なる部分をその都度開発するというの基本です。まず、開発に先立って、スキーマが適用されたデータベースがあることが前提です。これら以外に、HTMLで記述する「ページファイル」と、PHPで記述する「定義ファイル」を用意します。

図2-2-1 INTER-Mediatorと開発物の構成

 ページファイルは、実際にブラウザーが解釈してレイアウトされたページとしてレンダリング可能なHTMLであり、最終的なページを構成するためのテンプレート、つまり、データを埋め込む前の状態を記述したものと考えてください。例えば、データベースの内容を表にしたいのなら、TABLE、TR、TDといったタグで、1レコード分の表示をどのようにするのかをHTMLで記述するのが典型的な例です。

 一方、定義ファイルには、データベースの接続に関する設定を始めとして、さまざまな動作の設定を記述します。ページファイルにすべてを記述しない理由のひとつは、ある種の設定の共通化を行う場合を想定しているからです。例えば、ひとつの定義ファイルを複数のページファイルで利用するといった状況です。また、後で説明するように、データベースにあるデータを単にテーブルとして扱うのではなく、「コンテキスト」として、抽象化された対象として取り扱うことが動作の基礎をなしており、定義ファイルはコンテキストを定義するファイルとして存在しています。

 図2-2-1では、フレームワークが提供する部分と、さらにフレームワークの動作を拡張したり、間に入って処理系の違いを仲介するデータコンバーターなどの拡張を示す部分についても記載があります。これらの拡張コンポーネントについては、コースの後半に解説を行います。ここよりいくつかの章は、ページファイルや定義ファイルを作成することで実現する範囲の機能を説明します。

 実際に稼働させると、ページファイルとフレームワークの一部がブラウザーにダウンロードされて、ページの生成を始めます。その途中で必要に応じてデータベース処理を行います。

定義ファイルに定義するコンテキスト

 実際のファイルの記述方法を説明する前に、まず、「コンテキスト」の概念を説明しましょう。図2-2-2は、コンテキストを中心とした、INTER-MediatorによるWebページの構成です。データベースのデータをそのままページに持ち込むではなく、コンテキストという中間的なものを定義します。コンテキストの実体、すなわち、コンテキストから得られるデータは、テーブル形式のデータ(つまり、「リレーション」)と考えてください。

図2-2-2 コンテキストの概念

 このコンテキストは、テーブルと同一ではなく、意味が付加されたテーブル形式のデータです。ここでの意味というのは、具体的には検索条件や並べ替えフィールドの指定、そしてそれらの条件を適用した結果、得られたテーブル形式のデータを示すものです。つまり、成り立ちに意味があるデータです。例えば、住所録のテーブルがあるとします。その中で、利用者が興味があるのは、「学校の同期生」「家族と親戚」「取引先関係」など、その一部のデータであり、一部を抽出するためには意味をきちんと定義しなければなりません。住所録に対してなんらかの意味を与えることによって、得られるデータをコンテキストとします。もちろん、適切なフィールドの定義や、きちんとしたデータの入力など、さまざまな条件を満たさないと、コンテキストは完成しませんが、テーブルそのものではなく、意味を付与したコンテキストを中心にして、Webページを構成するという手法をINTER-Mediatorでは採用しています。

 そして、ページファイルの一部分が、コンテキストに対応付けられます。その規則についてはこの後すぐに説明をします。実際にブラウザー上で構成されるHTMLは、テンプレートとしてのページファイルの内容と、コンテキストで得られるデータを合成したものです。

定義ファイルの記述方法

 定義ファイルはPHPで記述します。PHPの文法を駆使したプログラムを記述するのではなく、主として、キーと値のセット(連想配列)による、コンテキストの定義やデータベースの接続のための設定などを記述します。したがって、プログラムを作成する知識は必要ではありませんが、一方でPHPのルールに従った連想配列を記述する必要があるため、基本文法についてはある程度知っていると作業はスムーズでしょう。リスト2-2-1は定義ファイルの記述例です。

リスト2-2-1 定義ファイルの記述例
<?php
require_once('INTER-Mediator/INTER-Mediator.php');

IM_Entry(
    // ここから第1引数
    array(
        array(
            'name' => 'postalcode', 'table' => 'postalcode', 'view' => 'postalcode',
            'records' => 10, 'maxrecords' => 100,
            'paging' => true, 'key' => 'id',
            'query' => array(
                array( 'field' => 'f3', 'value' => '1%', 'operator' => 'LIKE' )
            ),
            'sort' => array(
                array( 'field' => 'f3', 'direction' => 'ASC' )
            ),
            'repeat-control' => 'confirm-insert confirm-delete',
        ),
    ),
    // ここから第2引数
    array(
    ),
    // ここから第3引数
    array( 'db-class' => 'PDO', 'dsn' => 'mysql:host=localhost;charset=utf8mb4', 
             'user' => 'web', password => 'password' ),
    // ここから第4引数
    2
);

 定義ファイルは拡張子が.phpのファイルに保存します。そして、中身はPHP言語なので、冒頭には「<?php」の記述があります。続くrequire_onceにより、INTER-Mediatorの本体を読み込みます。サーバーのファイルシステム上で、この定義ファイルと、INTER-MediatorフォルダーにあるINTER-Mediator.phpファイルとの間の相対パスを記述します。定義ファイルと同じフォルダーにINTER-Mediatorフォルダーがあるので、指定のようなパスになります。そして、定義ファイルの残りの部分は、IM_Entry関数の呼び出しです。この関数の呼び出しを行うことは常に決まっています。引数は表2-2-1に示します。連想配列のキーに相当する文字列はすでに決められたものとなっており、決められていないキーは、デバッグ時にはエラーを出すようにしています。キーに指定する文字列とその機能は、本コースで順次説明します。

引数設定する値解釈される内容
1コンテキスト定義の配列コンテキスト定義は連想配列で記述する
2オプション設定の配列コンテキスト外部に設定する内容
3データベース接続の配列データベース接続に必要な情報
4デバッグ情報falseならデバッグしない、2ならデバッグ情報をページ上に表示する
表2-2-1 IM_Entry関数の引数

 もし、PHPのプログラムのファイルを直接開いて編集したくない場合には、INTER-Mediator内に組み込みの「定義ファイルエディター(Definition File Editor)」も用意していますので、こちらをお使いください。INTER-Mediator-Server VMでは簡単に定義ファイルを利用できるようになっています。このエディターは、Webアプリケーションの形式になっており、ブラウザーでデータを入力して保存できるようになっています。INTER-Mediator-Server VM上では、各ファイルやディレクトリに適切なアクセス権が設定されているので保存が可能ですが、Webブラウザーの稼働ユーザーの権限で、定義ファイル自体に書き込みが可能になっていないと、書き込み時にエラーが出ます。その場合はファイルのアクセス権を改めて調べてみてください。

図2-2-3 Webアプリケーションとして稼働する定義ファイルエディター

 この後の演習で、実際に、ファイルの内容を編集する方法も含めて、作業手順を示しながら、作成方法を学習します。

ページファイルの記述方法

 ページファイルは、拡張子が.htmlで、HTML5で記述するWebページのテンプレートとなるファイルです。まず、ヘッダーセクションでは、定義ファイルを、SCRIPTタグで読み込みます。定義ファイルはPHPで記述されたファイルですが、Webサーバー経由、つまりスクリプトが実行した結果は、JavaScriptのプログラムが返されます。拡張子は.phpですが、MIMEタイプはtext/javascriptで返される、JavaScriptのプログラムであり、それがINTER-Mediatorのクライアントサイドで稼働するプログラムの本体になります。

 以上の点から、ページファイルのヘッダーからBODYタグの部分は、リスト2-2-2のような書き方が一般的な記述方法になります。もちろん、ヘッダーには他にスタイルシートの読み込みやMETAタグ、他のJavaScriptのプログラムの読み込みがあってもかまいません。定義ファイルをSCRIPTタグで読み込む部分が必須の記述になります。

リスト2-2-2 定義ファイルがdef01.phpの場合のページファイルの例
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>INTER-Mediator Sample</title>
    <script type="text/javascript" src="def01.php"></script>
</head>
	:

 なお、Ver.5.4-devの途中までは、INTER-Mediatorを動作させるきっかけを記述する必要がありました。「INTERMediator.construct(true);」というJavaScriptのプログラムを記述する必要があったのです。そのために、BODYタグのonload属性か、SCRIPTタグないしは別途拡張子が.jsのファイルを用意して、そこでwindow.onloadに対して無名関数を定義するなど行っていました。Ver.5.4-devの途中より、このconstructメソッドの呼び出しは自動的に行われるようになりましたので、ページを開いたときにページ合成を行うのであれば、記述の必要は無くなりました。

 実際にデータベースのデータを表示するのは、BODYタグの内部になります。ここでは、コンテキストに「postalcode」という名前のコンテキストがあり、そこには、f3、f7、f8、f9といったフィールドがあることが既知であるとします。このとき、以下のように記述を行います。一般的なHTMLでのTABLEタグを利用したテーブルですが、一般的なページとの違いは、data-im属性があることです。data-im属性の値は「コンテキスト名@フィールド名」と記述します。すると、最初のTDタグ要素では、postalcodeコンテキストから得られたレコードのf3フィールドの値が、TDタグ要素のテキスト要素、つまり、<td>と</td>の間に挟み込まれるといった処理をINTER-Mediatorが行います。

リスト2-2-3 ページファイルのボディ部の記述例
<body>
<table>
  <thead>
    <tr><th>f3</th><th>f8</th>
    <th>f9</th><th>f10</th></tr>
  </thead>
  <tbody>
    <tr>
      <td data-im="postalcode@f3"></td>
      <td data-im="postalcode@f7"></td>
      <td data-im="postalcode@f8"></td>
      <td data-im="postalcode@f9"></td>
    </tr>
  </tbody>
</table>
</body>

 もし、ここで、postalcodeコンテキストが複数のレコードからなる場合はどうなるでしょうか? INTER-Mediatorは、TBODYタグの内部のTRタグ要素を、レコードごとに用意して、追加します。つまり、この場合はTRタグ要素がひとつありますが、レコードが10個あれば、TRタグ要素は10個並び、レコードの順に前からTBODYタグ要素の子要素として追加されて行きます。このとき、繰り返されるTRタグ要素を「リピーター」、その親要素であるTBODYタグ要素を「エンクロージャー」と呼びます。つまり、エンクロージャーの子要素にあるリピーターが、レコードの数だけ繰り返すということをINTER-Mediatorは行います。

 表2-2-2のようないくつかのレコードがコンテキストから得られた場合、INTER-Mediatorはクライアントサイドでリスト2-2-4のようなタグ要素を生成します。その結果、テンプレートとしてのページファイルの内容にコンテキストで得られたデータを合成して、ブラウザーの画面に表示されることになります。

idf3f7f8f9
11000000東京都千代田区以下に掲載がない場合
21020072東京都千代田区飯田橋
31020082東京都千代田区一番町
41010032東京都千代田区岩本町
51010047東京都千代田区内神田
:::::
表2-2-2 postalcodeコンテキストから得られたリレーションの例
リスト2-2-4 いくつかのレコードのデータを合成した結果
<body>
<table>
  <thead>
    <tr><th>f3</th><th>f8</th>
    <th>f9</th><th>f10</th></tr>
  </thead>
  <tbody>
    <tr>
      <td data-im="postalcode@f3">1000000</td>
      <td data-im="postalcode@f7">東京都</td>
      <td data-im="postalcode@f8">千代田区</td>
      <td data-im="postalcode@f9">以下に掲載がない場合</td>
    </tr>
    <tr>
      <td data-im="postalcode@f3">1020072</td>
      <td data-im="postalcode@f7">東京都</td>
      <td data-im="postalcode@f8">千代田区</td>
      <td data-im="postalcode@f9">飯田橋</td>
    </tr>
    <tr>
      <td data-im="postalcode@f3">1020082</td>
      <td data-im="postalcode@f7">東京都</td>
      <td data-im="postalcode@f8">千代田区</td>
      <td data-im="postalcode@f9">一番町</td>
    </tr>
            :
  </tbody>
</table>
</body>

 ここではTDタグにdata-im属性を記述しましたが、DIVやSPAN、Pなどの汎用的なタグにも記述できます。また、タグのテキストだけでなく、タグの属性にもフィールドのデータを差し込むことができます。ここでは、エンクロージャーとしてのTBODYとリピーターとしてのTRの組み合わせの中で、TRタグの内部にdata-im属性を持つタグ要素が存在しています。INTER-Mediatorはdata-im要素を持つタグ要素を「リンクノード」として識別し、リンクノードの上位ノードを検索して、リピーターの範囲を決めます。そして、そのリピーターの中で使われているコンテキストを求めてデータベースアクセスし、得られた結果を合成するといった動作を行います。

演習データベースの内容をリスト表示する

 以下、演習を通じて、データベースに入力されている郵便番号の情報を、Webページ上に一覧表示をしてみます。演習は、INTER-Mediator-Server VM(Ver.5.1以降のもの)を利用している前提で手順を記載しますので、実際にお手元で作業を行ってみてください。

データベースの内容を確認する(MySQL)

 まず最初に、データベースの内容をチェックします。MySQLについては以下のようにして、コマンドラインで参照しますが、コマンドラインに慣れていない方は、画面ショットの最後の結果だけを見て、データベースの中身を確認するだけでもかまいません。

1macOSの場合は「ターミナル」アプリケーション、Windowsの場合はTeraTermなどのSSHで接続可能なアプリケーションを利用して、ホスト、「192.168.56.101」に接続します。ユーザー名は「developer」、パスワードは「im4135dev」です。ターミナルの場合は、次のようにコマンドを入力します。
ssh 192.168.56.101 -l developer
2初めてssh接続を試みると次のようなメッセージが返ってきます。「本当にここに接続していいか?」を確認するメッセージです。ここで、「yes」とタイプしてリターンキーを押します。(RSA key fingerprintの後の値は、VMのバージョンによって異なります。)
The authenticity of host '192.168.56.101 (192.168.56.101)' can't be established.
RSA key fingerprint is 31:c9:0d:17:2c:0b:93:6c:e3:52:c3:86:ee:69:67:a9.
Are you sure you want to continue connecting (yes/no)? 
3パスワードの入力を要求されます。ここでは、「im4135dev」とキータイプして、returnキーを押します。
developer@192.168.56.101's password: 
4ログインできると、「developer@inter-mediator-server:~$」というプロンプトになります。ここで、以下のようなコマンドを入力して、MySQLデータベースに接続します。パスワードがたずねられるので、「im4135dev」と入力します。
mysql -u root -p test_db
5MySQLのプロンプトになります。例えば、以下のようなSQLコマンドを実行して、データベースの中身を見てみます。
select * from postalcode limit 6;
6データベースを見ると、以下のような特徴があることが分かります。

データベースの内容を確認する(FileMaker)

 FileMaker Server上のサンプルデータベース「TestDB.fmp12」を開き、「postalcode」レイアウトを参照してみます。FileMaker Proで開いて確認しておきましょう。

定義ファイルを編集する

1ここからの作業は、Webブラウザー上で行います。ブラウザーで、「http://192.168.56.101」に接続します。「トライアル用のページファイルと定義ファイル」という見出し部分を画面スクロールさせて表示してください。
2「def01.phpを編集する」をクリックします。このdef01.phpというファイルは、定義ファイルです。すると、def01.phpファイルを編集する定義ファイルエディターが開きます。(本コースでは、用意されたリンクの1番目から利用しますが、もし、他の用途で1番目を利用しているのなら、例えば、def11.phpを利用するなど、別の番号のセットを使用してください。その場合ソースコードの記述が変わる部分がありますが、可能な限り注記します。)
3Contextsの中のQueryと書かれ背景がグレーの部分を特定します。そして、その次の行の右の方にある「削除」をクリックして、Queryの設定がある行を削除します。
4「レコードを本当に削除していいですか?」とたずねられるので、OKボタンをクリックします。
5同様に、Sortingの次の行にある「削除」ボタンを押し、確認にOKボタンをクリックして、こちらの設定も削除しておきます。
6repeat-controlの右のテキストフィールドを削除して空白にします。そして、Tabキーを押して、次のフィールドに移動します。
定義ファイルエディターは、テキストフィールドを修正したとき、別のテキストフィールドに移動するときに書き戻しを行います。原則として、テキストフィールド修正後にはTabキーを押して確定することとします。
7Database Settingsに設定を行います。『2-1 データベースからの取り出し設定』で説明した設定項目に従って入力を行います。
[MySQL]の場合
db-classは「PDO」のままでかまいません。dsnに「mysql:host=localhost;dbname=test_db;charset=utf8mb4」と入力します。そして、userに「web」、passwordに「password」と入力します。
[FileMaker]の場合
db-classを「FileMaker_FX」に書き換えます。databaseは「TestDB」、userに「web」、passwordに「password」、serverに「192.168.56.1」、portに「80」、protocolに「http」、datatypeに「FMPro12」と入力します。
最後にTabキーを押して、確定することを忘れないでください。

ページファイルを編集する

1「http://192.168.56.101」で開いたページに戻ります。通常、定義ファイルエディターは異なるタブあるいは異なるウインドウに表示されるので、「http://192.168.56.101」のページは別のタブあるいはウインドウにあるはずです。そちらに切り替えます。
2「page01.htmlを編集する」をクリックします。このpage01.htmlというファイルは、ページファイルです。すると、page01.htmlファイルを編集するページファイルエディターが開きます。(別の番号のセットで作業している場合には、該当する番号のリンクをクリックしてください。)
3まずは、表の基本構造を考えます。page01.htmlを以下のように変更します。単にTABLEタグで表を作り、THEAD、TBODYを明示しています。まだここではINTER-Mediatorによるデータベースアクセスは行っていません。なお、スタイルについては特に意味はありませんので、自由に設定してかまいません。
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title></title>
</head>
<body>
    <table>
        <thead>
            <tr><th>郵便番号</th><th>住所</th></tr>
        </thead>
        <tbody>
            <tr><td>1111111</td><td>東京特許許可局</td></tr>
        </tbody>
    </table>
</body>
</html>
4「http://192.168.56.101」で開いたページに戻ります。別のタブあるいはウインドウにあるはずです。そちらに切り替えます。
5「page01.htmlを表示する」をクリックします。page01.htmlファイルが別のタブあるいはウインドウで開きます。(別の番号のセットで作業している場合には、該当する番号のリンクをクリックしてください。)この段階では、単にHTMLで定義した通りに見えています。
ここまでの作業で、「http://192.168.56.101」で開いたページ、def01.phpの編集ページ、page01.htmlの編集ページ、page01.htmlを開いたページの4つのタブあるいはウインドウが見えていると思われます。これらのタブやウインドウは閉じないでそのままにして、必要に応じて切り替え、更新等をすることで作業を継続できますので、以後はこの4つのページを切り替えて作業します。
6「page01.htmlを編集する」で開いたページファイルエディターのページに切り替えて、HTMLのコードを以下のように修正します。追加修正する部分は太字で示しています。
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title></title>
  <script type="text/javascript" src="def01.php"></script>
</head>
<body>
    <table>
        <thead>
            <tr><th>郵便番号</th><th>住所</th></tr>
        </thead>
        <tbody>
            <tr>
              <td data-im="postalcode@f3"></td>
              <td>
                <span data-im="postalcode@f7"></span>
                <span data-im="postalcode@f8"></span>
                <span data-im="postalcode@f9"></span>
              </td>
          </tr>
        </tbody>
    </table>
</body>

データベースからの取り出し結果の表示

1「page01.htmlを表示する」で表示したページに切り替えます。そして、画面の更新を行います。アドレスバーの左右にあるボタンなどを利用して、画面を更新します。
2次のように、グレーのボックスで何かたくさん表示されました。これは、現在デバッグモードになっており、データベースとのやりとりの部分を細かくログとして表示しています。途中を見ると、どんなSQL(あるいはRESTリクエスト)が発行されて、どんなデータが得られたかなどが分かります。消すには、ページの最初にある「clear」ボタンをクリックします。
3テーブルのページが表示されました。データベースの内容が、テーブルの中に表示されていることを確認してください。
4「def01.phpを編集する」によって表示された定義ファイルエディターのページを表示します。一番下のDebugの部分の「2」を「false」に書き換えて、Tabキーを押して値を確定させます。
5「page01.htmlを表示する」で表示したページに切り替えます。画面の更新をします。デバッグ情報は表示されなくなり、ページの要素としての表だけが見えています。

作成したファイルの確認

 INTER-Mediator-Server VMは、SMBでWeb公開ディレクトリを参照できるようになっています。ページファイルの中身は、ページファイルエディター上で見えるものと同じですが、定義ファイルのそのものの内容を確認してみます。

1Web公開ディレクトリをホストOS側から参照します。OSに応じて、次のように作業します。
[macOS]
Finderで、「移動」メニューから「サーバーへ接続」を選択し、サーバーアドレスとして、「smb://192.168.56.101」を指定して、「接続」ボタンをクリックします。その後に、ユーザー名「developer」、パスワード「im4135dev」でログインをして「webroot」という共有ディレクトリを指定します。
[Windows]
エクスプローラーのアドレスの枠に「¥¥192.168.56.101¥Webroot」と入力して、Enterキーを押します。ユーザー名「developer」、パスワード「im4135dev」でログオンします。
2webrootの直下にあるdef01.phpとpage01.htmlが、この演習で作成したファイルです。また、同じフォルダーにあるINTER-Mediatorフォルダーが、フレームワークINTER-Mediatorの実体です。INTER-Mediatorフォルダーは定義ファイルからアクセス可能な場所に配置しておきます。
<?php
//todo ## Set the valid path to the file 'INTER-Mediator.php'
require_once('INTER-Mediator/INTER-Mediator.php');

IM_Entry(array (
  0 => 
  array (
    'name' => 'postalcode',
    'table' => 'postalcode',
    'view' => 'postalcode',
    'records' => 10,
    'maxrecords' => 100,
    'paging' => true,
    'key' => 'id',
  ),
),
array (
),
array (
  'db-class' => 'PDO',
  'dsn' => 'mysql:host=localhost;dbname=test_db;charset=utf8mb4',
  'user' => 'web',
  'password' => 'password',
),
false);
?>

 定義ファイルの中身と、定義ファイルエディターの設定の対比をしてみてください。連想配列のキーに相当する部分はページ上では固定された文字列となっており、値に相当する部分が入力可能なテキストフィールドになっています。ここで見えているデータベース接続に関するキーと値は『2-1 データベースからの取り出し設定』ですでに説明した通りです。コンテキストの設定については、この後に説明をします。

 なお、定義ファイルを構成する上では、「0 =>」のような、数値のインデックスはあってもなくてもかまいません。手作業で定義ファイルを作成するときには省略しますが、定義ファイルエディターが機械的にファイルを生成するので、余計な記述が含まれてしまっています。

演習のまとめ

コンテキストの定義内容について

 ここまでの演習で作成した定義ファイルdef01.phpのコンテキスト定義の部分を解説しましょう。まず、コンテキストの定義は、PHPではひとつの連想配列となっています。その要素として、nameキーによる値は必ず必要です。nameキーは文字通りコンテキストの名称であり、ページファイルのリンクノードで、どのコンテキストのデータを取り出すのかを示すために利用します。nameキーの名前は、一般的にはプログラミング言語の変数命名規則に則って付けておくのが問題は少ないでしょう。一部に稼働する場合があるかもしれませんが、nameキーの値には空白文字を入れないようにしてください。

 実際に利用するデータベースは、読み出し、つまりクエリーのときにはviewキーで指定した値を利用します。つまり、viewキーには、データベースのテーブルやビューの名前を指定します。しかしながら、viewキーの値がない場合には、nameキーの値を使います。

 一方、編集やレコード作成、レコード削除といった書き込み処理の場合は、tableキーで指定した値を利用します。こちらはテーブルを指定するのが一般的と思われます。このtableキーの値も指定がなければ、nameキーの値を利用します。

 以上のように、viewやtableキーにより、読み書き対象のデータベース側のエンティティを個別に指定はできますが、もし、postalcodeテーブルがあるとして、nameキーの値が「postalcode」で、viewやtableキーを省略しているとしたら、postalcodeテーブルに対して読み書きを行います。これが一番シンプルな定義になります。さらにsourceキーもデータベース側のエンティティを指定するのに利用できますが、こちらはすぐ後の『データベース上での同一エンティティであることを示すsourceキー』で説明します。

 viewやtableを別に用意しているのは、同一のテーブルでも、状況により(つまり、コンテキストにより)、異なる結果を得たい場合に対応します。同じpostalcodeでも、「新宿区の郵便番号」と「足立区の郵便番号」というコンテキストを伴う利用がある場合、nameキーはそれぞれsinjuku_postalcode、adachi_postalcodeとしておき、viewはいずれも同じpostalcodeにするという使い方が考えられます。そして、次のセクションで説明する検索条件を適切に指定をしていれば、それぞれのコンテキストは名前に従った結果が得られるということになります。

 なお、FileMakerでは、viewやtableキーの値としては、レイアウト名を指定します。TO名(リレーションシップのタブで定義するボックスの名称)やテーブル名ではないので、注意をしてください。FileMaker ServerのXML共有およびPHP共有の制約があり、レイアウトを経由する方法でのWeb利用しかできません。

 idキーに対する値は、そのテーブルの主キーを指定します。複数のフィールドは指定できません。ただし、読み出しのみの場合には、この設定はなくてもかまいませんが、編集や削除の処理で、この値を利用します。また、挿入時にも挿入したレコードを特定するためにこの設定を利用します。つまり、更新処理がなければidキーの設定は不要ですが、更新処理が行われる場合には必須です。FileMakerの場合、「'key' => '-recid'」という指定が可能です。これは、システムが背後でレコードに自動的に割り振る通し番号を主キーとして利用する設定です。

 recordsキーは、検索結果の中からいくつのレコードを実際に取り出すのかということを指定するものです。postalcodeテーブルには何千ものレコードがありますが、10レコードだけが表示されています。この場合、たまたま検索して得られた先頭から10レコードを取り出しています。maxrecordsは、recordsの値を動的に変更する仕組みを使う上で、この数値以上は絶対に上回らないようにするという設定です。いずれも、省略すると、非常に大きな数字を設定します。しかしながら、何万のレコードを一度にページに表示しようとすると多大な時間がかかってしまいます。通常はなんらかの制限が必要ですので、この数値は適切な値を与えておくのが良いでしょう。

 pagingキーの値については、別のセクションで説明します。

データベース上での同一エンティティであることを示すsourceキー

 Ver.5.3より、コンテキスト定義に、sourceキーの指定ができます。データベース上のエンティティ名に関連するキーとしては、name、view、tableがあり、それらに加えてsourceも利用できます。データベースから読み出しを行うときには、INTER-Mediatorが背後でSQLステートメントを生成していると考えてください(FileMaker Serverは別の方法です)。その時、FROM句に指定されるビューやテーブルの名前は、viewキーがあればその値、なければnameキーの値が使われます。CREATE/UPDATE/DELETコマンドの対象は、tableキーの値で、それがなければnameキーが使わます。例えば、nameキーにテーブル名があれば、そのテーブル名を指定しての読み書きはviewとtableキーの指定はしなくてもできます。しかしながら、表示は何かのビューを使い、更新はそのビューではない特定のテーブルを指定したいような場合に対処できるように、viewとtableキーとして異なる名前を指定できます。

 しかし、これだけでは問題があります。あるテーブルのあるレコードのあるフィールドが、ページ上の複数のリンクノードに展開された場合、それが例えば両方ともテキストフィールドであるとします。この時、一方の値を変えると、フィールド更新のためのサーバー通信が行われるとともに、クライアントサイドで同一フィールドとバインドしている別のリンクノードの値を更新します。その時、何を手掛かりにして反映させるコンテキストを探しているかといえば、「viewないしはnameキーの値が同じだが異なるコンテキスト」です。例えば、住所録的なpeopleテーブルがあり、同一ページに全レコードの一覧と、その中で男性の一覧の両方があったとします。前者のコンテキストは、name=allmembers, view=people、後者のコンテキストはname=malemembers, view=peopleとして適切なqueryキーの条件を与えればいいでしょう。こうすれば、同一テーブルから異なるコンテキストを生成して、内容が異なる一覧を1ページ内で生成できます。この時、男性の一覧にあるレコードは、必ず全員のレコードの一覧にもあります。どちらもviewキーがpeopleなので、男性のレコードのひとつのフィールドを変更すると、対応する全員の一覧にあるレコードのフィールド値も更新されます。以下、この動作は「連動」と呼びます。同一のviewキーの値を持つコンテキスト同士なので、INTER-Mediatorにとっての手がかりがあります。

 しかしながら、データベースのスキーマに置いて、peopleをもとにしたビューeveryoneとsomeoneが定義してあったとします。それらで表を作るとしたら、nameやviewを使うにしても、everyoneとsomeoneという名前がそれぞれのコンテキスト定義に登場はしますが、コンテキスト定義から各々が同一のpeopleテーブルから導出されていることは分かりません。そうなると、同一のレコードがそれぞれの一覧に見えていて、一方の値を変更したとしても、その変更結果を伝達する手がかりがなく、連動はできません。

 このような時にはそれぞれのコンテキスト定義にsourceキーの値を指定して、一方のコンテキストを、name=everyone, source=people、もう一方はname=someone, source=peopleと定義します。ページファイル側は、everyoneあるいはsomeoneをdata-im属性に利用する点は変わりありません。このsourceの設定により、2つのコンテキスト定義から得られるコンテキストは、同一のテーブルから来ていることがINTER-Mediatorに伝わるので、それぞれのリンクノードに見えているフィールド値がユーザーインターフェース上で連動できようになります。

このセクションのまとめ

 INTER-Mediatorを使ったWebページ構築の基本である、定義ファイルとページファイルを作成することを説明しました。定義ファイルはPHPのプログラムですが、キーと値を与えるデータのセットであり、定義ファイルエディターを利用すればプログラミング言語に従った記述はしなくてもかまいません。定義ファイルの大きな目的は、コンテキストの定義とデータベースへの接続の定義です。コンテキストという中間的な存在を定義して、その内容をページファイルに埋め込みます。ページファイルでは、data-im属性により、コンテキスト名とフィールド名を指定して、フィールドのデータの埋め込みを行います。他に、定義ファイルのSCRIPTタグによる読み込みと、INTER-Mediatorを稼働するきっかけの1行のプログラムの記述が必要です。テーブルの中にdata-im属性を持つリンクノードを定義すれば、レコードの数だけTRタグ要素を複製するため、複数のレコードをページ上に展開する動作も行われます。コンテキストの定義では、name、table、viewという3つのエンティティを指定するキーがあり、同一のテーブルに対して異なる名前のコンテキストを定義して、ページファイル側で使い分けることもできます。recordsキーの値により、レコード数を制限できます。

2-3JavaScriptプログラムの記述

INTER-Mediatorは定義ファイルとページファイルの記述で多くのことができますが、一部の機能やあるいは複雑な処理を構築したいような場合には、JavaScriptによるプログラムが必要になることがあります。ここでは、ページファイルや別のファイルに記述するJavaScriptのプログラムについて基本的なことと、本コースでこの後に出てくるJavaScriptによる機能の呼び出しのための基本的なことを記述します。なお、言語についての説明は本コースでは行いません。

JavaScriptについての知識の確認

 すでにJavaScriptについての知識がある方や、これから勉強する方もいらっしゃると思います。INTER-Mediatorで使用するJavaScriptのプログラムを記述するために、どのような知識が必要なのかをまとめておきました。

INTER-Mediatorが定義する変数

 INTER-MediatorのAPIについては、本コースで少しずつ説明しますが、表2-3-1のようなグローバル変数がすでに定義された状態になります。ほとんどは、グローバル変数であり、変数が参照するのはオブジェクトです。IMLibContextのみ、クラスとして定義されておりその実態は関数で、実際に利用するときにはそのときに定義した異なる変数名になります。また、INTER-Mediator自体ではそのほかにも変数は定義していますが、APIとして利用するグローバル変数を表にまとめました。

グローバル変数名用途
INTERMediator一番中心になるオブジェクト。ページ合成を行う
INTERMediatorLib機能を構築する際のサポートを行うような小規模の機能をまとめたオブジェクト
INTERMediatorOnPage認証などHTMLページに連動するような機能のクラスで、メソッドの拡張もここで行うものが多い
INTERMediator_DBAdapterデータベースサーバーに対してのやりとりを行うオブジェクト
IMLibUIレコード追加などのユーザーインターフェースから利用できる機能をまとめたオブジェクト
IMLibContext(クラス)データベースから取り出した結果を保持するモデルに相当するオブジェクト
IMLibContextPoolIMLibContextクラスの集合を管理するオブジェクト。APIはこちらのオブジェクトに定義
IMLibLocalContextデータベースと独立した、クライアントだけに存在するコンテキスト
IMParts_CatalogJavaScriptのコンポーネントを利用するときに使用するオブジェクト
表2-3-1 INTER-Mediatorで定義される主要な変数

 なお、これらの変数がいつ定義されるかというと、定義ファイルをSCRIPTタグで読み込むときです。定義ファイルはPHPのプログラムとして記述しますが、INTER-Mediatorはその定義ファイルのプログラムを実行することにより、JavaScriptのプログラムを生成してクライアントに伝達します。したがって、拡張子は.phpだけれども、ブラウザーにとってはMIMEタイプがtext/javascriptとなっているJavaScriptのプログラムがサーバーから返ってきたように見えるので、そこで実行が開始されて、これらの変数が定義されます。

JavaScriptを記述する3つの代表的な場所

 JavaScriptのプログラムを記述するには、①タグ要素の特定の属性内、②ページファイルのヘッダー、③別ファイルの3つの方法があります。タグ要素の属性内においては、何行にも渡るようなプログラムを記述するのはかえって見づらくなります。通常はひとつあるいは数個の処理ステップで終わらせるような作り方をします。

 リスト2-3-1のように、ページファイル(HTMLファイル)のヘッダー部分に、SCRIPTタグでJavaScriptのプログラムを記述することができます。HTMLのコードがダウンロードされて、解析される段階で、SCRIPTタグの内容が実行されると考えれば良いでしょう。したがって、ここでのプログラムを実行する段階では、まだ、ページの要素がロードされた状態にはなっていません。そこで、ロードされたときに実行される関数を定義したり、関数の定義があるのが一般的です。

リスト2-3-1 ヘッダーに記述するJavaScriptプログラム
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title></title>
  <script type="text/javascript" src="def01.php"></script>
  <script type="text/javascript">
  INTERMediatorOnPage.doBeforeConstruct = function () {
    var params = INTERMediatorOnPage.getURLParametersAsArray();
    INTERMediator.clearCondition("postalcode");
    if (params["q"]) {
      INTERMediator.addCondition("postalcode",
         {field: "f3", operator: "LIKE", value: params["q"]});
    }
  }
  </script>
</head>
<body>
         :
</body>
</html>

 ヘッダー部のSCRIPTタグで記述するJavaScriptのプログラムは、リスト2-3-2のように、別のファイル(page01.js)に記述することもできます。これにより、HTMLとJavaScriptという2つの言語が混在することはなくなり、ファイルはひとつ増えるものの、別々に管理ができます。JavaScriptのプログラムが長くなると、別々のファイルになっている方が、それぞれのファイルの内容を把握しやすくなるでしょう。JavaScriptのプログラムを記述するファイルは拡張子が.jsのファイルで、JavaScripitのプログラムそのものを記述します。すると、それを呼び出しているSCRIPTタグが解析された段階で、ファイルに記述したプログラムが実行されると考えてください。jsファイルのエンコードは、ページファイルのエンコードと同一にするのが基本です。なお、閉じタグの「</script>」を記述する必要があり、「<script type="text/javascript" src="page01.js" />」といった空要素による表現は行いません。空要素にすると、Internet ExplorerやFirefoxで、SCRIPTタグの内容が無視されていたため、空要素にしない記述にしています。HTMLの定義では、内容を持つタグで内容が何もない場合は空要素の記述にはしないとされており、バグというわけではありません。空要素にしても稼働するブラウザーが、拡大解釈していると考えるべきです。

リスト2-3-2 別のファイルに記述するJavaScriptのプログラム
============================ page01.html
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title></title>
  <script type="text/javascript" src="def01.php"></script>
  <script type="text/javascript" src="page01.js"></script>
</head>
<body>
         :
</body>
</html>
============================ page01.js
INTERMediatorOnPage.doBeforeConstruct = function () {
  var params = INTERMediatorOnPage.getURLParametersAsArray();
  INTERMediator.clearCondition("postalcode");
  if (params["q"]) {
    INTERMediator.addCondition("postalcode",
       {field: "f3", operator: "LIKE", value: params["q"]});
  }
}

このセクションのまとめ

 このセクションでは、知っておきたい範囲のJavaScriptのプログラムの知識と、INTER-Mediatorで定義されているグローバル変数、そして、プログラムを具体的にどこに記述するのかといったことを説明しました。

2-4レコードを移動するナビゲーション

たくさんのレコードを決められた数だけのレコードを表示して、表示範囲を切り替えるような機能はWebサイトではよく見られるものです。こうした機能は「ページネーション」と呼ばれます。この機能もINTER-Mediatorではプログラミングの必要はありません。あるid属性を持ったノードが、ページネーションのためのナビゲーションにかわります。しかしながら、そのままだと見栄えがよくありませんので、CSSの設定も必要です。

ページネーションの生成

 ページネーションのユーザーインターフェースをページ内に表示させるには、定義ファイルのコンテキストの定義中で、pagingキーによる値をtrueにします。そのpagingキーがtrueになっているコンテキストの表示範囲をページネーションコントローラーで管理をします。このpagingキーは、複数のコンテキストを定義した場合、その中のひとつのコンテキストだけに指定する必要があります。複数のコンテキストでpagingキーの値がtrueの場合、どのコンテキストに適用されるかは定かではありません。

 定義ファイル側でpagingキーの設定を行った上で、ページファイルの中に、id属性が「IM_NAVIGATOR」のタグ要素を追加します。要素の種類はなんでもかまいませんが、帯状のコントロールを表示したいのであれば、DIVタグを使うのが便利でしょう。id属性がIM_NAVIGATORのタグ要素の子要素として、ページを前後するボタン等が追加されます。

 機能的には以上の設定で、ページネーションのコントロールがページ上に現れますが、例えば、次のページに移動するボタンはSPANタグで定義されていて、そのままでは、見栄えも悪く、また操作性も良くありません。そこで、ページネーションらしく見せるために、スタイルシートを適用させる必要があります。

 以上の動作を演習で追っていきます。

演習ページネーションのナビゲーションを表示する

 この章で作成している定義ファイルdef01.phpとページファイルpage01.htmlに対してそのまま編集を続けます。定義ファイルにはpostalcodeというコンテキストひとつだけ定義されていて、pagingキーの値がtrueになっていました。その状態から、ページファイルを変更して、ページネーションが表示されるようにします。

ページファイルの変更

1Webブラウザーで「http://192.168.56.101」を開きます。すでに開いている場合には、そのタブを確認します。
2「def01.phpを編集する」「page01.htmlを編集する」「page01.htmlを表示する」のリンクをクリックして、それぞれのタブを開きます。もし、すでに開いている場合には、そのタブを確認します。
3「page01.htmlを編集する」をクリックして開いたタブあるいはウインドウをで、HTMLの編集を行います。以下のように、BODYタグの後に、DIVタグを追加します。
<body>
  <div id="IM_NAVIGATOR"></div>
    <table>
4「page01.htmlを表示する」をクリックして表示したタブあるいはウインドウで、画面の更新を行います。すると、テーブルの上部に現在表示中のレコード番号、ページ指定のボックスなどが表示されました。テーブルの上部のグレーの帯の部分が、ページネーションのコントローラーです。全部で3654のレコードがあり、その中の1〜10レコード目のデータが現在表示していることを示します。
5黄色い「>」は、次のページを表示することを示しています。クリックすると、11〜20レコード目、21〜30レコード目、31〜40レコード目と、10レコードずつ先を表示するようになります。
6黄色い「>>」は、最後のページを表示することを示しています。クリックすると、3651〜3654レコード目、つまり、一連のレコードの最後のレコードを含む一群が表示されています。最後なので10レコードとは限らず、ここでは4レコードが表示されています。

演習のまとめ

ページネーションのカスタマイズ

 ページネーションのコントロールのボタンは、SPANタグで表現していますが、例えば、クリック可能なボタンは、class属性がIM_NAV_infoに指定されています。このように、要素に対するクラス設定が自動的になされているので、対応するセレクタに対するスタイルを記述することで、ある程度のカスタマイズは可能です。表2-4-1に、あらかじめ設定されているクラスをまとめておきます。なお、#IM_NAVIGATORについては、当初からつけられたid属性に対応するもので、このセレクタも利用できます。なお、ページネーションのスタイルはテーマの機能と連動しています。具体的なカスタマイズ方法は、『5-6 スタイルの設定を自動化するテーマ』でも説明します。

スタイルシートのセレクタページネーションの該当部分
#IM_NAVIGATORコントローラーの外側
.IM_NAV_panelコントローラー全体
span.IM_NAV_info文字を表示する部分
span.IM_NAV_buttonボタンになる部分(機能するボタン)
span.IM_NAV_disabled機能しないボタンの部分
表2-4-1 ページネーションで割り当てられたスタイルシートのセレクタ

 さらにページネーションの中の文言についてもカスタマイズが可能ですが、JavaScriptでのプログラミングが必要になります。JavaScriptのプログラミングについては、『Chapter 6 JavaScriptでのプログラミング』で説明をしますが、ここではその内容を踏まえて結果のみ記載しておきます。

 具体的には、INTERMediator.navigationLabelに配列を設定することで、ページネーションの各要素に対するカスタマイズが可能です。配列のインデックスと対応する箇所は表2-4-2に示します。INTERMediator.navigationLabelに何も設定しない場合には、表の既定値が画面に見えます。なお、インデックス9のレコード追加などのボタンについては、コンテキスト定義でのbutton-namesキーでの指定で、既定値ではない名前を設定できます(『3-3 レコードの追加・削除・複製』の『挿入と削除のコントロール』を参照)。

インデックス設定対象既定値非表示
0最初のレコードに戻る<<インデックス0〜3
1前のページに戻る<無関係
2次のページに進む>無関係
3最後のレコードに進む>>無関係
4レコード番号の直前レコード番号インデックス4〜7
5レコード番号の範囲の間の文字列-無関係
6レコード番号範囲と全レコード数の間の文字列/無関係
7全レコード数の後の文字列(空文字列)無関係
8更新ボタンの名称更新インデックス8
9レコード作成などのボタン作成や削除などレコード操作のボタンインデックス9
10まとめ保存のボタン保存インデックス10
11ログアウトボタンの名称ログアウトインデックス11
表2-4-2 JavaScriptによる要素のカスタマイズ

 INTERMediator.navigationLabelへの配列の設定は、INTERMediator.construct(true) の呼び出しよりも前にしなければなりません。したがって、ヘッダーやBODYタグ要素の書き方としては、例えばリスト2-4-1のような形式になります。INTERMediator.navigationLabelの右辺に要素が12ある配列を記述しますが、最後のnullが続く部分は省略してもかまいません。それぞれの要素が、表2-4-2のインデックスに対応します。要素がnullだと既定値のままになります。要素に文字列を指定すると、その文字列に置き換わります。インデックスが0、4、8、9、10、11についてはfalseを指定することで、ページネーションの中の要素を表示しなくなります。リスト2-4-1ではインデックスが8のものがfalseになっているので、「更新」ボタンが非表示になり、他の要素はそのまま表示します。

リスト2-4-1 ページネーションのカスタマイズを行うページファイルの例
<head>
<script type="text/javascript">
INTERMediatorOnPage.doBeforeConstruct = function () {
	INTERMediator.navigationLabel = [null, null, null, null, null, null, null, null, false];
}
</script>
</head>
<body>
</body>

 例えば、["最初", "前", "次", "最後"] のように指定すると、<<ボタンは「最初」ボタンなどと変更されます。[false, null, null, null, null, null, null, null, null] だと、インデックスの0〜3のものが非表示となり、ページを前後するボタンが画面には出てこなくなります。

このセクションのまとめ

 ページネーションは、pagingキーの値をtrueにしたひとつのコンテキストに対して構築され、機能します。また、そのコンテキスト定義のrecordsキーの値に応じて、1ページあたりのレコード数が決まります。ページファイルでは、id属性にIM_NAVIGATORを指定したDIVタグ要素などを配置しておけば、その場所にページネーションのコントロールが構築されます。スタイルシートによって、コントロール内部の要素のカスタマイズができますが、ボタン名などはJavaScriptを利用してカスタマイズが可能です。

2-5検索と並べ替えに関する設定

実際の業務において、データベースの内容を単に表示するだけで事足りる事例はほとんどありません。通常はさまざまな検索条件や並べ替えの条件を指定したりします。こうした設定はINTER-Mediatorでは、定義ファイル上に設定することができます。ここでは固定的な条件を定義ファイル上に記述する方法を紹介しましょう。実行時に条件が決まるような場合には、JavaScriptから設定を行います。

定義ファイルへの条件設定

 データベースへのクエリーを行うとき、SQLではWHERE句やORDER BY句で、検索条件やソート対象フィールドを指定します。INTER-Mediatorでは、その設定を行う場所として、まず、コンテキスト中を利用できます。リスト2-5-1はひとつのコンテキスト定義だけを抜き出した設定例です。PHPでの記述がファイルに対してそのまま記述されたものですが、実際の設定は定義ファイルエディターで可能ですので、設定時のキー名とその値を記述する後半の記述で理解しても良いでしょう。queryおよびsortキーに対する値を設定しますが、設定項目が複数あり、その項目がさらに複数あるので、「連想配列の配列」で記述します。後半の記述では、ひとつの塊を示すために、[ ] で囲みます。

リスト2-5-1 定義ファイルでの検索条件とソート対象フィールドの指定
(PHPでの記述)array(
	'name' => 'postalcode',
	'query' => array ( 
		array ( 'field'=>'f3', 'operator'=>'like', 'value'=>'16%' ),
		array ( 'field'=>'f8', 'operator'=>'=', 'value'=>'新宿区' )
	),
	'sort' => array ( 
		array ( 'field'=>'f3', 'direction'=>'desc' )
	)
)

(項目のみに注目した記述)
name:postalcode
query:
	[field:f3、operator:like、value:16%]
	[field:f8、operator:=、value:新宿区]
sort:
	[field:f3、direction:desc]

 sortキーの配列は、field、directionの2つのキーを持ちます。リスト2-5-1ではひとつの連想配列だけでしたが、複数の連想配列を記述した場合、順番に、並べ替えのキーとして利用します。fieldの指定は必ず必要ですが、directionは省略すると昇順と解釈します。ascが昇順、descが昇順で、サポートするすべてのデータベースはこの書き方で問題ありません(FileMakerでは置き換えを内部で行います)。

 queryキーの配列の中は、field、operator、valueの3つのキーを持ちます。それぞれ文字通り、コンテキストの元になるテーブルやビューにあるフィールド名と、検索条件に含める演算子、そして値を指定します。リスト2-5-1の最初の連想配列の場合は、MySQL向けであり、「`f3` like '16%'」というSQLステートメントの断片が記述されます。フィールド名や、値は、実際にデータベースアクセスする前にエスケープ処理を行っているので、この段階での記述ではエスケープ処理の必要はありません。

 演算子および値については、データベースエンジンに依存します。例えばMySQLの場合、[field:f3、operator:like、value:16%] により、「16で始まるf3フィールドのデータのあるレコード」が検索されます。%という記述やlike演算子は、MySQLに準拠したものです。したがって、queryキーの記述は、データベースごとによる違いがどうしても発生します。MySQLは多数の演算子をサポートしていますが、FileMakerで使用できるものとの対応は表2-5-1の通りです。MySQLの列のlike演算子は、likeと値に%を含む記述を行うことを意味しており、_は何らかの文字列に置き換わります。同等な条件をFileMaker Server向けに作成するには、[field:f3、operator:bw、value:16] となります。なお、「IS NULL」および「IS NOT NULL」については、operatorにこの記述を行い、valueには何も書かないでおきます。

MySQLFileMaker条件判断
=eq等しい
like '%_%'cn含む
like '_%'bwデータで始まる
like '%_'ewデータで終わる
>gtより大きい
>=gteより大きいか等しい
<ltより小さい
<=lteより小さいか等しい
!=neq等しくない
表2-5-1 operatorに使える演算子をMySQLとFileMakerで比較

 値については、ワイルドカードに対する文字列がデータベースに依存することが注意点です。また、FileMakerの場合で、完全一致にするには、operatorをeqにして、値は「=値」の形式にする必要があります。また、FileMakerで、「フィールド=値1...値2」の形式で検索条件を与えるには、operatorをasis、値を「値1...値2」と指定してください。

 日付データについては、データベースエンジンの記述法に従ってください。MySQLなどのSQLデータベースでは「2015-05-25 12:00:00」のような年月日の順に-で結ぶSQLでのルールに従います。FileMakerの場合は、月/日/年の記述つまり「5/25/2015 12:00:00」という記述を行います。

 queryの配列が複数ある場合、単に並べて記述されていれば、それらは、ANDで結ばれます。つまり、リスト2-5-1のような条件がある場合には、「`f3` like '16%' and `f8` = '新宿区'」となり、「f3フィールドが16で始まり、かつ、f8フィールドが新宿区」のレコードが抽出されます。

 もし、OR条件で記述したい場合は、次のように記述します。2番目の配列により、「ANDとORを入れ替えるという考え方」を適用しています。__operation__もexも決められたキーワードで、その通りの文字列で記述します。以下の場合、「`f3` like '16%' or `f8` = '新宿区'」という条件が生成されます。なお、FileMakerの場合は検索条件に式を記述することができないので、__operation__を記述すると、「すべての演算子がORとなる」という動作になります。FileMakerの場合は「ex」あるいは「or」というキーワードが使えます。FileMakerでORを導入するときは、デバッグモードでどんな検索がされているかを確認しながら設定を行うことをお勧めします。

リスト2-5-2 検索条件でOR演算を行う場合
query:
	[field:f3、operator:like、value:16%]
	[field:__operation__、operator:ex]
	[field:f8、operator:=、value:新宿区]

 さらに複雑な条件を設定した例はリスト2-5-3の通りです。fieldが__operation__の場合は、そこまででいったん式をまとめるという意味合いがあります。通常は、andでまとめた式をorでつなげますが、operatorがexの場合は、orでまとめた式をandでつなげるという逆動作になります。なお、複雑な式の記述はここまでです。理論的には、すべての論理式が論理和標準形ないしは論理積標準形で表現できるという定理があるので、この仕様ですべての論理式が記述できると言えるかと思われます。しかしながら、さまざまなロジックが絡む判定がアプリケーションにはつきものです。INTER-Mediatorではこの条件設定以外にもさまざまな手法がありますが、場合によっては、データベースが持つ機能、例えば、ビューを作ったり、ストアドプロシージャを使ったり、FileMaker Serverの場合はスクリプトの呼び出しを行うなどを利用することで、より適切な解決策になることも考えられます。

リスト2-5-3 複雑な条件の指定
query:
	[field:age、operator:>、value:19]
	[field:year、operator:>、value:1980]
	[field:__operation__]
	[field:age、operator:<、value:39]
	[field:year、operator:<、value:2006]
生成される条件:(age > '19' and year > '1980') or (age < '39' and year < '2006')

query:
	[field:age、operator:>、value:19]
	[field:year、operator:>、value:1980]
	[field:__operation__、operator:ex]
	[field:age、operator:<、value:39]
	[field:year、operator:<、value:2006]
生成される条件:(age > '19' or year > '1980') and (age < '39' or year < '2006')

 定義ファイルをPHPのコードとして記述するとき、queryキー内の配列のvalueキーに表2-5-2のようなキーワードを利用することができます。定義ファイルエディターでは、IM_TODAYなどと記述すると、その文字列そのものになりますので、この記述は定義ファイルを別のテキストエディターで開くなど、PHPのコードとして直接編集する場合にだけご利用ください。

キーワード置き換わる値
IM_TODAY今日現在の日付
IM_NOWいま現在の日時
表2-5-2 valueキーに指定できるキーワード

JavaScriptで検索条件を付加する方法

 コンテキストに記述した検索条件やソート条件は、そのコンテキストに対して常に適用される条件になります。これに対して、アプリケーション稼働時に決まるような検索条件を、JavaScriptで付与する手法も用意されています。JavaScriptを利用する方法を使うと、コンテキストの条件に、さらにプログラムで条件をプラスすることができます。例えば、来週締め切りを迎えるプロジェクトを表示させるといったことが可能になります。

 具体的には、条件を付与して、ページの合成を行うのが基本です。リスト2-5-4はその例です。diaryというコンテキストへのクエリーを行うときに、「`theDate` <= '2015-01-01'」という検索条件を付与します。コンテキストで決定される条件全体に対して、and条件で、JavaScriptで指定した条件が追加されます。addConditionメソッドは2つの引数を取り、最初がコンテキスト名、次が条件です。条件は、これまで通りfield、operator、valueというプロパティに対する値を指定したオブジェクトです。

リスト2-5-4 JavaScriptで検索条件を付与した例
<script type="text/javascript">
INTERMediatorOnPage.doBeforeConstruct = function () {
	INTERMediator.addCondition("diary", {field: "theDate", operator: "<=", value: "2015-01-01"});
	INTERMediator.addSortKey("diary", {field: "theDate", direction: "asc"});
}
</script>

 現在設定されている検索条件を得るには、INTERMediator.additionalConditionを利用します。addtionalConditonプロパティに配列が入っています。例えば、リスト2-5-5の実行により、INTERMediator.additionalCondition["diary"]の値が「{field: "theDate", operator: "<=", value: "2015-01-01"}」となります。このプロパティはオブジェクトに保持されるので、明示的に消すまで消えません。したがって、条件が変わるような場合、「INTERMediator.additionalCondition = [];」によって一度クリアする必要がある場合も出てくると考えられます。

 並べ替え条件の付与は、同様にINTERMediator.addSortKeyメソッドを利用します。また、参照は、INTERMediator.additionalSortKeyプロパティを利用します。

演習データベース検索に条件を追加する

 この演習では、コンテキストに検索条件やソート対象フィールドの設定を付与して、その条件が適用されて検索されていることを確認します。

コンテキストに検索条件を追加する

1Webブラウザーで「http://192.168.56.101」を開きます。すでに開いている場合には、そのタブを確認します。
2「def01.phpを編集する」「page01.htmlを編集する」「page01.htmlを表示する」のリンクをクリックして、それぞれのタブを開きます。もし、すでに開いている場合には、そのタブを確認します。
3「def01.phpを編集する」をクリックして表示されるタブあるいはウインドウを表示します。ここで、Contextsに、nameがpostalcodeの定義が設定されているのを確認し、Queryの下の「追加」ボタンをクリックします。追加していいかどうかをダイアログボックスでたずねるので、OKボタンをクリックします。
4Queryの下に新たな設定項目が追加されました。最初は適当なデータが入っています。
5新たに作成されたQueryの次の行の部分で、fieldには「f8」、operatorには「=」、valueには「豊島区」をキータイプします。最後のテキストフィールドにキータイプした後、Tabキーを押して、設定内容を確定しておきます。(FileMakerでも=の指定は可能です)
6「page01.htmlを表示する」をクリックして表示されるタブあるいはウインドウを表示します。今までは千代田区などのデータが見えていましたが、豊島区だけのデータになりました。また、レコード数もぐっと減って83レコードとなっています。コンテキストに指定した検索条件、つまりf8フィールドが豊島区のものだけに絞られていることが確認できました。
7「def01.phpを編集する」をクリックして表示されるタブあるいはウインドウを表示します。Queryの次の行の検索条件を変更します。最後のテキストフィールドにキータイプした後、Tabキーを押して、設定内容を確定しておきます。
MySQLの場合は、fieldには「f3」、operatorには「like」、valueには「16%」をキータイプします。
FileMakerの場合には、fieldには「f3」、operatorには「bw」、valueには「16」をキータイプします。
8「page01.htmlを表示する」をクリックして表示されるタブあるいはウインドウを表示します。検索条件通り、f3フィールドが「16」で始まるものだけのデータになりました。

コンテキストにソート対象フィールドを追加する

1「def01.phpを編集する」をクリックして表示されるタブあるいはウインドウを表示します。ここで、Contextsに、nameがpostalcodeの定義が設定されているのを確認し、Sortingの下の「追加」ボタンをクリックします。追加していいかどうかをダイアログボックスでたずねるので、OKボタンをクリックします。
2Sortingの下に新たな設定項目が追加されました。最初は適当なデータが入っています。
3新たに作成されたSortingの次の行の部分で、fieldには「f3」、directionには「desc」をキータイプします。最後のテキストフィールドにキータイプした後、Tabキーを押して、設定内容を確定しておきます。
4「page01.htmlを表示する」をクリックして表示されるタブあるいはウインドウを表示します。検索条件通り、f3フィールドが「16」で始まるものだけのデータに絞られていますが、加えて、f3フィールドのデータの逆順に並べ替えられています。

演習のまとめ

ユーザーインターフェースの定義だけで検索条件を付与する

 データベースの内容を一覧するときに、検索結果を適用するという仕組みを一切プログラムを書かずに実現するために、ボタンやテキストフィールド、あるいは一般的なノードに対して機能を割り当てるという機能があります。要素のdata-im属性を利用して、ローカルコンテキスト(クライアントサイドでデータを記録する一種の「モデル」で、名前は「_」)に特別なキー名でバインドすることで、機能が割り当てられます。以下は具体例でその機能を説明します。

検索条件を付与するテキストフィールド

 クエリー時に検索条件を付加するための記法の例がリスト2-5-5です。検索条件は通常、テキストフィールドにキータイプして、returnキーを押して検索されることを期待します。そこで、リスト2-5-5のようなdata-im属性を持ったINPUTタグ要素を記述します。この要素は、コンテキストの外に記述します。中に記述すると、繰り返されてしまうので、外側に記述するのが一般的と思われます。data-im属性の@以前は、ローカルコンテキストを示す_を指定します。@以降は、コロン(:)で4つのセクションに分かれます。それぞれのセクションに記入する内容は、表2-5-3にまとめました。

リスト2-5-5 検索条件のテキストフィールドの記述例
<input type="text" data-im="_@condition:postalcode:f3,f7,f8,f9:*match*">
セクション記述内容
第1セクションconditionこの文字列「condition」と記述する
第2セクションpostalcodeコンテキスト名
第3セクションf3,f7,f8,f9フィールド名。カンマ区切りで複数の指定も可能で、その場合はOR条件。FileMakerのフィールド名に含まれる「::」は、「;;」に置き換えて指定
第4セクション*match*演算子(記述可能な演算子:= != < > <= >= *match match* *match*)
表2-5-3 検索条件のテキストフィールドに指定する内容

 最初の2つのセクションは、説明通りです。3つ目のセクションのフィールド指定はカンマで区切って複数指定も可能です。複数指定をすると、それぞれのフィールドに対して同じ値の検索条件をORで与えます。演算子は、データベースエンジンに関わらずに、表に示した演算子を記述します。matchを含む演算子は、*の位置に応じて、順に後方一致(*match)、前方一致(match*)、部分一致(*match*)に対応します。

 リスト2-5-5で示したテキストフィールドに、例えば「新宿」と入れてEnterキーを押すと、例えばMySQLを使っている場合には「f3 LIKE '%新宿%' OR f7 LIKE '%新宿%' OR f8 LIKE '%新宿%' OR f9 LIKE '%新宿%'」検索条件がコンテキストに付加されて、再度検索を行い、そのコンテキストのエンクロージャー内が更新され、検索結果が表示されます。

 テキストフィールドが空白のときには、""やNULLでの条件を設定するわけではなく、このテキストフィールドによる検索条件自体の設定が行われません。

 同様なテキストフィールドを2つ以上配置すると、それぞれのテキストフィールドで決まる検索条件に対して、andでの検索が行われます。また、このとき、テキストフィールドが空白だった場合、そのテキストフィールドに対する検索条件は、やはり設定されません。

 2つのテキストフィールドをorで結びたい場合や、あるいは空白時に特別な処理をしたいような場合には、単にテキストフィールドを配置した上で、その値を取り出し、addConditionメソッドを使うなどするJavaScriptのプログラムを実行して、検索処理を実施するようにします。

表示件数を指定するポップアップメニュー

 リスト2-5-6のポップアップメニューを選択すると、レコードの表示件数をポップアップの選択肢で指定でき、選択と同時にコンテキストが更新されます。data-im属性に指定する「limitnumber」が決められた名前で、コロンより後にはコンテキスト名を記述します。そして、選択肢のためにOPTIONタグ要素を並べますが、選択した項目のvalue属性の値が、表示件数となります。このポップアップメニューのchangeイベントにより、コンテキストを更新します。

リスト2-5-6 ページあたりの表示件数を選択するポップアップメニュー
<select type="text" data-im="_@limitnumber:postalcode">
	<option value="5">5件ずつ</option>
	<option value="10">10件ずつ</option>
	<option value="30">30件ずつ</option>
</select>

コンテキストの更新ボタン(検索ボタン)

 リスト2-5-7のボタンをクリックすると、指定したコンテキストが更新されます。つまり、「検索」ボタンとして機能するということです。「update」が決められた名前で、コロンより後にはコンテキスト名を記述します。clickイベントにより、コンテキストの更新します。

リスト2-5-7 コンテキストの更新ボタン
<button data-im="_@update:postalcode">検索ボタン</button>

並べ替えフィールドの指定

 リスト2-5-8のSPANタグ内の▲をクリックすると、f3フィールドの昇順で並べ替えを行います。記述するタグはSPANに限らず、onclick属性が適用できるのであれば、なんでもかまいません。clickイベントにより指定したコンテキストが更新されます。

 @以降は、コロン(:)で4つのセクションに分かれます。それぞれのセクションに記述する内容は、表2-5-4に記載します。ここで、同一のコンテキストに対する「addorder」の機能を持った要素は連動します。例えば「f3で昇順」の後に「f9の降順」を選択すると、「f9の降順」を最優先とし、続くキーとして「f3で昇順」を設定します。最後に設定した条件が最優先になるようになっています。

リスト2-5-8 フィールドの並べ替えを指定
<span style="cursor: pointer" data-im="_@addorder:postalcode:f3:asc">▲</span>
セクション記述内容
第1セクションaddorderこの文字列「addorder」を記述する
第2セクションpostalcodeコンテキスト名
第3セクションf3フィールド名。ひとつのみ
第4セクションasc昇順ならasc、降順ならdesc
表2-5-4 並べ替えるタグ要素に指定する内容

演習検索のユーザーインターフェースを作成する

 この演習では、検索条件やソート対象フィールドのユーザーインターフェースをページファイル上に定義して、そのユーザーインターフェースが期待通りの動作をすることを確認します。

検索条件を与えるテキストフィールド

1Webブラウザーで「http://192.168.56.101」を開きます。すでに開いている場合には、そのタブを確認します。
2「def01.phpを編集する」「page01.htmlを編集する」「page01.htmlを表示する」のリンクをクリックして、それぞれのタブを開きます。もし、すでに開いている場合には、そのタブを確認します。
3「def01.phpを編集する」をクリックして表示されるタブあるいはウインドウを表示します。Queryの次の行の検索条件の右側にある「削除」ボタンをクリックします。また、Sortingの次の行にある「削除」ボタンをクリックします。
4QueryおよびSortingの次の行に項目がなにもない状態になっていることを確認します。
5「page01.htmlを編集する」をクリックして表示されるタブあるいはウインドウを表示します。BODYタグの次の行に、検索のためのユーザーインターフェースに関する記述を追加します。
<body>
  検索:<input type="text" data-im="_@condition:postalcode:f8,f9:*match*"/>
  <div id="IM_NAVIGATOR"></div>
    <table>
6「page01.htmlを表示する」をクリックして表示されるタブあるいはウインドウを表示します。レコードの個数が3654なので、すべてのデータが見えています。ここで、ページの冒頭に「検索」と書かれたテキストフィールドがあることを確認します。
7検索のテキストフィールドに「青」と入力して、Enterキーを押します。すると、全レコード数が55になり、検索された一覧を見ると、f8ないしはf9に、「青」という文字が含まれた住所のみが検索されていることが分かります。
8検索のテキストフィールドに「赤」と入力して、Enterキーを押します。同様に、f8ないしはf9に、「赤」という文字が含まれた住所のみが検索されていることが分かります。

その他の検索用ユーザーインターフェース要素

1「page01.htmlを編集する」をクリックして表示されるタブあるいはウインドウを表示します。ページネーションのDIVタグ要素の前に、以下のように追加します。また、テーブルのヘッダー部分も追加します。
<body>
  検索:<input type="text" data-im="_@condition:postalcode:f8,f9:*match*"/>
  <button data-im="_@update:postalcode">検索</button>
  レコード数:<select data-im="_@limitnumber:postalcode">
  <option value="5">5</option>
  <option value="10" selected="selected">10</option>
  <option value="20">20</option>
  </select>
  <div id="IM_NAVIGATOR"></div>
    <table>
        <thead>
            <tr>
              <th>
                郵便番号
                <span style="cursor: pointer" data-im="_@addorder:postalcode:f3:asc">▲</span>
                <span style="cursor: pointer" data-im="_@addorder:postalcode:f3:desc">▼</span>
              </th>
              <th>住所</th>
          </tr>
        </thead>
2「page01.htmlを表示する」をクリックして表示されるタブあるいはウインドウを表示します。「検索」ボタンをクリックすれば、検索が行われることを確認します。そして、ポップアップメニューから「20」を選択します。
31ページあたり20レコードになりました。以後、20ページ表示の状態が保持されます。
4「郵便番号」の右の「▼」をクリックすると、郵便番号の降順(大きいものが最初に来る)での並べ替えが行われました。
5「郵便番号」の右の「▲」をクリックすると、郵便番号の昇順(小さいものが最初に来る)での並べ替えが行われました。

演習のまとめ

SQLの集計処理

 INTER-Mediatorはコンテキスト定義やあるいは動作上の状況から自動的にSQLステートメントを生成します。通常のリレーション取得はそれでもいいのですが、SUM関数などを使う集計処理(アグリゲーション)を行うようなSQLを生成させたいことがあるでしょう。集計処理を伴うビューを利用してその結果から検索をして必要な集計結果を取り出すこともできますが、その方法では集計として不要なレコードの処理も行うことになるかもしれません。そこで、コンテキスト定義やあるいはその他の検索条件の指定も含めたSQLコマンドの記述ができるようになっています。

 SQLコマンドの記述ができるように、コンテキスト定義にaggregation-select、aggregation-from、aggregation-group-byという3つのキーが記述できます。これらのキーがあると、viewキーはSQL生成では無視されます。また、読み込み処理のみをサポートし、更新等の処理は行えないコンテキストとなるので、tableキー、keyキーは実質的に使われません。aggregation-select、aggregation-fromは両方とも指定する必要があります。これらのキーを設定すると、コンテキストからの読み込みに次のようなSQLを生成します。つまりaggregation-で始まるキーに加えて、query、relation、sort、recordsキーの値や、JavaScriptで動的に追加した検索条件などが加味されたSQLのSELECTステートメントが生成されてデータベースに送られます。

リスト2-5-9 生成されるSQLステートメント
SELECT [aggregation-selectの値]
FROM [aggregation-fromの値]
WHERE [query, relation, その他による検索条件]
ORDER BY [sort, その他によるソート条件]
GROUP BY [aggregation-group-byの値]
LIMIT [recordsの値]
START [オフセット値]

 なお、STARTについては、引き渡しは実装しましたが、Ver.5.3現在、0でのみ利用してください。つまり、ページネーションは利用できないということです。パフォーマンスを考慮して、レコード数のカウントは、SQLの結果の数と同じにしてあるので、結果的に1ページ分しか出てこないでしょう。これは、後々改良をすることとします。また、このコンテキストは、PDOでしか利用できず、FileMaker Serverでは利用できません。

 この機能によるパフォーマンス向上の効果を説明しましょう。例えば、大量の売り上げデータがあって、月ごとに集計したいとします。集計する方法は、SQLだけでなく、計算プロパティを使う方法ありますが、大量なので、処理を効率的にしたいため、データベース側で集計したいとします。aggregation-*キーがない場合には、月ごとの売り上げ集計結果が1レコードとなるようなビューを作成しておき、検索条件(例えば、年と月を指定)をビューに適用することになります。しかし、そのような動作だと、一旦ビューを構築するために全部のデータの集計を行うこともあり、一部のデータだけを使うという動作にならず、十分なパフォーマンスが得られません。しかし、aggregation-selectに「SUM(price)」のような記述が含まれていれば、WHERE句で対象月に絞り込んでクエリーを実施した上で集計されるので、全部のデータを取り出して処理をするということはなく、より最適化されたSQLが発行されます。

 FROMを独立して指定できるようにしているので、ここに、「テーブル名 JOIN テーブル名 ON 条件」という記述によるテーブル結合もできます。aggregation-*キーはそのまま指定されるようになっていて、とりあえず、現状ではフィールド名のクォートなどはしていません。セキュリティ的に問題になる可能性もありますが、クライアントのユーザーによって改変できない内容なので、構築時に注意をしておけば基本的には問題ないでしょう。

このセクションのまとめ

 データベースへのクエリーでは、検索条件やソート対象フィールドの指定が欠かせません。INTER-Mediatorでは、コンテキストへの設定、およびJavaScriptでの動的な設定をサポートします。加えて、ユーザーインターフェース要素へのルールに従った記述により、例えばテキストフィールドを配置するだけで検索条件を設定する機能を追加することもできます。