<!-- -*- mode:text coding:euc-jp -*-
   $FML: cgi.sgml,v 1.15 2009/12/26 13:33:26 fukachan Exp $
-->


<chapter id="cgi.internal">
	<title>
	CGI プロセスの内部構造
	</title>


<sect1 id="cgi.internal.method">
	<title>
	メソッド
	</title>

<para>
FML::CGI:: の階層にあるクラス(たとえば FML::CGI::ML)では、
以下のメソッド群を実装して下さい。
<screen>
html_start()
run_cgi_main()
run_cgi_title()
run_cgi_navigator()
run_cgi_menu()
run_cgi_command_help()
run_cgi_options()
html_end()
</screen>
ここで
html_start() は、
ようするに HTML の先頭部分、たとえば DOCTYPE から BODY あたりを、
html_end() は
/BODY と /HTML を表示する部分をカスタマイズするために用います。
「run_なんとか」は HTML BODY の中身を定義するメソッド群です。
</para>

<para>
$curproc の run() メソッドは
<screen>
html_start()
run_cgi_XXX() 群を実行(3x3 テーブル状に出力を配置、9 メソッドあります)
html_end()
</screen>
を順番に実行しています。
つまり CGI プロセスの実行のフロー( FML::Process::Flow 参照)は
<screen>
new()
prepare()
verify_request()
run()
   html_start()
   run_cgi_○○() (9 メソッドあります)
   html_end()
finish()
</screen>
ということになります。
</para>

</sect1>


<sect1 id="cgi.internal.frames">
	<title>
	CGI の画面の作りとメソッド
	</title>

<para>
&fml8; CGI スクリプトでは典型的な画面が次のように分割されると考えています。
<screen>
          ヘッダ
◎        メニュー    ◎
バー１    メイン      バー２
◎        メニュー    ◎
          フッタ
</screen>
なお、バー１と２の部分は navigation などと呼ばれます。
</para>

<para>
ヘッダ部分(HTTP ヘッダではなく、HTML の DOCTYPE から BODY あたり)や、
フッタの部分は
html_start() および html_end() で HTML コードを生成しています。
</para>

<para>
一方、
HTML BODY の中身は中央の3x3テーブル状の部分で、
run_cgi() から呼ばれるメソッドが生成しています。
</para>

<para>
(1) run_cgi() の粒度をあげる(中身をより細かくする)、
(2)「画面上のどの部分をどのメソッドが記述するのか」を指定できるメソッド、
が必要でしょう。
また、
これにあわせて BODY の中身もより細かく次のような3x3の精度で表現されています。
<screen>
nw   north  ne
west center east
sw   south  se
</screen>
</para>


<sect2>
	<title>
	現在の CGI の画面の構造	
	</title>

<para>
以下のような３x３のテーブル構造をとっており、
それぞれ次のメソッドが表示を担当しています。
<screen>
run_cgi_main
			run_cgi_title
run_cgi_navigator	run_cgi_menu	run_cgi_command_help
run_cgi_options
</screen>
HTML のレベルでは、
TABLE 命令を使って疑似的なナビゲーションバーを作っています。
そして、
ハッシュテーブルで定義されている関数を決められた順番で実行し、
テーブルを作成しています。
</para>

<para>
run_cgi_main() は何らかの処理をしない限り何も表示しません。
たいていは「なし」か「OK …」程度です。
エラーメッセージを表示することもあります。
また、
この関数はＭＬ一覧などをきちんと最新の情報にするために、
画面を描く前に実行する必要があります。
</para>

<para>
ちなみに、
run_cgi_main() は個々の関数を呼び出すためのトップレベルのアダプター層で、
FML::CGI::Menu::Admin に定義されています。
個々のコマンドは、makefml の時と同様に、この関数経由で実行されます。
</para>

<para>
ただし、
ログやメンバーリスト一覧のように
run_cgi_menu() から結果の表示をしているものもあります。
これは表示のオプションの指定をさせるために、
run_cgi_main() ではなく
run_cgi_menu() 経由で表示しているともいえるのですが、
なにしろコマンドの結果の表示が長いので、
今のように menu() 経由のほうがよいと思います。
</para>

</sect2>

</sect1>


<sect1 id="cgi.internal.trampoline">
	<title>
	画面とトランポリン機構
	</title>

<para>
CGI を表示する実体部分は
FML::Command::
以下のクラスに移動させました。
しかしながら、
FML::Command::
の中に実体があるとは限らず
object composition の形式で
FML::CGI:: クラスが提供するメニュー生成クラスを使うことになっています。
たとえば subscribe の場合
<screen>
FML::CGI::Admin::Main →
FML::Command::Admin::subscribe →
FML::CGI::Admin::User →
メニューの表示
</screen>
などとなっていて、
Mach のトランポリン機構のように、いったりきたりしています。
</para>

</sect1>


<sect1 id="cgi.internal.problems">
	<title>
	備考: FML::CGI::Admin:: ではハードコーディングするしかないのか？
	</title>

<para>
たとえば FML::CGI::Admin::User では
$comname と maps の関係がハードコーディングされていますが、
設定ファイルに移動するには非常に多くの変数が必要になりそうなので、
ある程度のハードコーディングは仕方ないでしょう。
できるだけ config.cf で変更可能であるように心がけたいとは思うのですが…
</para>

</sect1>


<!-- 後半では .cgi の実装例について解説する -->
&sect.internal.cgi.examples;


</chapter>
