名前

CGI::Application - 再利用可能なWebアプリケーションを組み立てるためのフレームワーク

概要

  # "WebApp.pm"で...
  package WebApp;
  use base 'CGI::Application';

  # (setup()は一般的には省略可能です。以降のドキュメントを参照してください。)
  sub setup {
        my $self = shift;
        $self->start_mode('mode1');
        $self->mode_param('rm');
        $self->run_modes(
                'mode1' => 'do_stuff',
                'mode2' => 'do_more_stuff',
                'mode3' => 'do_something_else'
        );
  }
  sub do_stuff { ... }
  sub do_more_stuff { ... }
  sub do_something_else { ... }
  1;

  ### "webapp.cgi"で...
  use WebApp;
  my $webapp = WebApp->new();
  $webapp->run();

前書き

CGI::Applicationは、洗練され、パフォーマンスが高く再利用しやすいWebアプリケーションを、簡単に作成できるようにします。CGI::Applicationは、あなたのWebアプリケーションをより設計しやすく、書きやすく、また発展させやすくするのに役立ちます。

CGI::Applicationは、開発者を特定のツールセットやOS、Webサーバに縛り付けてしまうテクノロジーやテクニックを極力採用しないようにしています。

メモリ使用量が多くないため、CGI::Applicationは一般的なCGI環境に適合しやすく、またFastCGIやmod_perlのような永続環境では、高パフォーマンスの選択肢といえます。

また、必要に応じてプラグインを追加することで、より高度で複雑な機能を追加することもできます。

2000年に最初のリリースが行われてから、多くのプロWeb開発者によって拡張が続けられ、CGI::Applicationは今やとても安定した、信頼性の高い選択肢のひとつとなっています。

使用例

ウィジェットのデータベースを検索するアプリケーションを書くことを想像してみてください。あなたのアプリケーションには3つの画面があります:

   1. 検索フォーム
   2. 結果一覧
   3. 個別レコードの詳細

CGI::Applicationでこのアプリケーションを書く場合、次の2つのファイルを作成することになるでしょう:

   1. WidgetView.pm  -- "アプリケーションモジュール"
   2. widgetview.cgi -- "インスタンススクリプト"

アプリケーションモジュールは、アプリケーションの機能に固有の全てのコードを含んでいます。これを、Webサーバのドキュメントルートの外側、Perlライブラリのサーチパスのどこかに配置します。

インスタンススクリプトは、Webサーバから呼び出されます。これはごく小さくシンプルなファイルで、単にアプリケーションのインスタンスを作成し、run()という、CGI::Applicationから継承したメソッドを呼び出すことだけを行います。以下は、"widgetview.cgi"のコード全体です:

   #!/usr/bin/perl -w
   use WidgetView;
   my $webapp = WidgetView->new();
   $webapp->run();

ご覧のとおり、widgetview.cgiはアプリケーションモジュール("WidgetView"というクラスを実装する)を単に"use"しているだけです。アプリケーションモジュール"WidgetView.pm"は、これよりも幾分長いコードになることでしょう。

   package WidgetView;
   use base 'CGI::Application';
   use strict;

   # データベース接続に必要
   use CGI::Application::Plugin::DBH;

   sub setup {
        my $self = shift;
        $self->start_mode('mode1');
        $self->run_modes(
                'mode1' => 'showform',
                'mode2' => 'showlist',
                'mode3' => 'showdetail'
        );

        # DBI->connect()と同じ引数でDBIデータベースへ接続
        $self->dbh_config();
   }

   sub teardown {
        my $self = shift;

        # 終了時にデータベースから切断する(DBIは通常これを自動的に行うが、一応)
        $self->dbh->disconnect();
   }

   sub showform {
        my $self = shift;

        # CGIクエリーオブジェクトを取得
        my $q = $self->query();

        my $output = '';
        $output .= $q->start_html(-title => 'Widget Search Form');
        $output .= $q->start_form();
        $output .= $q->textfield(-name => 'widgetcode');
        $output .= $q->hidden(-name => 'rm', -value => 'mode2');
        $output .= $q->submit();
        $output .= $q->end_form();
        $output .= $q->end_html();

        return $output;
   }

   sub showlist {
        my $self = shift;

        # データベース接続ハンドルを取得
        my $dbh = $self->dbh();

        # CGIクエリーオブジェクトを取得
        my $q = $self->query();
        my $widgetcode = $q->param("widgetcode");

        my $output = '';
        $output .= $q->start_html(-title => 'List of Matching Widgets');

        ## CGI.pmのクエリーオブジェクト経由で、前画面でユーザーが入力した
        ## "widgetcode"を取得し、それにマッチする"ウィジェット"を
        ## DBIで接続したデータベースから取得するための一連の処理を行う。
        ##
        ## 取得した各行は、次のような"ウィジェットの詳細"ページへの
        ## リンクを含むアンカータグを持つ:
        ##
        ##   "widgetview.cgi?rm=mode3&widgetid=XXX"

        ##
        ## ..."XXX"はユーザーがクリックした"ウィジェット"を特定する
        ## 一意の値である。

        $output .= $q->end_html();

        return $output;
   }

   sub showdetail {
        my $self = shift;

        # データベース接続ハンドルを取得
        my $dbh = $self->dbh();

        # CGIクエリーオブジェクトを取得
        my $q = $self->query();
        my $widgetid = $q->param("widgetid");

        my $output = '';
        $output .= $q->start_html(-title => 'Widget Detail');

        ## ユーザーがクリックした"ウィジェット"の全情報を取得するための
        ## 一連の処理を行う。このウィジェットのIDはCGI.pmのクエリーオブ
        ## ジェクト経由で"widgetid"プロパティから取得する。

        $output .= $q->end_html();

        return $output;
   }

   1;  # Perlの全てのモジュールの末尾にはこれが必要

CGI::Applicationはnew()及びrun()の2つのメソッドを実装します。標準出力へ出力を送るためのprint()がないことに留意してください。代わりに、全ての出力はスカラーとして返却されます。

CGI::Applicationの最も大きな存在意義は、アプリケーションの状態を管理することにあります。アプリケーションを先に進めるのに必要なのは、HTMLフォームのパラメータ'rm'に、フォーム送信処理のための適切な"ランモード"の値をセットする事だけです。これは、CGI::Applicationのキーポイントです。

概念

CGI::Applicationの基本的な考え方として、Webベースのアプリケーションは一連の"ランモード"にまとめることができる、ということが挙げられます。ランモードは、おおざっぱに言えば、それぞれが一つの画面(フォームや何らかのアウトプットなど)に相当するとも言えます。全てのランモードはただ一つの"アプリケーションモジュール"(これはPerlモジュールです)によって管理されます。Webサーバのドキュメントスペースには、WebサーバからCGI(又は、Apache + mod_perlを使用しているなら、Apache::Registryスクリプト)として呼び出されるべき"インスタンススクリプト"を一つだけ配置します。

この方法論は、"埋め込み"方式(ASP、JSP、EmbPerl、Masonその他)のような、アプリケーションの状態毎に"ページ"が存在し、それらのページが機能を起動するようなものとは対極にあると言えます。CGI::Applicationでは、機能の後にフォームが続きます―アプリケーションモジュールはページを起動し、ひとつのアプリケーションのためのコードは一箇所にしか存在しません;複数の"ページ"に跨る事はないのです。もし、埋め込み方式を紛らわしくまとまりのない、設計や管理のしにくいものと感じるのなら、CGI::Applicationはまさにあなたにうってつけの方法でしょう!

ApacheはCGI::Applicationの必須要件ではありません。CGI::ApplicationベースのWebアプリケーションはNT/IISやその他のCGI互換環境でも動作します。とはいえ、CGI::Applicationベースのプロジェクトは、Apache/mod_perlサーバでの稼動が最も適しています。というのも、これらはプログラミングに良い習慣をもたらし、また大抵の場合、全く修正せずに永続環境で稼動させることもできるからです。

CGI::Applicationとmod_perlとの併用に関する更なる情報については、私たちのウェブサイト http://www.cgi-app.org/ や、CGI::Application::Plugin::Apache及びこれを統合したApache::Requestを参照してください。

解説

アプリケーションモジュールは、CGI::Applicationのサブクラスとして実装されることを想定しています。これは、単に次のようにします:

    package My::App;
    use base 'CGI::Application';

表記法

このドキュメントでは、次の表記を用います:

  WebApp.pm   アプリケーションモジュールクラスを実装するPerlモジュール。
  WebApp      アプリケーションモジュールクラス; CGI::Applicationのサブクラス。
  webapp.cgi  アプリケーションモジュールを実装するインスタンススクリプト。
  $webapp     アプリケーションモジュールクラスのインスタンス(オブジェクト)。
  $c          $webappと同じく、現在のオブジェクトをたらい回しにするのに使われる。
              (別のコードでは"$self"と表記される場合もある)

インスタンススクリプトのメソッド

CGI::Applicationを継承することで、いくつかの組み込みメソッドを使用することができます。インスタンススクリプトから呼び出すことのできる組み込みメソッドは、以下のとおりです。

new()

new()メソッドは、CGI::Applicationのコンストラクタです。このメソッドは、アプリケーションモジュールパッケージ(クラス)へのブレスされたリファレンスを返します。またオプションとして、new()メソッドへ キー=>値 のパラメータペアを渡すことができます:

    my $webapp = WebApp->new(
                TMPL_PATH => 'App/',
                PARAMS => {
                        'custom_thing_1' => 'some val',
                        'another_custom_thing' => [qw/123 456/]
                }
    );

このメソッドへ、特定のパラメータを渡すこともできます:

TMPL_PATH - このオプションは、テンプレートディレクトリへのパスを定義します。load_tmpl()メソッド(以下に詳述)はこのパスを参照するほか、同様のテンプレートプラグインもこれを参照するかもしれません。この実行時パラメータはテンプレートの初期化プロセスを隠蔽し、再利用性を高めます。このオプションは、スカラー又は複数パスの配列リファレンスのいずれかで渡すことができます。

QUERY - このオプションで、既に作成済みのCGI.pmのクエリーオブジェクトを特定することができます。通常、CGI::Applicationは、独自のCGI.pmオブジェクトを作成・初期化します。特定の状況では、作成済みのオブジェクトを利用できる事が役に立つかもしれません。

PARAMS - このオプションで、実行時のカスタムパラメータをセットすることができます。同じアプリケーションモジュールを共用する複数のインスタンススクリプトへ、それぞれ異なるパラメータを渡すことで、再利用性を高めることができます。例えば、"Mailform.pm"というアプリケーションモジュールがあるとします。このモジュールは、HTMLフォームから送信された情報を特定のあて先へメール送信します。このオプションを使用することで、"Mailform.pm"モジュールをそのまま使い、あて先やフォームの異なる複数のインスタンススクリプトを運用することができるでしょう。

インスタンススクリプトには設定ファイルへのパスを記述する、というのが一般的です。そうすることで、複数のインスタンススクリプトから利用可能な広範囲の設定オブジェクトを定義する事ができます。この文法を単純化したり、遅延ロードしたりするプラグインがいくつか存在します。以下は、多くの設定ファイル形式をサポートするConfig::Autoを利用するCGI::Application::Plugin::ConfigAutoの使用例です。

 my $app = WebApp->new(PARAMS => { cfg_file => 'config.pl' });

 # 後で:
 my %cfg = $self->cfg()
 # 又は... $self->cfg('HTML_ROOT_DIR');

設定ファイル統合化に関するさらなる情報は、後述のプラグイン一覧を参照してください。

run()

インスタンススクリプトから、アプリケーションモジュールのrun()メソッドを呼び出します。呼び出されると、アプリケーションモジュールは機能を実行します。

    my $webapp = WebApp->new();
    $webapp->run();

このメソッドはまず、mode_param()で指定されたCGIパラメータ(デフォルトは"Run Mode"を意味する'rm')を見て、アプリケーションの状態(ランモード)を決定します。このCGIパラメータは、ランモードの名前を含んでいるとみなされます。このパラメータが指定されなかった場合は、start_mode()の値がデフォルトのランモードとして使用されます。

いったんランモードが決定すると、run()run_modes()が保持しているディスパッチテーブルを参照し、ランモード名をキーとするサブルーチンへのポインタを探します。見つかったら、そのサブルーチンは呼び出され、返却されたデータは標準出力(及びブラウザ)へprint()されます。指定されたランモードがディスパッチテーブルに見つからなかった場合は、run()メソッドはcroak()します。

オーバーライド可能なメソッド

CGI::Applicationは、サブクラスモジュールでオーバーライド可能なメソッドをいくつか実装しています。メソッドは以下のとおりです:

setup()

このメソッドは、継承されたnew()コンストラクタメソッドから呼び出されます。setup()メソッドは、次のプロパティやメソッドを定義するのに使われます:

    mode_param() - ランモードのCGIパラメータ名を設定する。
    start_mode() - スタートモード(デフォルトのランモード)名のスカラー値。
    error_mode() - エラーモード名のスカラー値。
    run_modes()  - ランモード=>サブルーチン のハッシュテーブル。
    tmpl_path()  - テンプレートファイルへのパスを含むスカラー値又は配列へのリファレンス。

setup()メソッドは、アプリケーションのあらゆるインスタンスメソッドを呼び出すことができます。このメソッドは、$webapp->param()メソッドを使ってアプリケーション固有のプロパティを定義するのに適した場所です。

setup()メソッドは、次のように実装できます:

        sub setup {
                my $self = shift;
                $self->tmpl_path('/path/to/my/templates/');
                $self->start_mode('putform');
                $self->error_mode('my_error_rm');
                $self->run_modes({
                        'putform'  => 'my_putform_func',
                        'postdata' => 'my_data_func'
                });
                $self->param('myprop1');
                $self->param('myprop2', 'prop2value');
                $self->param('myprop3', ['p3v1', 'p3v2', 'p3v3']);
        }

しかし多くの場合、setup()メソッドで行う事は、ランモードとスタートモードを定義する事だけです。なお、CGI::Application::Plugin::AutoRunmodeを使えば、ランモード属性を使用した簡単な文法でこれを行うことができます:

 use CGI::Application::Plugin::AutoRunmode;

 sub show_first : StartRunmode { ... };
 sub do_next : Runmode { ... }

teardown()

実装されている場合、このメソッドはアプリケーション実行後に自動的に呼び出されます。このメソッドは各種操作の後始末に使用されます。teardown()メソッドの代表的な用途は、setup()メソッドで接続したデータベースからの切断です。また、teardown()メソッドは、アプリケーションの状態に関する情報をサーバへ格納するのにも使えます。

cgiapp_init()

実装されている場合、このメソッドは、setup()メソッドが呼び出された直後に呼び出される直前に自動的に呼び出されます。このメソッドはオプションとして初期化フックを提供し、CGI::Applicationのオブジェクト指向的な性格をさらに高めます。cgiapp_init()メソッドは、new()メソッドへ送出された全ての引数をパラメータとして受け取ります。

このフックの利点を活用した例として、あなたのWebアプリケーションがCGI::Applicationの代わりに継承する、カスタムの"アプリケーションスーパークラス"を作成することが挙げられます。

次をご覧ください:


  # MySuperclass.pmで:
  package MySuperclass;
  use base 'CGI::Application';
  sub cgiapp_init {
        my $self = shift;
        # データベースやファイルから設定情報をロードする等の、
        # プロジェクト固有の初期化処理を行う。
  }

  # MyApplication.pmで:
  package MyApplication;
  use base 'MySuperclass';
  sub setup { ... }
  sub teardown { ... }
  # 残りのCGI::Applicationベースのコードが続く...

CGI::Applicationとcgiapp_init()メソッドを上記のように使用することで、一連のアプリケーションが、ある種の性格を共有するように設計することもできるかもしれません。これは、オブジェクト指向の継承を使って組み立てられた、ずっと綺麗なコードになる余地があります。

cgiapp_prerun()

実装されている場合、このメソッドは、選択されたランモードのメソッドが呼び出される直前に自動的に呼び出されます。このメソッドはオプションとしてランモード直前のフックを提供し、ランモードメソッドが呼び出される直前のポイントに機能を追加することができます。このフックをより有効活用するために、ランモードの値はcgiapp_prerun()メソッドへ渡されます。

このフックを使うことによるもう一つの利点は、あなたのWebアプリケーションがCGI::Applicationの代わりに継承する、カスタムの"アプリケーションスーパークラス"を作成できることです。

次をご覧ください:

  # MySuperclass.pmで:
  package MySuperclass;
  use base 'CGI::Application';
  sub cgiapp_prerun {
        my $self = shift;
        # ランモード固有の認証機能を実装する等の、
        # プロジェクト固有の初期化処理を行う。
  }

  # MyApplication.pmで:
  package MyApplication;
  use base 'MySuperclass';
  sub setup { ... }
  sub teardown { ... }
  # 残りのCGI::Applicationベースのコードが続く...

CGI::Applicationとcgiapp_prerun()メソッドを上記のように使用することで、一連のアプリケーションが、ある種の性格を共有するように設計することもできるかもしれません。これは、オブジェクト指向の継承を使って組み立てられた、ずっと綺麗なコードになる余地があります。

また、cgiapp_prerun()メソッドの中から、アプリケーションのランモードを変更することもできます。これはprerun_mode()によって実現可能です。

cgiapp_postrun()

実装されている場合、このフックはランモードが出力を返した後、HTTPヘッダを生成する前にに呼び出されます。これにより、Webブラウザへ出力を返す前にボディやヘッダを修正する事ができます。

このフックの代表的な使い方は、CGIアプリケーションの出力を一連の"フィルター"処理にかける事です。例えば:

  * より大きなWebページにおいて、全てのCGIアプリケーションの出力を
    HTMLテーブルの中へ閉じ込める場合。

  * ランモードが構造化データ(XML等)を返し、それを標準的な仕組み
    (XSLT等)で変換したい場合。

  * 例えばHTML::Masonのような別のシステムを通して、CGIアプリケーション
    の出力の後処理を行いたい場合。

  * 全てのランモードを横断して、特定の基準に基づく特定の方法でHTTP
    ヘッダを修正したい場合。

cgiapp_postrun()フックは、CGIアプリケーションオブジェクトの他に、出力内容のリファレンスをランモードメソッドから受け取ります。典型的なcgiapp_postrun()メソッドは次のように実装されます:

  sub cgiapp_postrun {
    my $self = shift;
    my $output_ref = shift;

    # 出力内容をHTMLテーブルに閉じ込める
    my $new_output = "<table border=1>";
    $new_output .= "<tr><td> Hello, World! </td></tr>";
    $new_output .= "<tr><td>". $$output_ref ."</td></tr>";
    $new_output .= "</table>";

    # 出力内容を新しいものに置き換える
    $$output_ref = $new_output;
  }

言うまでもなく、CGIアプリケーションオブジェクトを通して、ランモードで通常利用可能な全てのメソッドを自由に利用することができます。例えば、load_tmpl()を使用して、上の例にある静的HTMLを、HTML::Templateを使ったものに置き換えることができます。また、HTTPヘッダを変更(header_type()header_props()で)し、リダイレクトを設定することもできます。さらに、特定の条件下(例えば特定のランモードで、param()が特定の値の場合)のみ変更を適用するよう、オブジェクトプロパティを使用することもできます。

cgiapp_get_query()

 my $q = $webapp->cgiapp_get_query;

CGI.pm以外のクエリーインターフェースを使用したい場合、クエリーオブジェクト取得のために、このメソッドをオーバーライドしてください。

CGP.pmは、既定のリクエストに使われた場合のみロードされます。

CGI.pmの代わりに別のものが使用可能な場合も、それはCGI.pmのAPIとある程度互換性があるものでなければなりません。通常の使用では、paramメソッドの互換性を持っていれば十分でしょう。

mode_param()メソッドにpath_infoオプションを使用する場合は、クエリーオブジェクトのpath_info()メソッドが呼び出されます。

CGI::ApplicationでDumpメソッドを使用する場合は、クエリーオブジェクトのDump及びescapeHTMLメソッドが呼び出されます。

必要不可欠なアプリケーションメソッド

以下のメソッドはCGI::Applicationから継承され、アプリケーションモジュールから呼び出すことが可能なものです。必要不可欠と言っている理由は、これらがアプリケーションを稼動させるのに使われるものの大部分を占めるからです。以下、メソッドをアルファベット順に並べています。

load_tmpl()

    my $tmpl_obj = $webapp->load_tmpl;
    my $tmpl_obj = $webapp->load_tmpl('some.html');
    my $tmpl_obj = $webapp->load_tmpl( \$template_content );
    my $tmpl_obj = $webapp->load_tmpl( FILEHANDLE );

このメソッドはテンプレートファイル名又はテンプレートデータへのリファレンス、もしくはファイルハンドルを引数に取り、HTML::Templateオブジェクトを返します。ファイル名が未定義又はファイルが見つからない場合、CGI::Applicationはデフォルトでは、現在のランモード名の後に".html"を付けたものを使ってファイルを探そうとします。

デフォルトのテンプレート命名規則を使っている場合、CGI::Application::Plugin::Forwardを使うことで、制御をあるランモードから別のランモードへ移す際にも、現在のテンプレート名を正しく保持する事ができるでしょう。

(その他のテンプレートシステム及びテンプレート名の自動生成システムとの統合に関しては、後述の"load_tmpl()の代替手段"を参照してください。)

ファイル名が渡された場合、オブジェクトの作成にHTML::Template->new_file()コンストラクタが使用されます。一方、テンプレート内容へのリファレンスが渡された場合はHTML::Template->new_scalar_ref()コンストラクタが使用され、またファイルハンドルが渡された場合にはHTML::Template->new_filehandle()コンストラクタが使用されます。

HTML::Templateの具体的な使用法については、HTML::Templateを参照してください。

tmpl_path()が指定されている場合は、load_tmpl()はHTML::Templateのpathオプションに、そのパスを設定します。

load_tmpl()メソッドは、追加で指定されたパラメータを全てHTML::Template->new_file()(又はnew_scalar_ref()もしくはnew_filehandle())へ直接渡します。これにより、HTML::Templateオブジェクトはさらに柔軟にカスタマイズできるようになります:

    my $tmpl_obj = $webapp->load_tmpl('some_other.html',
         die_on_bad_params => 0,
         cache => 1
    );

追加のパラメータを渡し、なおかつデフォルトのテンプレート名を使いたい場合は、テンプレート名にundefを渡す必要があることに留意してください:

    my $tmpl_obj = $webapp->load_tmpl(undef,
         die_on_bad_params => 0,
         cache => 1
    );

load_tmpl()の代替手段

アプリケーションが上記よりもさらに特殊な動作を必要としている場合は、CGI::Applicationのサブクラスであるアプリケーションモジュールで独自のload_tmpl()を実装して、これを自由にオーバーライドすることができます。

まず、テンプレート関連のプラグインを確認するとよいでしょう。

CGI::Application::Plugin::TTはTemplate Toolkitとの統合に焦点を合わせており、テンプレート処理前・処理後のフックやシングルトンのサポートその他の機能を持っています。

ストリームやファイル以外のものを返したい場合は、CGI::Application::Plugin::Streamが役に立つことでしょう。これは単純な文法とMIMEタイプの自動判別機能を持っています。

html_tmpl_class()を使用してテンプレートクラスを指定する

html_tmpl_class()をオーバーライドすることで、HTML::TemplateとAPI互換のある代替モジュールを記述することができます。このメソッドはあなたのテンプレートシステムのクラス名を返却する必要があります。デフォルトでは、単に"HTML::Template"を返します。代替クラスは、少なくとも以下のHTML::Template APIを用意する必要があります:

 $t = $class->new( scalarref => ... );  # スカラーリファレンスのテンプレートを使う場合
 $t = $class->new( filehandle => ... ); # ファイルハンドルのテンプレートを使う場合
 $t = $class->new( filename => ... );
 $t->param(...);

実装例:

 sub html_tmpl_class { 'HTML::Template::Pro' }

load_tmpl()コールバック

プラグインの作者は、load_tmpl()が戻り値を返却する直前に実行されるコールバックを登録できるかどうかが気になることでしょう:

  $self->add_callback('load_tmpl',\&your_method);

your_method()が実行される時、次の3つの引数が渡されます:

 1. load_tmpl()に渡された追加パラメータのハッシュリファレンス。
 2. 続いて、テンプレートパラメータへのハッシュリファレンス。
    以上2つについて、逆参照して修正することで、テンプレートオブジェクトの
    new()及びparam()メソッドに実際に渡される値を変更することができる。
 3. テンプレートファイル名。

以下は、load_tmpl()コールバックの例です:

    sub my_load_tmpl_callback {
        my ($c, $ht_params, $tmpl_params, $tmpl_file) = @_
        # $ht_params及び$tmpl_paramsを逆参照して修正する...
    }

param()

    $webapp->param('pname', $somevalue);

param()メソッドで、アプリケーションの起動から終了までいつでも、アプリケーションインスタンスのプロパティにアクセスする事ができます。

param()メソッドの基本的な使い方は2つあります。1つ目は、パラメータの取得及び設定です:

    $webapp->param('scalar_param', '123');
    my $scalar_param_values = $webapp->param('some_param');

2つ目は、パラメータ名を指定せずにリストコンテキストで使用した場合、param()は、存在する全てのパラメータを含むリストを返します:

    my @all_params = $webapp->param();

また、param()メソッドにハッシュ(又はハッシュリファレンス)を渡すことで、一連のパラメータを一度に設定することもできます:

    $webapp->param(
        'key1' => 'val1',
        'key2' => 'val2',
        'key3' => 'val3',
    );

param()メソッドで、インスタンス単位でのカスタマイズ性を基本とした、高付加価値のシステムを作成できます。これは、1つのアプリケーションモジュールを、複数のスクリプトが個別にインスタンス化できる、ということです。それぞれのインスタンススクリプトは、パラメータ群にそれぞれ異なる値を設定できます。これにより、同種のアプリケーションは共通のコードベースを共有でき、かつ、それぞれに異なる動作を行わせることが可能です。例えば、1つのアプリケーションモジュールに複数のインスタンススクリプトを使ったメールフォームを想像してみてください。この場合、それぞれのインスタンススクリプトは、異なる宛て先を設定することができるでしょう。また、もう一つはWeb掲示板システムです。複数の板にそれぞれ異なるトピックや管理者を設定することができるでしょう。

new()メソッドは、起動時のパラメータを一度に指定するためのショートカットです。内部的には、CGI::Applicationはparam()メソッドを使用してそれらのパラメータをプロパティに設定します。param()メソッドは、アプリケーションの再利用性を大幅に向上する、強力なツールです。

query()

    my $q = $webapp->query();
    my $remote_user = $q->remote_user();

このメソッドは、アプリケーションモジュールをインスタンス化した時に作成されるCGI.pmのクエリーオブジェクトを取得します。このクエリーオブジェクトの詳しい使い方については、CGIを参照してください。CGI::Applicationは、CGIモジュールの上に成り立っています。一般的に言って、フォームデータの操作のためにクエリーオブジェクトを扱うのなら、CGI.pmには慣れ親しんでおきたいものです。

new()メソッドが呼び出された時は、自動的にCGIクエリーオブジェクトが作成されます。なんらかの理由があって、独自のCGIクエリーオブジェクトを作成したい場合は、new()メソッドでインスタンスを作成する際にQUERYオプションを使用することで、独自のクエリーオブジェクトを渡すことができます。

とても稀な例として、アプリケーションモジュールのインスタンスが作成された後に、独自のクエリーオブジェクトを渡したい場合があるかもしれません。そのようなケースでは、次のようにquery()メソッドへ渡してください:

    $webapp->query($new_query_object);
    my $q = $webapp->query(); # $new_query_objectが使用されるようになります

run_modes()

    # 一般的な使用法:サブルーチン名に一致するランモード名の配列リファレンス
    $webapp->run_modes([qw/
        form_display
        form_process
    /]);

   # 別の名前やコードレフをハッシュで渡す
   $webapp->run_modes(
           'mode1' => 'some_sub_by_name',
           'mode2' => \&some_other_sub_by_ref
    );

このアクセサ/ミューテータは、上のような文法で、アプリケーションの状態を表すディスパッチテーブルを定義します。このメソッドは、ディスパッチテーブルをハッシュとして返します。

run_modes()メソッドは、二回以上呼び出すこともできます。その場合、run_modes()に新たに渡されたランモードは、ディスパッチテーブルに追加されます。また、既存のランモードの定義が再度渡された場合は、新たな定義で上書きされます。この挙動は、他のアプリケーションから継承して作成されたアプリケーション、もしくはユーザーからの入力で機能の範囲が広がるような先進的なアプリケーションの場合に、とても役に立つかもしれません。

run()メソッドは、mode_param()で定義されたCGIパラメータ(デフォルトでは、"Run Mode"を意味する'rm')を読み取り、このディスパッチテーブルのデータを使用して適切な機能を起動します。これらの機能は"ランモードメソッド"と称されます。

このメソッドで設定するハッシュテーブルには、ランモード名がハッシュキーとして格納されます。またハッシュの値には、アプリケーションがそのランモードに入った時に呼び出されるランモードメソッドへのリファレンス(コードレフ)、又は呼び出されるべきランモードメソッドの名前のいずれかが設定されます:

    'mode_name_by_ref'  => \&mode_function
    'mode_name_by_name' => 'mode_function'

設定されたランモードメソッドは、最終的にブラウザへ渡されるべきテキストブロック(HTMLなど)を返します。テキストブロックは、スカラー又はスカラーリファレンスとして返却されます。

ランモードメソッドをリファレンスではなく名前で設定すれば、継承を使った派生アプリケーションをもっと簡単に作成できます。例えば、既存のアプリケーションから、一つだけ内容の異なるランモードを持つ新しいアプリケーションを作成する場合は、単に既存のアプリケーションを継承し、そのランモードをオーバーライドすれば良いでしょう。もし、ランモードをコードレフで設定していた場合は、継承したクラスは親クラスのコードを呼び出します。

ランモードメソッドを名前でなくコードレフで設定する事の利点は、パフォーマンスです。コードレフをデリファレンスするのは、コードブロックをeval()するより速いからです。もし実行時のパフォーマンスがクリティカルな問題であるなら、ランモードメソッドを名前でなくコードレフで設定してください。しかし、一般的に速度の差は小さいため、名前での設定の方がお勧めです。

ランモード名を配列リファレンスで設定する場合は、以下のようにします:

    $webapp->run_modes([ 'mode1', 'mode2', 'mode3' ]);

これは、次のようにハッシュのキーと値を指定するのと同じです:

    $webapp->run_modes(
        'mode1' => 'mode1',
        'mode2' => 'mode2',
        'mode3' => 'mode3'
    );

ランモード名を同名のメソッドに紐付けるのは、大抵の場合、構成的にとても理にかなっています。配列リファレンスの記法は、同じ挙動をしつつコードの冗長性を抑えるためのショートカットです。

ランモードをハッシュ又は配列リファレンスで設定することのもう一つの重要性は、明示されたPerlのメソッドだけがアプリケーションで呼び出されるのを保証することです。許可メソッドの明示ができず、他のメソッドを全て拒否するようになっていないアプリケーション環境は、安全とは言えず、任意のコードの実行を許してしまう危険性を秘めています。CGI::Applicationは、全てのメソッド起動に厳格な"デフォルトで拒否"のスタンスを貫いており、それによって安全なアプリケーションをその上に構築することができます。

ランモードメソッドに関する重要事項

あなたのアプリケーションは*決して*、標準出力へのprint()をしないようにしてください。print()を使用して標準出力へ出力を送ること(HTTPヘッダを含みます)は、継承されたrun()メソッドだけの排他的な領域です。このルールを破ることは、エラーの多発する原因になります。あなたのプログラムがHTTPヘッダより前にボディを送信するようなエラーが頻発するようになった場合、おそらくどこかでこのルールを破っています。

伝家の宝刀:"AUTOLOAD"ランモード

CGI::Applicationが、存在しないランモードを要求された場合、通常はエラーをcroak()します。もしこの挙動がイヤなら、予約語である"AUTOLOAD"という名前のランモードを実装することで、例外を捕捉できるかもしれません:

  $self->run_modes(
        "AUTOLOAD" => \&catch_my_exception
  );

CGI::Applicationは、croak()を呼び出す前に"AUTOLOAD"ランモードの存在をチェックします。存在する場合は、たった一つの例外を除いて、通常のランモードと同じように起動されます。そしてその例外とは、それを起動したランモードの名前を引数として受け取ることです:

  sub catch_my_exception {
        my $self = shift;
        my $intended_runmode = shift;

        my $output = "Looking for '$intended_runmode', but found 'AUTOLOAD' instead";
        return $output;
  }

この機能は、人間が読むことのできる簡素なエラー画面の表示や、より洗練されたアプリケーションの振る舞いのために使うことができます。

start_mode()


    $webapp->start_mode('mode1');

start_modeは、run_modes()テーブルに定義されたモード名を含んでいます。デフォルトのランモードは"start"です。mode_param()で指定されたCGIフォームのパラメータの値が未定義である場合はいつでも、ここで指定されたランモード名が使用されます。通常は、アプリケーションに最初にアクセスした時です。

tmpl_path()

    $webapp->tmpl_path('/path/to/some/templates/');

このアクセサ/ミューテータは、テンプレートファイルが配置されたディレクトリへのパスを設定します。load_tmpl()メソッドは、HTML::Templateのpathオプションを使用して、このパスの配下にあるテンプレートファイルを探します。パスを設定する場合は、テキストのスカラー値又は配列リファレンス(複数のパスの場合)をこのメソッドに渡します。

その他のアプリケーションメソッド

あなたがまだCGI::Applicationに慣れていないのなら、このセクションは読み飛ばしても構いません。

以下のメソッドはCGI::Applicationから継承されており、アプリケーションモジュールから呼び出すことが可能です。以下、アルファベット順に並べています。

delete()

    $webapp->delete('my_param');

delete()メソッドは、以前にnew()メソッドのPARAMSオプションもしくはparams()メソッドで渡され、アプリケーション内部に格納されているパラメータを削除するのに使用されます。これは、CGI.pmのdelete()メソッドに似ています。これは、前のセクションで取り除かれる可能性のあるパラメータの有無でアプリケーションの振る舞いを決定する場合や、単にparam()の後片付けをするのに役立ちます。

dump()

    print STDERR $webapp->dump();

dump()メソッドはデバッグ用の関数で、全ての環境変数や受け取ったWebフォームデータを含むテキストの塊を、人間に読みやすい形に整形して返します。標準エラーへの出力に好都合です。

dump_html()

    my $output = $webapp->dump_html();

dump()メソッドはデバッグ用の関数で、全ての環境変数や受け取ったWebフォームデータを含むテキストの塊を、Webブラウザを通して人間に読みやすい形に整形して返します。ブラウザへの出力に好都合です。

error_mode()

    $webapp->error_mode('my_error_rm');

何らかの理由でランモードが例外を投げた場合、run()メソッドはerror_mode()が定義されているかどうかをチェックします。もし定義されている場合、run()はこのメソッドをランモードとして呼び出し、$@だけを引数として渡します。

プラグインの作者向けの情報として、error_mode()が呼び出される直前にerrorフックが実行され、エラーメッセージが唯一の引数として渡されることを記しておきます。

デフォルトでは、error_mode()は定義されていません。error_mode()は例外を捕捉しないため、独自の方法で例外処理を行うこともできます。

その他、完全に統合されたロギングソリューションの情報としては、CGI::Application::Plugin::LogDispatchを参照してください。

get_current_runmode()

    $webapp->get_current_runmode();

get_current_runmode()メソッドは、現在実行中のランモード名を含むテキストのスカラー値を返します。setup()中など、ランモードが決定されていない場合は、このメソッドはundefを返します。

header_add()

    # 'type'ヘッダを追加又は置き換える
    $webapp->header_add( -type => 'image/png' );

    - 又は -

    # クッキーを追加する
    $webapp->header_add(-cookie=>[$extra_cookie]);

header_add()メソッドは、クライアントへ返されるレスポンスヘッダへ1つ以上のヘッダを追加するのに使用します。このメソッドに渡された引数は、最終的にはCGI.pmのheader()メソッドへ渡されますので、より詳しい使用法などの情報についてはCGIを参照してください。

header_props()の呼び出しと異なり、header_add()は既に存在するヘッダはそのままにします。ただし、header_add()にスカラー値が渡された時、もし同じキーのヘッダが既に存在している場合は、これを上書きします。

header_add()に配列リファレンスが渡された場合は、渡された配列リファレンスの中の値は指定されたキーに追加されます。これは主に、既にセットされたクッキーに追加の値をセットするのに役立ちます。

header_props()

    $webapp->header_props(-type=>'image/gif',-expires=>'+3d');

header_props()メソッドは、CGI.pmに互換性のあるHTTPヘッダプロパティのハッシュを前提としています。このメソッドに指定された引数は、そのままCGI.pmのheader()又はredirect()メソッドへ渡されます。より詳しい使用法などの情報についてはCGIを参照してください。

header_props()を引数を付けて呼び出すと、指定されたヘッダの値は新しいものに置き換えられます。

また、header_props()を引数なしで呼び出すと、現在設定されている全てのヘッダのハッシュを返します。単に、現在設定されているヘッダを取得したい場合に、このように呼び出すことができます。

既存のヘッダの値を破棄することなく値を追加したい場合は、header_add()を使用してください。

HTTPヘッダに関する重要事項

クライアントへ返されるHTTPレスポンスヘッダの修正は、header_props()及びheader_add()を通して行うことができます。これは、クッキーをセットしたり、MIMEタイプを"text/html"以外のものにしたり、あるいはリダイレクトしたい場合に行う必要があります。header_props()メソッドは、header_type()メソッドと連携して機能します。header_type()に設定された値は、CGI::header()又はCGI::redirect()のどちらのメソッドを呼び出すかを決定します。header_props()に設定された値は、どちらのメソッドを呼び出すかに係わらず、呼び出すメソッドへ引数として渡されます。

HTTPヘッダを適切に扱いたい場合は、これらの関連性を理解することが重要です。

header_type()

    $webapp->header_type('redirect');
    $webapp->header_type('none');

このメソッドは、リダイレクト用のヘッダを設定していること、又はフレームワークからヘッダを返さないことのいずれかを宣言するのに使われます。

デフォルトは'header'という値ですが、これはほとんど使われることはありません。

リダイレクトの例:


  sub some_redirect_mode {
    my $self = shift;
    # 何らかの処理...
    $self->header_type('redirect');
    $self->header_props(-url=>  "http://site/path/doc.html"; );
  }

もっと簡単に記述したい場合は、CGI::Application::Plugin::Redirectuseして、以下のように記述してください:

    return $self->redirect('http://www.example.com/');

コンテンツをストリーミングする場合は、ヘッダの値を'none'に設定すると良いでしょう。あるいは、$ENV{CGI_APP_RETURN_ONLY} = 1;で、ヘッダを含む全ての出力を抑制し、代わりに出力を返すという方法でも良いでしょう。

これはテストの時や、CGI::Applicationをcronスクリプトのコントローラとして使う場合に一般的な方法です!

mode_param()

 # ランモード名を含む、CGIフォームのパラメータ名。
 # デフォルトの動作であり、通常はこれで十分。
 $webapp->mode_param('rm');

 # ランモード名をコードレフから直接設定する。
 $webapp->mode_param(\&some_method);

 # その他、$ENV{PATH_INFO}からランモード名を
 # 直接設定することも可能。
 $webapp->mode_param(
        path_info=> 1,
        param =>'rm'
 );

このアクセサ/ミューテータは、一般的にsetup()メソッドの内部で呼び出されます。これは、呼び出すべきランモードを決定するのに使用されます。呼び出し方は3通りあります。

 $webapp->mode_param('rm');

上記は、ランモード名を含むCGIフォームのパラメータを定義します。これはデフォルトの動作で、'rm'がパラメータ名として使われます。

 $webapp->mode_param(\&some_method);

上記は、コードレフを設定します。このコードレフは直接ランモード名を返します。例:

 sub some_method {
   my $self = shift;
   return 'run_mode_x';
 }

これにより、ランモードを任意のロジックでプログラム的に設定することができます。

 $webapp->mode_param(
        path_info=> 1,
        param =>'rm'
 );

この方法は、環境変数$ENV{PATH_INFO}からランモードを簡単に設定することができます。この方法では、$ENV{PATH_INFO}の最初の部分(最初の"/"より前)からランモード名を取得しようと試みます。$ENV{PATH_INFO}の2番目の部分からランモード名の取得を試みる場合は、次のようにします:

 $webapp->mode_param( path_info=> 2 );

上記は、paramハッシュキーを省略できる点についても示しています。この場合、デフォルトとしてrmが指定されます。

path_infoにマイナスの値を設定することもできます。これは、配列のマイナスの添え字と同じように働きます:-1が指定された場合は$ENV{PATH_INFO}の最後の部分から、-2ならその前の部分から等、ランモード名の取得を試みます。

$ENV{PATH_INFO}にランモード名が見つからなかった場合は、自動的に、上記の'param'で定義されたCGIフォームフィールドの値をチェックする方法に切り替わります。これにより、ほとんどの場合は便利な$ENV{PATH_INFO}のトリックを使う一方で、ランモードが不明の場合に備えて事前にJavaScriptでそれを定義しておきたい、というような場合にも対応できます。

$ENV{PATH_INFO}に関するさらなる情報.

$ENV{PATH_INFO}でランモード名を設定するようにすれば、送信したフォーム変数とランモード生成方法をすっきりと分けることができます。さらにこの方法は、検索エンジンにより親和性の高いURLを生成します。この記法を使用したフォーム送信の例を見てみましょう:

    <form action="/cgi-bin/instance.cgi/edit_form" method=post>
        <input type="hidden" name="breed_id" value="4">

この例では、ランモードは"edit_form"になります。次は、クエリー文字列のもう一つの例です:

    /cgi-bin/instance.cgi/edit_form?breed_id=2

この例は、$ENV{PATH_INFO}とクエリー文字列を問題なく併用できることを示しています。$ENV{PATH_INFO}はCGIの仕様の一部として定義されており、CGIスクリプトをサポートするWebサーバはこの仕様に準拠しているはずです。

prerun_mode()

    $webapp->prerun_mode('new_run_mode');

prerun_mode()メソッドは、cgiapp_prerun()メソッドの内部で使用できるアクセサ/ミューテータで、これから実行されるランモードを変更します。例えば、以下をご覧ください:

  # WebApp.pmで:
  package WebApp;
  use base 'CGI::Application';
  sub cgiapp_prerun {
        my $self = shift;

        # もしあれば、webユーザー名を取得する
        my $q = $self->query();
        my $user = $q->remote_user();

        # 必要なら、ログイン画面へリダイレクト
        unless ($user) {
                $self->prerun_mode('login');
        }
  }

この例では、ログインしていないwebユーザーは強制的に"login"ランモードが実行されます。prerun_mode()メソッドにはテキストのスカラー値を渡すことができ、以前にどんなランモードが設定されていても、それを上書きします。

cgiapp_prerun()メソッドの内部でprerun_mode()メソッドを使用することは、mode_param()にサブルーチンのコールバックを設定するのとは違います。なぜならcgiapp_prerun()は、それ自身のロジックを元にランモードを選択できるからです。一方、mode_param()のコールバック機構は、CGI::Applicationのランモード決定メカニズムを、あなた独自のメソッドで完全に置き換えることを強いるものです。prerun_mode()メソッドは、CGI::Applicationの通常のランモード切り替え機構を使用したい場合で、かつランモードを特定の条件下で選択的に変更したい場合に使用するのが良いでしょう。

注意:prerun_mode()メソッドは、cgiapp_prerun()メソッドの内部からのみ、呼び出すことができます。例えばsetup()やランモードメソッドなど、別の場所でprerun_mode()を呼び出した場合は、アプリケーションはdie()します。

綺麗なURIでランモードを起動する

最近のWebフレームワークは、お粗末なURIをなくし、代わりに綺麗なURIを用意します。例えば:

 /cgi-bin/item.cgi?rm=view&id=15

のようなURIの代わりに、同じリソースを指す、次のようなURIを用意します:

 /item/15/view

これらのURIとランモードの紐付けはディスパッチと呼ばれ、CGI::Application::Dispatchがこれを扱います。ディスパッチは必須ではなく、後からとても簡単にアプリケーションに追加することができるレイヤーです。

オフラインでのWebサイト開発

デスクトップやラップトップPCでCGI::Applicationを使ったWebアプリケーションを開発するのに、機能満載のwebサーバをインストールする必要はありません。代わりに、CGI::Application::ServerをCPANからインストールしてください。セットアップから数分後、自分だけの開発用アプリケーションサーバを起動することができます。

自動化されたテスト

CGI::Application向けに特別に開発されたテスト用モジュールが、2つあります。

Test::WWW::Mechanize::CGIAppは、Webサーバを起動しなくても、CGI::Appベースのプロジェクトをテストすることができます。Test::WWW::Mechanizeは実際のWebサーバを通してアプリケーションをテストすることができます。

Test::WWW::Selenium::CGIAppも同様ですが、テストにSeleniumを使用します。これは、ローカルのWebブラウザが使われ、JavaScriptを含めたテストが可能であることを意味します。

直接テストするのも簡単です。CGI::Applicationは通常ランモードの出力内容を直接標準出力へ吐き出します。これは、環境変数CGI_APP_RETURN_ONLYを定義することで抑制することができます。例えば:

  $ENV{CGI_APP_RETURN_ONLY} = 1;
  $output = $webapp->run();
  like($output, qr/good/, "output is good");

このテストスタイルの例は、私たちのテストスィートで見ることができます。

プラグイン

CGI::Applicationは、簡単に作れて簡単に使えるプラグインアーキテクチャを採用しています。

お勧めのプラグイン

次のプラグインは、一般的なWeb/DB開発用途にお勧めのプラグインです:

その他のプラグイン

代替用又は特定用途向けに、さらに多くのプラグインが利用可能です。現在の完全なリストについては、CPANをあたってみてください:

http://search.cpan.org/search?m=dist&q=CGI%2DApplication%2DPlugin

プラグインの使い方については、それぞれの紹介ページを参照してください。

プラグインを書く

プラグインを書くのはとても簡単です。新しいパッケージを作成し、CGI::Application内部で使いたいメソッドをエクスポートするだけです。例として、CGI::Application::Plugin::ValidateRMをご確認ください。

CGI::Applicationオブジェクト内で名前空間の衝突を回避するため、プラグイン開発者は、プラグインパッケージ名などの一意のプレフィックスを、情報を格納する際に使用することをお勧めします。例えば:

 $app->{__PARAM} = 'foo'; # 良くないです!衝突の可能性があります。
 $app->{'MyPlugin::Module::__PARAM'} = 'foo'; # 良いです。
 $app->{'MyPlugin::Module'}{__PARAM} = 'foo'; # 良いです。

高度なプラグインを書く - コールバックを使った方法

プラグインを書く際に、例えばデータベースへ接続する時やセッションを初期化する時など、特定のタイミングで自動的にアクションを起こすようなことがしたいかもしれません。以下のような'コールバック'メソッドを使用すれば、特定のタイミングに起動するサブルーチンを登録し、目的を達成することができます。

コールバックの例

  # 標準のCGI::Applicationフック(以下)のいずれかへコールバックを登録する
  #   'init'、'prerun'、'postrun'、'teardown'及び'load_tmpl'
  # プラグイン作者にとっては、上記のメソッド以外は必要ないと思われる。

  # クラスベース:コールバックはアプリケーションの最初から最後まで永続する
  $class->add_callback('init', \&some_other_method);

  # オブジェクトベース:コールバックはオブジェクトと同じ期間だけ生存する
  $self->add_callback('prerun', \&some_method);

  # アプリケーション中で、新たなフック場所を作成したい場合は、
  # フックの作成及び呼び出しに関して、次の2つのメソッドを知っておく
  # 必要がある。

  # 新たなフックを作成する
  $self->new_hook('pretemplate');

  # 後で、フックに登録された全てのコールバックを実行する
  $self->call_hook('pretemplate');

コールバックメソッド

add_callback()

        $self->add_callback ('teardown', \&callback);
        $class->add_callback('teardown', 'method');

add_callbackメソッドは、指定されたタイミング(フック)で呼び出されるコールバック関数を登録することができます。指定可能なフックは'init'、'prerun'、'postrun'、'teardown'及び'load_tmpl'で、それ以外のフックはnew_hookメソッドで定義することができます。

登録するコールバックは、サブルーチンのリファレンス又はメソッドの名前で指定します。

同じフックに複数のコールバックを登録した場合は、それらは順次実行されます。実行される順番は、どのクラスがコールバックを登録したかによります。後述のコールバックの順序を参照してください。

コールバックは、オブジェクトベース又はクラスベースのいずれかで登録でき、これはadd_callbackメソッドをオブジェクトメソッドかクラスメソッドのいずれで呼び出したかによります:

        # オブジェクトベースのコールバックを登録する
        $self->add_callback('teardown', \&callback);

        # クラスベースのコールバックを登録する
        $class->add_callback('teardown', \&callback);
        My::Project->add_callback('teardown', \&callback);

オブジェクトベースのコールバックは、Webアプリケーションの$cオブジェクトへ格納されます;リクエストの処理が終了し、$cオブジェクトがスコープ外へ消える時、コールバックも一緒に消滅します。

オブジェクトベースのコールバックは、現在処理中のアプリケーションに一度だけ適用されるタスクに向いています。例えば、全てのHTMLをブラウザへ送信した後、長時間を要するプロセスをリクエストの処理の終わりで起動するコールバックを、teardownフックにインストールすることができます。

クラスベースのコールバックは、Perlプロセスが稼動している間生存します(mod_perlPersistentPerlのような永続環境では、一つのPerlプロセスが多くのWebリクエストを処理します)。

クラスベースのコールバックは、全てのWebアプリケーションに機能を追加するプラグインに適しています。

クラスベースのコールバックのもう一つの機能は、プラグインがフックの作成とコールバックの登録を一度にできるということです―これは、Webアプリケーションの$cオブジェクトが初期化される前であったとしてもです。これを行うのに適した場所は、プラグインのimportサブルーチンの中です:

        package CGI::Application::Plugin::MyPlugin;
        use base 'Exporter';
        sub import {
                my $caller = scalar(caller);
                $caller->add_callback('init', 'my_setup');
                goto &Exporter::import;
        }

$caller->add_callbackは、次の行を含むモジュールのためにコールバックをインストールすることに留意してください:


        use CGI::Application::Plugin::MyPlugin;

new_hook(HOOK)

    $self->new_hook('pretemplate');

new_hook()メソッドは、開発者のために、コールバックを登録できる新しい場所を作成します。このメソッドは、引数にフックの名前を取ります。もし存在しなければ、フックの場所が新たに作成されます。このメソッドは、常に真を返します。

例えばCGI::Application::Plugin::TTは、全てのテンプレート処理の前後に、フックを追加しています。

どのようにフックが呼び出されるかについて、詳細はcall_hook(HOOK)を参照してください。

call_hook(HOOK)

    $self->call_hook('pretemplate', @args);

call_hookメソッドは、フックに登録されたコールバックを実行するのに使われます。このメソッドは、新しいフックの場所を追加するnew_hookメソッドと連携して使用されます。

call_hookの最初の引数は、フックの名前です。それ以降の引数は全て、フックの場所でコールバックが呼び出される都度、そのコールバックに渡されます。以下は、'pretemplate'フックのコールバックの例です:

 sub my_hook {
    my ($c,@args) = @_;
    # ....
 }

フックは半パブリックな場所であることに留意してください。フックの呼び出しは、現在のオブジェクトによってフックに登録されたコールバックを実行することを意味し、また、そのオブジェクトの親クラスによって登録されたコールバックを実行することをも意味します。正確な実行順序に関しては以下をご覧ください。

コールバックの順序

オブジェクトベースのコールバックは、クラスベースのコールバックの前に実行されます。

クラスベースのコールバック内の順序は、実行中のアプリケーションの継承ツリーによって決まります。組み込みメソッドであるcgiapp_initcgiapp_preruncgiapp_postrun及びteardownも、後述の順序で同様に実行されます。

永続環境では、メモリ上に同時に多数のアプリケーションが存在しているかもしれません。例えば:

        CGI::Application
            Other::Project  # CGI::Application::Plugin::Bazを使用する
                Other::App  # CGI::Application::Plugin::Bamを使用する

        My::Project         # CGI::Application::Plugin::Fooを使用する
            My::App         # CGI::Application::Plugin::Barを使用する

上記のプラグインが、それぞれ以下のように'init'ステージで実行されるコールバックを追加した場合:

        プラグイン                       'init'コールバック
        -----------------------------    ------------------
        CGI::Application::Plugin::Baz    baz_startup
        CGI::Application::Plugin::Bam    bam_startup

        CGI::Application::Plugin::Foo    foo_startup
        CGI::Application::Plugin::Bar    bar_startup

My:Appが実行されたとき、foo_callbackbar_callbackが実行されます。その他のコールバックはスキップされます。

My::App@ISAリストは次のとおりです:

        My::App
        My::Project
        CGI::Application

この順序が、コールバックの実行順序を決定します。

My::Appアプリケーションでcall_hook('init')が実行されたとき、これらのモジュールによってインストールされたコールバックが、次の順序で実行されます:bar_startup、次にfoo_startup、最後にcgiapp_init

単一のクラスが二つ以上のコールバックを同じフックにインストールした場合は、登録された順(FIFO)にコールバックが実行されます。

コミュニティ

CGI::Applicationをもっと学習したり議論したい人が利用可能な主要なリソースを、以下に示します。

Wiki

これは、誰でも参加可能なコミュニティによって構築され、メンテナンスされているリソースです。ここでは、多くの記事やCGI::Application関連の外部リンクが掲載されています:

http://www.cgi-app.org

サポートメーリングリスト

もし質問事項やコメント、バグ報告や機能提案があれば、サポートメーリングリストへ投稿してください!メーリングリストへの参加は、"cgiapp-subscribe@lists.erlbaum.net"へ空のメッセージを送信するだけでできます。

IRC

irc.perl.org#cgiappへ顔を出せば、CGI::Applicationプロジェクトに参加している人を見つけられるかもしれません。

ソースコード

このプロジェクトは、darcsソース管理システム(http://www.darcs.net/)によって管理されています。darcsのアーカイブはこちらにあります:http://mark.stosberg.com/darcs_hive/cgi-app

こちらもご覧ください

o

CGI

o

HTML::Template

o

CGI::Application::Framework - CGI::Applicationをベースにした、フル装備のWebアプリケーションです。http://www.cafweb.org/

その他の読み物

CGI::Applicationに関する情報をもっとお探しなら、Perl.comで次の記事が参照できます。

    Using CGI::Application
    http://www.perl.com/pub/a/2001/06/05/cgi.html

    Rapid Website Development with CGI::Application
    http://www.perl.com/pub/a/2006/10/19/cgi_application.html

これらの記事を出版し、またPerlコミュニティに計り知れない価値をもたらしてくれたO'Reillyに感謝します。

著者

Jesse Erlbaum <jesse@erlbaum.net>

Mark Stosbergはバージョン3.2からの共同メンテナーで、また彼以外にも、Changesファイルに記された幾多の寄稿者の助力がありました。

クレジット

CGI::Applicationは当初、New York Cityのソフトウェアエンジニアリング・コンサルティング会社であるErlbaum Groupによって開発されました。

このライブラリの初期の開発に投資し、世界に向けたリリースにあたってJesse Erlbaumを勇気付けてくださったVanguard Media(http://www.vm.com)に感謝します。

数年に渡って、このモジュールに対して数え切れないほど貢献をし、CPANへ上げるために重いケツを蹴飛ばしてくれたSam Tregar(素晴らしいHTML::Templateモジュールの作者です!)に、とても感謝しています!

多くの方が、具体的な提案やパッチを送ってくださいました。彼らの名前は、Changesファイルに記されています。

CGI-Appメーリングリストの全メンバーにも感謝しています!あなたたちのアイデアや提案、見識(それと批評!)は、このモジュールを形作るのに計り知れないほどの助けとなりました(メーリングリストへの参加は、"cgiapp-subscribe@lists.erlbaum.net"へ空のメッセージを送信するだけでできます)。

ライセンス

CGI::Application : Framework for building reusable web-applications Copyright (C) 2000-2003 Jesse Erlbaum <jesse@erlbaum.net>

This module is free software; you can redistribute it and/or modify it under the terms of either:

a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version,

or

b) the "Artistic License" which comes with this module.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details.

You should have received a copy of the Artistic License with this module, in the file ARTISTIC. If not, I'll be glad to provide one.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

原文へのリンク

CGI::Application

翻訳者

Bahoo! <mlf22270@nifty.com> (翻訳:2009年5月31日)

これまでに翻訳したpod一覧