Ⅶ. Webアプリケーションの開発②

 前章では、CSSによる画面デザインを行いデータベース操作ライブラリを作成しました。これでHTMLを書き下ろす準備は完了です。
 本章ではまず検索ページのHTMLをざっくりと作成して、JavaScriptを組み込んで仕上げます。続いて結果表示ページを作成して、検索指示から検索結果の応答までをテストします。

1.検索ページHTMLの作成

①冒頭部を書き始める

 まず最初の部分を書いてみましょう。HTML5の決まり文句はとても簡潔です。
 6~8行でcssフォルダーに格納されているスタイルシートを読み込むように指示しています。続く9行目でJavaScriptファイルを組み込むのですが、まだ作成していないのでコメントにしておきます。
 以前に説明しましたが、HTML上でのPHPコードは"<?php"から"?>"の間に書きます。13行目は、PHPのinclude文を使って、前章で作成したmysqlmdl.phpをincフォルダーから組み込んでいます。
<!DOCTYPE html>
<html lang="ja">
<head>

日本の世界遺産




</head>

<?php
	include "inc/mysqlmdl.php";		// MySQL用モジュールを組み込む
?>

<body>

②<body>の最初のブロック要素まで

 <body>の先頭のformタグでは、何も呼び出さない(action="#")で、"POST"メソッドによってHTTPリクエストを送信するように指示しています。
 次の18行目はcurrent_tabという名前の非表示項目を定義しています。この項目はタブの選択位置を保持するために使用し、初期値に「tab1」を設定しています。
<body>
  <form name="canvas" action="#" method="post">
  		

  

日本の世界遺産

<div class="tabbox"> <p class="tabs"> 都道府県別 登録年度別 構成遺産内訳 遺産分類別 </p>  
 22行で最初のブロック要素を書いてtabboxクラスを指定。ここからタブフォルダーのデザインが展開されます。
 24~27行では、スタイルシートのp.tabs, p.tabs a, p.tabs a.tab1~4で記述したタブ見出しが描かれます。さらにアンカータグでは、それぞれのタブ見出しのクリックをonClickイベントハンドラで捕捉して、changeTabメソッドをタブ種別を引数として呼ぶように指定しています。changeTabメソッドは、後ほどJavaScriptで記述することになります。アンカータグ後方の「都道府県別」などの名称は、それぞれのタブ見出しに表示されます。


③ブロック要素単位で個別のタブを表示する

 続いて、4つのタブページの内容を組み立てます。それぞれのタブページには
   ・ガイダンスメッセージ
   ・選択肢一覧を記録したリストボックス
   ・検索ボタン
を配置することにします。例えば「都道府県別」のタブページは下図のようになります。


 各ブロック要素ではガイダンスメッセージを表示した後、データベースから選択肢一覧を取得してリストボックス表示のためのHTML文を生成します。それに、onClickイベントの処理メソッドを指示した検索ボタンのHTML文を連結してブラウザに書き込みます。
 タブごとにテーブルの種別や抽出フィールド名は異なりますが、次のようなスケルトンに沿って各ブロック要素のコードを書き進めます。
 ついでながら、文字列型変数$bufの右辺に書かれたポイント(.)は結合演算子で、左右に書かれたデータを連結するためのものです。
<div id="tab~" class="tab"> <p>~~~~を選択してください!</p> <?php $conn = openDatabase($targ_db, $user_id, $user_pwd); if ($conn) { $sql = "SELECT ~~~ FROM ~_table ORDER BY ~"; $rs = exequteQuery($conn, $sql); $buf = "<select id='selectbox~' name='~_list' size='~'>"; while( $row = getResultSet($rs) ) { $buf = $buf . "<optionvalue='" . $row['コードフィールド名'] . "'>" . $row['名称フィールド名'] . "</option>"; } closeDatabase($conn); $buf = $buf . "</select><br><br>"; $buf = $buf . "<input type='button' value=' 検 索 ' onClick='checkSelection~();'>"; echo $buf; } ?> </div>

 「都道府県別」タブページのHTMLコードは次の通りです。
	<div id="tab1" class="tab">
			<p>都道府県名を選択してください!</p>
	<?php
		$conn = openDatabase($targ_db, $user_id, $user_pwd);
		if ($conn) {
			$sql = "SELECT PrefCode, PrefName FROM pref_table ORDER BY PrefCode";
			$rs = execQuery($conn, $sql);
			$buf = "<select id='selectbox1' name='pref_list' size='10'>";
			while( $row = getResultSet($rs) ) {
				$buf = $buf . "<option value='" . $row['PrefCode'] . "'>"
					 . $row['PrefName'] . "</option>";
			}
			closeDatabase($conn);
			$buf = $buf . "</select><br><br>";
			$buf = $buf . "<input type='button' value=' 検 索 ' onClick='checkSelection1();'>";
			echo $buf;
		}
	?>
    </div>

 他の3つのタブページのデザインとコードも掲げておきましょう。
「登録年度別」

	<div id="tab2" class="tab">
			<p>対象年を選択してください!</p>
	<?php
		$conn = openDatabase($targ_db, $user_id, $user_pwd);
		if ($conn) {
			$sql = "SELECT DISTINCT RegisterDate FROM heritage_table ORDER BY RegisterDate";
			$rs = execQuery($conn, $sql);
			$buf = "<select id='selectbox2' name='pref_list' size='10'>";
			while( $row = getResultSet($rs) ) {
				$month = $row['RegisterDate'];
				if (strlen($month) > 4)
					$month = substr($month, 0, 4);
				$buf = $buf . "<option value='" . $month . "'>" . $month . "</option>";
			}
			closeDatabase($conn);
			$buf = $buf . "</select><br><br>";
			$buf = $buf . "<input type='button' value=' 検 索 ' onClick='checkSelection2();'>";
			echo $buf;
		}
	?>
    </div>

「構成遺産内訳」

	<div id="tab3" class="tab">
			<p>対象の構成遺産を選択してください!</p>
	<?php
		$conn = openDatabase($targ_db, $user_id, $user_pwd);
		if ($conn) {
			$sql = "SELECT RegisterNo, HeritageName FROM heritage_table ORDER BY RegisterNo";
			$rs = execQuery($conn, $sql);
			$buf = "<select id='selectbox3' name='heritage_list' size='10'>";
			while( $row = getResultSet($rs) ) {
				$buf = $buf . "<option value='" . $row['RegisterNo'] . "'>"
					 . $row['HeritageName'] . "</option>";
			}
			closeDatabase($conn);
			$buf = $buf . "</select><br><br>";
			$buf = $buf . "<input type='button' value=' 検 索 ' onClick='checkSelection3();'>";
			echo $buf;
		}
	?>
    </div>

「遺産分類別」

	<div id="tab4" class="tab">
			<p>選択してください!</p>
	<?php
		$conn = openDatabase($targ_db, $user_id, $user_pwd);
		if ($conn) {
			$sql = "SELECT Kind, KindName FROM kind_table ORDER BY Kind";
			$rs = execQuery($conn, $sql);
			$buf = "<select id='selectbox4' name='kind_list' size='2'>";
			while( $row = getResultSet($rs) ) {
				$buf = $buf . "<option value='" . $row['Kind'] . "'>" . $row['KindName'] . "</option>";
			}
			closeDatabase($conn);
			$buf = $buf . "</select><br><br>";
			$buf = $buf . "<input type='button' value=' 検 索 ' onClick='checkSelection4();'>";
			echo $buf;
		}
	?>
    </div>


④終結部を書く

 検索ページHTMLの最後は次の様に結びます。
  </div>
  </form>

<script type="text/javascript">
 	//hiddenオブジェクトに書き込まれたタブを選択する
	var targ = document.getElementById("current_tab").value;
	changeTab(targ);
</script>

</body>
</html>
 formタグの外にJavaScriptを直書きしていることに注意してください。
 document.getElementById('エレメント名').valueで、HTMLを構成する任意のエレメントの値を参照、またはエレメントに値を代入することができます。112行では変数targに、18行目で確保したタブ位置保持用の非表示項目current_tabから値を取得しています。
 続くchangeTab(targ)で、指定ページだけを表示しようというわけです。このメソッドは後ほどJavaScriptで作成することになります。最初は初期値として設定されていた「tab1」が取り出されて、「都道府県別」のタブページが表示されます。タブがクリックされたときに、つまり各タブのonClickイベントハンドラを利用してcurrent_tabにタブ種別(tab1~4)を代入しておくことで、検索結果表示画面から戻ってきたときに直前の検索タブページを再表示することができるわけです。

2.検索ページにJavaScriptを組み込む

 検索ページindex.htmlには、イベントハンドラから呼び出す5つのメソッドがあり、いずれも後ほどJavaScriptで開発すると述べてきました。そのメソッドを整理してみましょう。
   ・特定のタブページを表示させるchangeTab()メソッド
   ・各タブページの検索ボタンクリックによって呼び出されるcheckSelection1~4()メソッド
 changeTab(tabname)メソッドは、すべてのタブページを
    document.getElementById('tab~').style.display = “none”;
で非表示にしてから、引数のtabnameで指定されたタブページを
    document.getElementById(tabname).style.display = 'block';
で表示するものです。

/*
 *	File name:		index.js
 *	Function:	   『日本の世界遺産DB検索システム』 index.html用
 *	Date written:	2016/06/15
 *	Author:			Marchan
 */

function changeTab(tabname) {
   //すべての表示を無効にして
   document.getElementById('tab1').style.display = 'none';
   document.getElementById('tab2').style.display = 'none';
   document.getElementById('tab3').style.display = 'none';
   document.getElementById('tab4').style.display = 'none';
   // 指定ページのみ表示する
   document.getElementById(tabname).style.display = 'block';
}

function checkSelection■() {
	var idx = document.canvas.selectbox■.selectedIndex;
	if (idx < 0) {
		alert("~を選択してください!");
		return;
	}
	document.getElementById("current_tab").value = "tab■";
	document.cookie = 'type=■';
	document.cookie = 'code=' + document.canvas.selectbox■.options[idx].value;
	document.cookie = 'name=' + document.canvas.selectbox■.options[idx].text;
	window.location.href = "result.html";
}
 checkSelectionメソッドの■は、タブ種別に応じて1~4の値をとる4種類のメソッドを記述します。
    var idx = document.canvas.selectbox■.selectedIndex
で変数idxに対応するリストボックスの選択位置「0~(選択肢の数 - 1)」を取得して、(idx < 0)なら何も選択されていないので、タブの種別に応じた選択督促メッセージを表示して何もしません。
 選択されていれば、タブ種別の番号、選択された要素のvalue(つまりコード)、選択された要素の名称を、それぞれクッキーに記録します。そしてwindow.location.hrefで、結果表示ページresult.htmlにURLを遷移させる、つまりresult.htmlを呼び出します。

 出来上がったコードはjsフォルダーにindex.jsのファイル名で格納してください。そして、index.htmlの9行目でコメント化していた
<!--script src="js/index.js"></script-->
のコメント記号を外してください。
<script src="js/index.js"></script>
これで検索ページが完成です。

3.結果表示ページHTMLの作成

①前処理を書く

 冒頭で結果表示用のスタイルシートresult.cssを読み込みます(8行目)。続いてPHPコードの先頭で、mysqlmdl.phpをincフォルダーから組み込ませます(12行目)。
 まず行うのは、クッキーに記録したタブ種別、コード、名前を取り出すことです。それぞれ、変数$type, $code, $nameに取り出しています。
 その後、タブ種別$typeに基づいて、$nameの名前を修飾して標題を編集します。そして標題をHTMLとして書き出します(40行目)。
<!DOCTYPE html>
<html lang="ja">
<head>

検索結果



</head>

<?php
	include "inc/mysqlmdl.php";		// MySQL用モジュールを組み込む

	//ページ渡しの様式と選択されたメニューのコード・名称を取得する
	$type = $_COOKIE['type'];
	$code = $_COOKIE['code'];
	$name = $_COOKIE['name'];

	/*
	 * 種別とメニュー選択結果から標題を編集する
	 */
	switch ($type) {
		case '1':	/* 都道府県検索 */
			$thema = $name . "の世界遺産";
			break;
		case '2':	/* 登録年度検索 */
			$thema = $name . "年登録の世界遺産";
			break;
		case '3':	/* 構成資産検索 */
			$thema = $name . " :その構成資産";
			break;
		case '4':	/* 登録種別検索 */
			$thema = $name . "として登録された世界遺産";
			break;
		default:
			$thema = "";
			break;
	}
	//編集した標題をHTML出力する
	echo "

$thema

";   ?>


②<body>タグ以降を書く

 先の標題の後方に検索結果を表示して、最後に[ 戻 る ]ボタンを配置します。次の様なイメージのHTMLを生成してブラウザに書き出すのが、結果表示ページresult.htmlの役割です。

 では、<body>タグ以降のコードを書き進めましょう。
 まずsectionタグでid="contents"を指定しています。ここから終端の</section>まで、スタイルシートresult.cssの#contentsで記述した表示位置が適用されることになります。すぐ次に再びsectionタグでresultTableクラスを指定しており、以降の<table>タグ内のテーブル表示は、同じスタイルシートの.resultTableクラス関連セレクタで記述されたスタイルで表示されます。
<body>
<section id="contents">
	<section class="resultTable">
<?php
	/*
	 * 指示された内容を検索して結果をテーブル様式に表示する
	 */
	$conn = openDatabase($targ_db, $user_id, $user_pwd);
	$tbl = "<br><br><br><table><thead><tr><th>No.</th><th>遺  産  名</th></tr></thead>\n"
			. "<tbody>";
	switch ($type) {
		case '1':	/* 都道府県検索 */
			$sql = "SELECT DISTINCT HeritageName FROM heritage_table INNER JOIN config_table"
				 . " ON heritage_table.RegisterNo = config_table.RegisterNo WHERE PrefCode="
				 . $code . " ORDER BY heritage_table.RegisterNo";
			$rs = execQuery($conn, $sql);
			$no = 0;
			while( $row = getResultSet($rs) ) {
				$data = $row['HeritageName'];
				$no++;
				$tbl = $tbl . "<tr><td>" . $no . "</td><td>" . $data . "</td></tr>\n";
			}
			if ($no == 0)
				$tbl = $tbl . "<tr><td></td><td>  ** 世界遺産は未登録です **</td></tr>\n";
			break;
		case '2':	/* 登録年度検索 */
			$sql = "SELECT HeritageName FROM heritage_table WHERE RegisterDate LIKE '"
				 . $code . "%' ORDER BY RegisterNo";
			$rs = execQuery($conn, $sql);
			$no = 0;
			while( $row = getResultSet($rs) ) {
				$data = $row['HeritageName'];
				$no++;
				$tbl = $tbl . "<tr><td>" . $no . "</td><td>" . $data . "</td></tr>\n";
			}
			break;
		case '3':	/* 構成資産検索 */
			$sql = "SELECT DISTINCT Configure FROM config_table WHERE RegisterNo=" . $code
				 . " ORDER BY ConfigNo";
			$rs = execQuery($conn, $sql);
			$no = 0;
			while( $row = getResultSet($rs) ) {
				$data = $row['Configure'];
				if ($data == "") {
					$tbl = $tbl . "  ** 構成資産の内訳はありません **\n";
					break;
				}
				$no++;
				$tbl = $tbl . "<tr><td>" . $no . "</td><td>" . $data . "</td></tr>\n";
			}
			break;
		case '4':	/* 登録種別検索 */
			$sql = "SELECT HeritageName FROM heritage_table WHERE Kind=" . $code
				 . " ORDER BY RegisterNo";
			$no = 0;
			$rs = execQuery($conn, $sql);
			while( $row = getResultSet($rs) ) {
				$data = $row['HeritageName'];
				$no++;
				$tbl = $tbl . "<tr><td>" . $no . "</td><td>" . $data . "</td></tr>\n";
			}
			break;
	}
	closeDatabase($conn);
	$tbl = $tbl . "</tbody></table>";

	//編集したテーブルをHTML出力する
	echo $tbl;
?>
	</section>
	   <input type='button' value=' 戻 る ' onClick='history.back();'><br><br>
</section>
</body>
</html>
 PHPのコードは、最初にデータベースを開いて、変数$tblに表の見出しを編集しています。それ以降は、条件分岐文switchでタブ種別により4種類のケースに切り分けて、case文でそれぞれの処理を記述しています。

 54行目から始まる「都道府県検索」を見ると、変数$sqlに長いSQL文を作成しています。世界遺産テーブル(heritage_table)と構成資産テーブル(config_table)を結合して、都道府県コード(PrefCode)が検索ページで指定されたコード(クッキーから$codeに取り出されている)と一致するレコードを検索して、世界遺産名(HeritageName)を抽出するためのSQL文です。2つのテーブルを結合した時点で、複数の構成資産が登録されている場合は世界遺産名が重複しますが、SELECT文の次のDISTINCTによって一つにまとめられます。
 検索を実行して、変数$noをゼロで初期化した後に、getResultSetメソッドで検索結果を取得します。検索結果の取り出しは60行目のようにレコードの内容を(ここではHeritageNameフィールドだけですが)$rowに取得します。$rowには文字列型の連想配列が取得されるので、$row['フィールド名']で内容を参照することができます。検索結果を次々に$dataに取りだしながら、$noにレコード件数をカウントアップし(62行目)、$tblに$noと$dataを編集して連結します。
 すべての結果を取り出すとレコード件数をチェックします。$noがゼロなら対象レコードが見つからなかったと判断できるので、一覧表に未登録メッセージを編集します。
 他のケースも同じ要領でコードを書いています。「登録年度検索」と「遺産分類検索」には$noのゼロチェックがありませんが、検索ページのリストボックスの選択肢がデータベースの記録内容から抽出されていることから、この2つのケースには検索結果が無いという状態はあり得ないためです。しかし「遺産分類検索」では、構成遺産がない場合はConfigureフィールドが空白になっているので、その旨を編集して、88行目のbreak文で即座にループから脱出しています。

4.検索アプリケーションをテストしてみる

 出来上がったアプリケーションで4種類の検索を行ってみました。ブラウザから「http://192.168.0.22/WorldHeritage/」をアクセスすると、index.htmlが起動されて「都道府県別」フォルダーの開いた検索ページが表示されます。

①都道府県検索

 何も選択せずに[検索]ボタンをクリックするとメッセージボックスが表示されます。
 [岩手県]を選択して[検索]ボタンをクリックすると、次の検索結果が表示されます。
 [戻る]ボタンをクリックすると検索画面に戻ります。


②登録年度検索

「登録年度別」のタブをクリックするとフォルダーが開きます。
 [1993年]を選択して[検索]ボタンをクリックすると、次の検索結果が表示されます。
 [戻る]ボタンをクリックすると検索画面に戻ります。


③構成遺産内訳検索

「構成遺産内訳」のタブをクリックするとフォルダーが開きます。
 [琉球王国のグスク及び関連遺産群]を選択して[検索]ボタンをクリックすると、次の検索結果が表示されます。
 [戻る]ボタンをクリックすると検索画面に戻ります。


④遺産分類検索

「遺産分類別」のタブをクリックするとフォルダーが開きます。
 [文化遺産]を選択して[検索]ボタンをクリックすると、次の検索結果が表示されます。
 [戻る]ボタンをクリックすると検索画面に戻ります。


 とても簡単なテストですが、当初に計画していた「日本の世界遺産」データベース検索アプリケーションの画面と動作を確認することができました。