速構Web Frameworkとは?

Webシステムの開発には、理解するのが困難な高度な技術上の概念が必要とされているわけではありません。 本当に必要なのは、良い企画・組織化された開発チーム・開発者にフィットするライブラリ・ツール類・高速-安定-高い保守性 を持つ動作環境です。

開発者にとっては、欲するものが当たり前に提供されるべきなのですが、現実は食い違っています。 私たちは、理想的ではあるが実現像が不明確な聞こえばかりが良い手法ではなく、目的を高効率で実現できる開発手法を提供したいと考えています。適切な実現手法の選択・当然あってしかるべきツールの提供です。

本稿では、この考えに基づき作成したWebシステム開発の為のPHPフレームワークをご紹介させていただきます。


対象バージョン: 速構Web Framework ver1.1.6 PHP版
関連: http://www.pm9.com/newpm9/itbiz/php/framework/
作成: 2005/7/26 修正: 2005/9/20


目次

フレームワークの適用分野

当フレームワークの適用分野は、次のようなものを想定しています。

実現項目

このフレームワークは、次のようなことを実現します。

適度なモジュール分割による、開発作業の分業化の実現

デザイン・プログラム・テスト環境に対するモジュール分割方式の提供

開発作業の自動化・パターン化

Web上の表現の定石に対する処理のパターン化
データ属性による入出力処理のパターン化(データディクショナリ)

学習容易性の実現

MVCモデルベース(VB程度の抽象化されたモデル)
きわめて簡潔なプログラム記述
ルールの数を必要最小限にまで減らす
学習容易性に主眼を置いたシステム構造、処理の抽象化

導入・保守の容易性

デザイン、プログラム開発、運用に関するデファクトスタンダードの採用

必要な運用環境の提供

複雑なWebシステムの実現を可能とするには?

(複雑なWebシステムとは?)
(解決方法)
プロトタイピング手法による開発

主な技術要素

ポータル・ベース テクノロジー

一つのHTMLウィンドウ内に独立して動作する複数のアプリケーションポートレット(以下、単にポートレットと呼びます)を表示させることができます。

一見複雑に見えるコマースサイトやEIP等は、複数の単機能ポートレットの集合体とみなすことができます。 それぞれのポートレットの開発・テスト・デプロイ・運用を独立した単位で行なうことができます。

データディクショナリベース・データフローコントロール

クラスタリング、High Availability対応

テスト、運用時トレース・スナップショット

速構WebFrameworkの構成要素

このシステムは、一般的なウィンドウシステムに近い構造により実現されています。
(ディスパッチャ、イベントドリブンによる動作構造)

外面的なデザインと内部処理ロジックを完全分離するために、MVCモデルを採用しています。

しかし開発者にとっては上記にあげた複雑な概念を細かく意識する必要はなく、簡単なCGIプログラムを作成するような感覚でアプリケーションを開発することができます。

以下、システムの構築に際し知っておく必要のある構成要素について説明いたします。

レイアウトテンプレート

このフレームワーク上では複数のアプリケーションポートレット(業務プログラム、例えば商品情報検索、ユーザ情報管理、Webメール、メニュー、etc)を各々独立性を保たせながら同時に一つのWeb画面上で実行することができます。 レイアウトテンプレートは、それらのポートレットをWeb画面上にレイアウトする為のHTMLファイルです。

個々のポートレットは、入出力処理をレイアウト「枠」を通して行ないます。 そして、各ポートレットは担当部分のHTMLコードを出力し、レイアウトテンプレートとともに1つのHTMLにマージされてブラウザに出力されます。

一般的な開発では、レイアウトテンプレートを複数ファイル用意し、業務の流れが大きく変わるところで、ポートレットからの指示により別のレイアウトテンプレートに切り替えます。例えばメニュー管理ポートレットがユーザからの業務開始ボタンのクリックを検出したときに該当する業務ポートレットを処理する為のレイアウトテンプレートを表示する等です。

レイアウトテンプレートの例:
<html>
<body>
<table>
  <tr>
    <td>{&menu}</td><td>{&shopcart}</td>
  </tr>
</table>
</body>
</html>

※ 当システムでは、基本的には定型的な業務を実現することを目標にしています。 当システムのレイアウトテンプレートは、各業務に特化したレイアウトデザインとなることが前提となります。

※ 全体を統括するDispatcherプログラムが起動すると、現在の表示対象となっているレイアウトテンプレートが読み込まれ、その上に配置されているポートレットのプレゼンテーションロジック(画面組み立てロジック)が起動されます。

ポートレット

業務アプリケーションを実現するためのプログラム、テンプレート、変数等です。

テンプレート

テンプレートは、ポートレットが出力するべき自分の担当部分のHTMLを定義するものです。 通常、複数のテンプレートファイルを用意し、動作の状況(ステータス)に応じて適切なテンプレートを選択できるようにします。

テンプレートは通常のHTML形式ですが、プログラムからのデータの流し込み処理・繰り返し部分の表示処理・入力チェック処理を行う為の定義をHTMLの仕様に沿った形で仕様拡張してあります。

<input type="text" name="ITEM_NAME" value="{ITEM_NAME}" {?ITEM_NAME}>
  // {ITEM_NAME}:変数タグ
  // {?ITEM_NAME}:入力チェックタグ
<table>
<!-- START BLOCK : LIST_BL -->
<tr>
<td> ... </td><td> ... </td>
</tr>
<!-- END BLOCK : LIST_BL -->
</table>
  // <!-- START BLOCK : LIST_BL -->:繰り返し表示部分の定義

複数のポートレットの「枠」にまたがるようなFormを記述をした場合、動作を保障できません。 ポートレットは、テンプレートを利用しないで直接ブラウザに対しHTMLを直接出力することはできません。

ステータス

ステータスは、ポートレットの現在の動作状態を表すもので、開発者が定義します。

ステータスの例
search: 検索処理中
list: 検索結果一覧
edit: データ編集
edit_conf: 編集内容確認
edit_fini: DB登録

各ポートレットが、ステータス情報を管理し状況に応じて変更することができます。

定義したステータスに対し、後述するプレゼンテーションロジック、コントロールロジックをそれぞれ1組づつ定義する必要があります。

まだポートレットのステータスが設定されていない状態で、初めてディスパッチャーがポートレット起動する場合、ディスパッチャーはそのポートレットのステータスを「start」に設定します。

ポートレット変数

ポートレット変数は、ポートレットの持つアプリケーションデータを永続的に保持することができる特殊な変数領域です。
※永続性:Submitして次の画面に遷移しても変数が消去されない性質

ポートレット変数の有効期間は、ユーザがブラウザを起動してからウィンドウを閉じるまでの間です。 ポートレットが一時的にレイアウトテンプレートに配置されていない状態であったとしても、ポートレット変数およびステータスの値は保持されます。

ポートレットは、複数のポートレット変数を持つことができます。
また、一つのポートレット変数は配列Typeを含めたあらゆる型の変数を辞書式に複数格納可能な連想配列です。
各ポートレット変数には識別子が付いており、状況に応じて使い分けることができます。

$portletvars['shopcart_search'] -- 商品検索・検索条件入力画面用
$portletvars['shopcart_cart']   -- 商品購入・カート画面用

「カレント変数」と呼ばれるポートレット変数が標準で提供されます。
この「カレント変数」は$portletvars[実行中のポートレットの名称]と等価です。
また、「カレント変数」は「$_」と表記されます。
状況に応じてカレント変数を他のポートレット変数に割り当て直すことができます。

ポートレットのFormがSubmitされると、フォームパラメータの各パラメータ名と同名の配列要素値でポートレット変数の各値が入力されたパラメータ値で上書きされます。

<input type="text" name="user">

上記のように記述した場合、FormがSubmitされるとポートレット変数の該当要素にデータが設定されます。

$_['user']

パラメータを配列定義することもできます。

<input type="text" name="line[1][user]">

上記のように記述した場合は、ポートレット変数の下記の要素にデータが設定されます。

$_['line'][1]['user']

*Formのname属性を配列として定義する場合、配列の要素名の前後に「'」や「"」を記述しないで下さい。
<input type="text" name="line[1][user]"> の 「user」の前後

ポートレット変数の利用イメージ

ポートレット変数は、ホワイトボードのようなものです。利用方法を例えて言うと下記のようになります。

コントロールパラメータ

テンプレートの作成ルールとして、コントロールパラメータと呼ばれる特殊なパラメータをForm内およびリンクに記述することになっています。このパラメータにはポートレットのステータス情報が埋め込まれます。

ユーザがブラウザ画面からFormをSubmitした際、このパラメータに基づいて、適切なポートレット・ステータスに対応するメッセージ処理ロジックが起動されます。

Form用コントロールパラメータの例:
<form action="i.php">
{_CONTROL}
<input type="submit" name="_ACTION[next]" value="確認">
</form>
URL用コントロールパラメータの例:
<a href="i.php?{_CONTROL_URL}&_ACTION[next]=1">確認</a>

アクションパラメータ

Formやリンクに記述する処理分岐判断の為のパラメータです。 Submitもしくはリンククリック時、コントロールロジックは、アクションパラメータを参照してその内容に応じた処理を実行します。

アクションパラメータの文字列は開発者が任意に決めることができます。

アクションパラメータ記述例:(下記の3種類の記述方法があります)
<input type="submit" name="_ACTION[search]" value="検索">
<a href="i.php?{_CONTROL_URL}&_ACTION[search]">検索</a>
<input type="hidden" name="_ACTION_" value="search">
コントロールロジックの例:
switch($action) {
// 該当ポートレットの'検索'ステータスへ推移
case 'search':  exec_portlet(null, 'search'); break;
// レイアウトテンプレートを編句してトップページへ推移
case 'toppage':  change_frame('index_toppage.html'); break;
}

プレゼンテーションロジック

プレゼンテーションロジックは、ポートレット編集やDBの内容等を反映した表示画面の組み立てを行ないます。 ブラウザ用画面組み立ての際、ディスパッチャにより画面表示に必要なプレゼンテーションロジックが起動されます。

各ポートレットステータス毎に、対応したプレゼンテーションロジックを用意する必要があります。
どのプレゼンテーションロジックが画面表示の為に実行されるかは、表示対象のポートレットの現在のステータス値によって決まります。

ポートレットのプレゼンテーションロジックの内容は、通常下記のようになります。

  1. 表示用テンプレートの指定
  2. 画面に表示すべきDBの検索等
  3. テンプレートへのポートレット変数やDBの検索結果等のアプリケーションデータの流し込み

テンプレートへのデータの流し込みについては、各種のユーティリティ関数が用意してあり、データディクショナリとの組み合わせで、少ないステップで表示ロジックを組立てることができます。

プレゼンテーションロジックの実装例:
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'cart.html');
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
$win->set_values('default_constructor', $rec);
$win->finish();

テンプレートに流し込む文字列は、変数タグ毎に設定していくことも可能ですが、連想配列・変数を使用して変数タグ名に対応した内容を一括して流し込むことができます。一括流し込みの際は、データディクショナリにより変数タグ毎に表示ルールが適用されます。細かな設定を行なうために変数タグにアトリビュート属性を設定することも可能です。

コントロールロジック

FormがSubmitされるとディスパッチャにより、そのFormを生成したポートレットとそのステータスに対応するコントロールロジックが起動されます。 コントロールロジックは、パラメータの内容によりDB処理や画面遷移(レイアウトテンプレートの変更、ポートレットステータスの変更)処理を行ないます。

Submitの際、カレント変数(ポートレット変数)の各データがForm内の各パラメータにより上書きされます。

リンクがクリックされた場合もSubmit時と同様にコントロールロジックの起動、カレント変数の上書きが行なわれます。

ポートレットのコントロールロジックの内容は、通常下記のようになります。

  1. アクションパラメータによる処理の分岐
  2. データ入力チェック(データチェックディクショナリを利用した一括チェック
    必要であれば入力画面に戻るように制御する
  3. 入力データの正規化
  4. DB更新
  5. ポートレットステータス変更(次の画面表示のタイミングでステータスに応じたポートレット画面が表示される
  6. 必要であれば、レイアウトテンプレートの切替
    コマースサイトにおける例: 商品紹介ページから購入ページへの切替

ポートレットコモンロジック

ポートレットの為のプログラムロジック格納ディレクトリにポートレットコモンロジック定義ファイルを設置すると、プレゼンテーションロジック、コントロールロジックの実行の直前にポートレットコモンロジックが実行されます。 ポートレットコモンロジック定義ファイルの名称は、「_common.php」です。

ポートレット間インターフェース

ポートレットの為のプログラムロジック格納ディレクトリにポートレット間インターフェース定義ファイルをを設置しインターフェース関数を定義すると、他のポートレットから機能呼び出しを受けうことができるようになります。 ポートレット間インターフェース定義ファイルの名称は、「_interface.php」です。

ポートレット間インターフェース関数の定義:
function ポートレット名__インターフェース名(引数1, 引数2, ...) {
  // ロジックを記述
}
ポートレット間インターフェース呼び出し側の記述:
pm9mvc::call_portlet_function(ポートレット名,  ポートレット名__インターフェース名,
     引数1, 引数2, ...);

データディクショナリ

ポートレットの作成の際、入力処理(入力チェック、入力データ正規化)、出力処理(DBからの読み込み、データフォーマッティング)、DB更新処理 毎に開発者が処理ロジックを記述するのではなく、データの性質毎にルールを用意し、実行時にフレームワークがルールを参照しながらデータ項目毎に自動的に処理を行ないます。

各ルールは、データディクショナリにて一括管理されます。

データの分類処理は、開発者がフィールド名称の文字列パターン判定ロジックの実装を行なうことにより実現します。

if (strstr($field_name, '_DATETIME')) {
  $data = strftime('%Y/%m/%d %H:%M:%S', $field_value);
} else if (strstr($field_name, '_DATE')) {
  $data = strftime('%Y/%m/%d', $field_value);
} else if (strstr($field_name, '_PRICE')) {
  $data = number($field_value);
}

データ表示ロジックディクショナリ

プレゼンテーションロジックにより、テンプレートへの一括データ流し込み処理が実行される場合、このディクショナリに定義されたルールが適用されます。

データ表示ロジックは、入力フィールド名称の文字列パターンマッチのよる分類化の他に入力フィールド名称が"データフィールド名称/アトリビュート属性文字列"形式で与えられたときのアトリビュート属性文字列による例外ルールの設定が可能になっています。

テンプレート:
<form action="i.php">
{_CONTROL}
<input type="text" name="USER_NAME" value="{USER_NAME}">
<input type="radio" naem="COMM_METHOD" value="TEL" {$checked} > 電話
<input type="radio" naem="COMM_METHOD" value="MAIL" {$checked} > メール
<input type="submit" name="_ACTION[next]" value="確認">
</form>
データディクショナリ:
function default_constructor(&$win, &$rec, $field_name, $attr1, $attr2) {
  if (!is_array($rec)) $rec = array();

  if (strstr($field_name, 'ERRSTR')) return;

  $data = htmlspecialchars(trim($rec[$field_name]));

  if ($attr1 == 'radio_checked') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'checked';
    }
  } else if ($attr1 == 'checkbox_checked') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'checked';
    }
  } else if ($attr1 == 'option_selected') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'selected';
    }
  } else if ($attr1 == 'select' || $attr1 == 'select_search') {
    if ($attr1 == 'select') {
      $srch_fg = false;
    } else {
      $srch_fg = true;
    }

    if (strstr($field_name, 'PREFECTURE')) {
      $data = util::make_options($dict_prefecture, $rec[$field_name], $srch_fg);
    }
    if (strstr($field_name, 'PER_PAGE')) {
      $data = util::make_options($dict_per_page, $rec[$field_name], $srch_fg);
    }
  } else if ($attr1 == 'dict') {
    if (strstr($field_name, 'SUPPLYER_ID')) {
      $data = pm9db_core::select_item("select SUPPLYER_NAME
              from tbl_SUPPLYER where SUPPLYER_ID = '{$rec[$field_name]}'");
    }
    if (strstr($field_name, 'USER_ID')) {
      $data = pm9db_core::select_item("select USER_NAME
              from tbl_USER where USER_ID = '{$rec[$field_name]}'");
    }
  } else if ($attr1 == 'hidden') {
    $data = str_repeat('*', strlen($rec[$field_name]));
  } else if ($attr1 == 'nl2br') {
    $data = nl2br($rec[$field_name]);
  } else if ($attr1 == 'raw') {
    $data = $rec[$field_name];
  } else if (!$attr1) {
    if (strstr(strstr($field_name, '_PRICE') || strstr($field_name, '_COUNT')) {
      if (is_numeric($rec[$field_name])) {
        $data = number_format(util::str2number($rec[$field_name]));
      } else if ($rec[$field_name]) {
        $data = $rec[$field_name];
      }
    } else if (strstr($field_name, '_DATETIME')) {
      if ($rec[$field_name] && $rec[$field_name] != '0') {
        $data = util::str2datetime($rec[$field_name]);
      } else {
        $data = "";
      }
    } else if (strstr($field_name, '_DATE')) {
      if ($rec[$field_name] && $rec[$field_name] != '0') {
        $data = util::str2date($rec[$field_name]);
      } else {
        $data = "";
      }
    }
  }
  return $data;
}
データ流し込み:
$win->set_values('default_constructor', $rec);
アトリビュート属性の使用例:
<select name="PREFECTURE">
{PREFECTURE/select_search}
</select>

下記のようなルールを設定できます。

エラー表示ロジックディクショナリ

プレゼンテーションロジックにより、テンプレートへのエラーメッセージ一括設定処理が実行される場合、このディクショナリに定義されたルールが適用されます。

エラー表示ロジックディクショナリの例:
function set_tpl_error(&$win, $field_list) {
  if (!$field_list) return;
  foreach($field_list as $field => $type) {
    $win->assign("ERR_$field", 'error');
    switch ($type) {
      case 'req':
        $win->assign("ERRSTR_$field", '(必須)');
        break;
      case 'kana':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      case 'kanji':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      case 'mail':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      case 'tel':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      default:
        $win->assign("ERRSTR_$field", '(不正)');
        break;
    }
  }
}

データ入力チェックロジックディクショナリ

コントロールロジックにより、データ入力チェック処理を実行した場合、このディクショナリに定義されたルールが適用されます。

下記のようなルールを設定できます。

データ入力チェックロジックディクショナリの例:
class validate {
  function check_equal($rec, $field, &$err) {
    $tmp_field = str_replace('2', '', $field);
    if ($rec[$field] != $rec[$tmp_field]) {
      $err[$field] = 'equal';
    }
  }
  function check_kana($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!mbereg("^[ーァ-ヶ]*$", $rec[$field])) $err[$field] = 'kana';
  }
  function check_tel($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!eregi('^[0-9]*$', $rec[$field])) $err[$field] = 'tel';
  }
  function check_mail($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!eregi("^[0-9,A-Z,a-z][0-9,a-z,A-Z,_,\.,-]+
@[0-9,A-Z,a-z][0-9,a-z,A-Z,_,\.,-]+\.[0-9,A-Z,a-z]{2,3}$", $rec[$field]))
       $err[$field] = 'mail';
  }
  function check_passwd($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!eregi("^[0-9a-z]{8,12}$", $rec[$field])) $err[$field] = 'passwd';
  }
}

function default_validator(&$rec, $field_name, $f_attr1, $f_attr2, &$__err_list) {
  if (!is_array($rec)) return;
  if (!$__err_list) $__err_list = array();

  $rec[$field_name] = trim($rec[$field_name]);

  if ($f_attr1 == 'option' && !$rec[$field_name]) {
    return;
  }

  if ($f_attr1 == 'equal') {
    validate::check_equal($rec, $field_name, &$__err_list);
    return;
  }

  if (strstr($field_name, 'KANA')) {
    validate::check_kana($rec, $field_name, &$__err_list);
  }
  if (strstr($field_name, 'TEL')) {
    validate::check_tel($rec, $field_name, &$__err_list);
  }
  if (strstr($field_name, 'MAIL')) {
    validate::check_mail($rec, $field_name, &$__err_list);
  }
  if (strstr($field_name, 'PASS')) {
    validate::check_passwd($rec, $field_name, &$__err_list);
  }
}

入力データ正規化ロジックディクショナリ

コントロールロジックにより、入力データ正規化処理を実行した場合、このディクショナリに定義されたルールが適用されます。

下記のようなルールを設定できます。

入力データ正規化ロジックディクショナリの例:
function default_converter(&$rec) {
  foreach ($rec as $name => $val) {
    if (is_array($val)) {
      default_converter($rec[$name]);
      continue;
    }
    if (strstr($name, '_PRICE')  || strstr($name, '_COUNT')) {
      $rec[$name] = to_integer($rec[$name]);
    }
  }
}

DBインターフェース

select, insert, update処理に関する抽象化されたサービスを提供します。 例えば、レコード内のフィールドを意識することなく、ポートレット変数の内容で一括してレコードを挿入、更新を行なう等の処理ができます。

DBデータの画面への表示についてもselectインターフェースにより取得した値setを一括して画面テンプレートに流し込みが行なえます。

ユーティリティ

テンプレートベースメール送信ユーティリティ

画面テンプレートと同様の値setの一括設定とメール送信が簡単な記述で行なえます。

InfoPathデータインポートユーティリティ

マルチメディアデータを含む複雑な形式の大量のデータをInfoPathを介して登録できるようにするソリューションを提供いたします。

テンプレートベースXML、PDF、テキスト生成ユーティリティ

画面テンプレートと同様の値setの一括設定を利用したXML、PDF、テキストの生成を簡単な記述で行なえます。

デバッグ、トレース

(特色)
本Frameworkには、次の様な特徴があります。

速構Web Framework 開発マニュアル

目次

ディレクトリ構成

/システムルートディレクトリ/ … Web公開している任意のディレクトリ
  /_app/          … ポートレットロジック格納ディレクトリ
    /(portlet 1)/     … ポートレット1
      /(status 1).php  … ステータス1プレゼンテーションロジック
      /(status 1)_.php … ステータス1コントロールロジック
      /(status 2).php
      /(status 2)_.php
        :
      /(status n).php
      /(status n)_.php
        :
    /(portlet n)/     … ポートレットn
      /(status 1).php
      /(status 1)_.php
      /(status 2).php
      /(status 2)_.php
        :
      /(status n).php
      /(status n)_.php

  /_design/         … テンプレート格納ディレクトリ
        ----------------------------------------------------------------
        * 各プレゼンテーションロジックが必要とするHTMLテンプレートを格納
         以下のディレクトリ構成は任意
        ----------------------------------------------------------------

    /_design/cache/      … テンプレートキャッシュ格納ディレクトリ
        ----------------------------------------------------------------
        * テンプレートファイルは、自動的にコンパイルされて、
         コンパイルドオブジェクトとしてchacheディレクトリに格納される。
        * _designディレクトリ以下にサブディレクトリが存在する場合は、
         サブディレクトリ毎に cache ディレクトリを作成する必要がある。
        ----------------------------------------------------------------

  /_config/         … 各ディクショナリ、設定ファイル、ユーザ定義関数
      /license.php
      /define.php
      /default_constructor.php
      /error_constructor.php
      /default_converter.php
      /default_error_presenter.php
      /default_validator.php

  /_include/        … フレームワークエンジン

  /i.php          … メイン・プログラム

  /coverage.php       … カバレッジテスト用テスト項目抽出ユーティリティ

/(PHP拡張ライブラリ格納ディレクトリ)/pm9framework.so … フレームワークエンジン

ライセンスキーの設定

_config/license.phpにライセンスキーを設定します。 商用ライセンスキーでの御利用の場合は、株式会社PM9から発行されるライセンスキーを設定して下さい。
それ以外の場合、パッケージ出荷時のライセンスキーのままで御利用下さい。

パッケージ出荷時のライセンスキー
define('LICENSE', 'NON_BUSINESS::....................');
商用利用の場合のライセンスキー
define('LICENSE', '(株式会社PM9から発行されるライセンスキー)');

設定ファイルのカスタマイズ

(_config/define.php)

各種ディレクトリの定義
define('CONFIG_DIR', '/var/www/html/e-shop/config/');
define('HOME_DIR', '/var/www/html/e-shop/');
define('TEMPLATE_DIR', '/var/www/html/e-shop/design/');
define('TEMPLATE_MAIL_DIR', '/var/www/html/e-shop/template_mail/');
define('TEMPLATE_PDF_DIR', '/var/www/html/e-shop/template_pdf/');
define('TEMPLATE_TEXT_DIR', '/var/www/html/e-shop/template_text/');
define('APP_DIR', '_app/');

define('LOG_DIR', '/var/www/html/e-shop/log/');
define('TRACE_FILE', "/var/www/html/e-shop/log/{$_SERVER['REMOTE_ADDR']}");

define('HOME_URL', 'http://www.e-shop.com/');
メール送信ユーティリティ定義
define('MAIL_RETURN_PATH', 'admin@e-shop.com');
DB定義
// GLOBAL-DB定義
define('DB_HOST_GLOBAL', 'localhost');
define('DB_NAME_GLOBAL', 'e-shop-global');

// LOCAL-DB定義
define('DB_HOST', 'localhost');
define('DB_NAME', 'e-shop');

// DBユーザ定義
define('DB_USER', 'e-shop');
define('DB_PASS', 'pass');

// クエリー処理DB(GLOBAL-DB/LOCAL-DB)判定
// pm9db_coreクラスからのコールバック関数
function db_check_global($sql) {
    // クエリー文字列に含まれたテーブル名称により判定
    if (strstr($sql, 'tbl_global_')) {
        // GLOBAL-DBのテーブルを使用する場合
        return 1;
    else
        // それ以外
        return 0;
}
エラー発生時のスナップショットダンプ動作定義
define (FATAL,E_USER_ERROR);
define (ERROR,E_USER_WARNING);
define (WARNING,E_USER_NOTICE);

error_reporting (E_ALL ^ E_NOTICE);

set_error_handler("my_error_handler");

function my_error_handler($errno, $errstr, $errfile, $errline) {
       :
}

ディクショナリのカスタマイズ

データ表示ロジックディクショナリ

データ表示ロジックディクショナリの例 -- default_constructor.php:
function default_constructor(&$win, &$rec, $field_name, $attr1, $attr2) {
  if (!is_array($rec)) $rec = array();

  if (strstr($field_name, 'ERRSTR')) return;

  $data = htmlspecialchars(trim($rec[$field_name]));

  if ($attr1 == 'radio_checked') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'checked';
    }
  } else if ($attr1 == 'checkbox_checked') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'checked';
    }
  } else if ($attr1 == 'option_selected') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'selected';
    }
  } else if ($attr1 == 'select' || $attr1 == 'select_search') {
    if ($attr1 == 'select') {
      $srch_fg = false;
    } else {
      $srch_fg = true;
    }

    if (strstr($field_name, 'PREFECTURE')) {
      $data = util::make_options($dict_prefecture, $rec[$field_name], $srch_fg);
    }
    if (strstr($field_name, 'PER_PAGE')) {
      $data = util::make_options($dict_per_page, $rec[$field_name], $srch_fg);
    }
  } else if ($attr1 == 'dict') {
    if (strstr($field_name, 'SUPPLYER_ID')) {
      $data = pm9db_core::select_item("select SUPPLYER_NAME
              from tbl_SUPPLYER where SUPPLYER_ID = '{$rec[$field_name]}'");
    }
    if (strstr($field_name, 'USER_ID')) {
      $data = pm9db_core::select_item("select USER_NAME
              from tbl_USER where USER_ID = '{$rec[$field_name]}'");
    }
  } else if ($attr1 == 'hidden') {
    $data = str_repeat('*', strlen($rec[$field_name]));
  } else if ($attr1 == 'nl2br') {
    $data = nl2br($rec[$field_name]);
  } else if ($attr1 == 'raw') {
    $data = $rec[$field_name];
  } else if (!$attr1) {
    if (strstr(strstr($field_name, '_PRICE') || strstr($field_name, '_COUNT')) {
      if (is_numeric($rec[$field_name])) {
        $data = number_format(util::str2number($rec[$field_name]));
      } else if ($rec[$field_name]) {
        $data = $rec[$field_name];
      }
    } else if (strstr($field_name, '_DATETIME')) {
      if ($rec[$field_name] && $rec[$field_name] != '0') {
        $data = util::str2datetime($rec[$field_name]);
      } else {
        $data = "";
      }
    } else if (strstr($field_name, '_DATE')) {
      if ($rec[$field_name] && $rec[$field_name] != '0') {
        $data = util::str2date($rec[$field_name]);
      } else {
        $data = "";
      }
    }
  }
  return $data;
}

エラー発生時のデータ表示ロジックディクショナリの例 -- error_constructor.php:
function error_constructor(&$win, &$rec, $field_name, $attr1, $attr2) {
  if (!is_array($rec)) $rec = array();

  if (strstr($field_name, 'ERRSTR')) return;

  $data = htmlspecialchars(trim($rec[$field_name]));

  if ($attr1 == 'radio_checked') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'checked';
    }
  } else if ($attr1 == 'checkbox_checked') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'checked';
    }
  } else if ($attr1 == 'option_selected') {
    if ($attr2 == $rec[$field_name]) {
      $data = 'selected';
    }
  } else if ($attr1 == 'select' || $attr1 == 'select_search') {
    if ($attr1 == 'select') {
      $srch_fg = false;
    } else {
      $srch_fg = true;
    }

    if (strstr($field_name, 'PREFECTURE')) {
      $data = util::make_options($dict_prefecture, $rec[$field_name], $srch_fg);
    }
    if (strstr($field_name, 'PER_PAGE')) {
      $data = util::make_options($dict_per_page, $rec[$field_name], $srch_fg);
    }
  } else if ($attr1 == 'dict') {
    if (strstr($field_name, 'SUPPLYER_ID')) {
      $data = pm9db_core::select_item("select SUPPLYER_NAME
              from tbl_SUPPLYER where SUPPLYER_ID = '{$rec[$field_name]}'");
    }
    if (strstr($field_name, 'USER_ID')) {
      $data = pm9db_core::select_item("select USER_NAME
              from tbl_USER where USER_ID = '{$rec[$field_name]}'");
    }
  } else if ($attr1 == 'hidden') {
    $data = str_repeat('*', strlen($rec[$field_name]));
  } else if ($attr1 == 'nl2br') {
    $data = nl2br($rec[$field_name]);
  } else if ($attr1 == 'raw') {
    $data = $rec[$field_name];
  } else if (!$attr1) {
  }
  return $data;
}

エラー表示ロジックディクショナリ

エラー表示ロジックディクショナリの例 -- default_error_presenter.php:
function set_tpl_error(&$win, $field_list) {
  if (!$field_list) return;
  foreach($field_list as $field => $type) {
    $win->assign("ERR_$field", 'error');
    switch ($type) {
      case 'req':
        $win->assign("ERRSTR_$field", '(必須)');
        break;
      case 'kana':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      case 'kanji':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      case 'mail':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      case 'tel':
        $win->assign("ERRSTR_$field", '(不正)');
        break;
      default:
        $win->assign("ERRSTR_$field", '(不正)');
        break;
    }
  }
}

データ入力チェックロジックディクショナリ

データ入力チェックロジックディクショナリの例 -- default_validator.php:
class validate {
  function check_equal($rec, $field, &$err) {
    $tmp_field = str_replace('2', '', $field);
    if ($rec[$field] != $rec[$tmp_field]) {
      $err[$field] = 'equal';
    }
  }
  function check_kana($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!mbereg("^[ーァ-ヶ]*$", $rec[$field])) $err[$field] = 'kana';
  }
  function check_tel($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!eregi('^[0-9]*$', $rec[$field])) $err[$field] = 'tel';
  }
  function check_mail($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!eregi("^[0-9,A-Z,a-z][0-9,a-z,A-Z,_,\.,-]+
@[0-9,A-Z,a-z][0-9,a-z,A-Z,_,\.,-]+\.[0-9,A-Z,a-z]{2,3}$", $rec[$field]))
       $err[$field] = 'mail';
  }
  function check_passwd($rec, $field, &$err) {
    if (!trim($rec[$field])) return;
    if (!eregi("^[0-9a-z]{8,12}$", $rec[$field])) $err[$field] = 'passwd';
  }
}

function default_validator(&$rec, $field_name, $f_attr1, $f_attr2, &$__err_list) {
  if (!is_array($rec)) return;
  if (!$__err_list) $__err_list = array();

  $rec[$field_name] = trim($rec[$field_name]);

  if ($f_attr1 == 'option' && !$rec[$field_name]) {
    return;
  }

  if ($f_attr1 == 'equal') {
    validate::check_equal($rec, $field_name, &$__err_list);
    return;
  }

  if (strstr($field_name, 'KANA')) {
    validate::check_kana($rec, $field_name, &$__err_list);
  }
  if (strstr($field_name, 'TEL')) {
    validate::check_tel($rec, $field_name, &$__err_list);
  }
  if (strstr($field_name, 'MAIL')) {
    validate::check_mail($rec, $field_name, &$__err_list);
  }
  if (strstr($field_name, 'PASS')) {
    validate::check_passwd($rec, $field_name, &$__err_list);
  }
}

入力データ正規化ロジックディクショナリ

入力データ正規化ロジックディクショナリの例 -- default_converter.php:
function default_converter(&$rec) {
  foreach ($rec as $name => $val) {
    if (is_array($val)) {
      default_converter($rec[$name]);
      continue;
    }
    if (strstr($name, '_PRICE')  || strstr($name, '_COUNT')) {
      $rec[$name] = to_integer($rec[$name]);
    }
  }
}

HTMLデザイン

レイアウトテンプレート・文法

ポートレットのアサイン

レイアウト内にポートレット用の枠を定義し、ポートレットの実行結果を枠の中に流し込みます。

記法:
{&ポートレット名}
例:
<html>
<body>
<table>
  <tr>
    <td>{&menu}</td><td>{&shopcart}</td>
  </tr>
</table>
</body>
</html>
HTMLファイルの埋め込み

記法:
<!-- INCLUDE : HTMLファイル名 -->
例:
<!-- INCLUDE : html_header.html -->
<table>
  <tr>
    <td>{&menu}</td><td>{&shopcart}</td>
  </tr>
</table>
<!-- INCLUDE : html_footer.html -->

テンプレート・文法

ブロック

画面プロセスオブジェクトのブロック生成関数により、ブロックの生成を行なう場所を定義します。

記法:
<!-- START BLOCK : ブロック名 -->

<!-- END BLOCK : ブロック名 -->
例:
<table>
<th>
<td>ID</td><td>名称</td>
</th>
<!-- START BLOCK : LIST_BL -->
<tr>
<td>{ITEM_ID}</td><td>{ITEM_NAME}</td>
</tr>
<!-- END BLOCK : LIST_BL -->
</table>
$rs = pm9db_core::query('select * from tbl_ITEM order by ITEM_ID');
while($rec = pm9db_core::fetch_array($rs)) {
  $win->new_block('LIST_BL');
  $win->set_values('default_constructor', $rec, 'LIST_BL');
}
データ流し込み

画面プロセスオブジェクトのデータ流し込み関数やデータ一括流し込み関数により、データを流し込む場所を示します。 HTMLの任意の場所に記述可能です。

記法:
{変数名}
例:
{ITEM_ID}
データ流し込み -- アトリビュート適用

記法:
{変数名/アトリビュート1}
例:
{ITEM_ID/dict}
データ流し込み -- アトリビュート2適用

記法:
{変数名/アトリビュート1::アトリビュート2}
例:
<input type="radio" naem="COMM_METHOD" value="TEL"
     {COMM_METHOD/radio_selected::TEL}> 電話
<input type="radio" naem="COMM_METHOD" value="MAIL"
     {COMM_METHOD/radio_selected::MAIL}> メール
前方名称参照、置換

$0が記述された箇所より前にある{}に囲まれた文字列を探し出し、その文字列と置き換えます。
$0は、{}内であれば、どこにでも記述が可能です。

記法:
{.. $0 ..}
例:
<td class="view"><input name="USER_MAIL" class="{ERR_USER_MAIL}"
       value="{USER_MAIL}" {?USER_MAIL}>{ERRSTR_$0}</td>
タグ内名称参照、置換

同一タグ内にある{}に囲まれた文字列を探し出し、その文字列と置き換えます。
$1は、{}内であれば、どこにでも記述が可能です。

記法:
{.. $1 ..}
例:
<td class="view">
  <input name="{#$1}" class="{ERR_$1}" value="{USER_MAIL}" {?$1}>{ERRSTR_$0}
</td>
後方名称参照、置換

$2が記述された箇所より後にある{}に囲まれた文字列を探し出し、その文字列と置き換えます。
$2は、{}内であれば、どこにでも記述が可能です。

記法:
{.. $2 ..}
例:
<td class="view">
  {ERRSTR_$2}<input name="{#$1}" class="{ERR_$1}" value="{USER_MAIL}" {?$1}>
</td>
{}内文字列のリテラル文字列化

記法:
{#文字列}
例:
<input type="text" name="{#$1}" value="{USER_NAME}">

{#$1}は文字列「USER_NAME」に変換されます。

<input type="text" name="USER_NAME" value="{USER_NAME}">
配列要素名を付加した{}内文字列のリテラル化

画面プロセスオブジェクトのデータ一括流し込み--配列要素名付加関数により、配列要素名が付加されます。

記法:
{#@フィールド名}
例:
<!-- START BLOCK : LIST_BL -->
<tr>
  <td><input type="text" name="{#@$1}" value="{item_data1}"></td>
  <td><input type="text" name="{#@$1}" value="{item_data2}"></td>
</tr>
<!-- END BLOCK : LIST_BL -->
while($rec = db::fetch_array($rs)) {
  $item_id = $rec['item_id'];
  $win->new_block('LIST_BL');
  $win->set_values('default_constructor', $rec, 'LIST_BL', "rec[$item_id]");
}

2つのレコードの内容がそれぞれ次のような場合、次のようなHTMLが生成されます。

1レコード目:
     $rec['item_id'] => 'rec1'、$rec['item_data1'] => 'abc'、$rec['item_data2'] => 'def'
2レコード目:
     $rec['item_id'] => 'rec2'、$rec['item_data1'] => 'ghi'、$rec['item_data2'] => 'jkl'
<tr>
  <td><input type="text" name="rec[rec1][item_data1]" value="abc"></td>
  <td><input type="text" name="rec[rec1][item_data2]" value="def"></td>
</tr>
<tr>
  <td><input type="text" name="rec[rec2][item_data1]" value="ghi"></td>
  <td><input type="text" name="rec[rec2][item_data2]" value="jkl"></td>
</tr>
入力チェック

画面プロセスオブジェクトのデータ入力チェック関数が実行されると、入力チェックマークのあるデータが、データ入力チェックロジックディクショナリのルールに従ってチェックされます。

記法:
{?入力フィールド名}
例:
{?USER_MAIL}
入力チェック -- アトリビュート属性あり

記法:
{?入力フィールド名/アトリビュート1}
例:
{?USER_MAIL/exist}

アトリビュート属性 existに対する処理は、データ入力チェックロジックディクショナリに記述します。

入力チェック -- アトリビュート属性あり2

記法:
{?入力フィールド名/アトリビュート1::アトリビュート2}
例:
{?USER_PASS/equal::USER_PASS_CONF}

アトリビュート属性 equal、USER_PASS_CONFに対する処理は、データ入力チェックロジックディクショナリに記述します。

セレクトボックス選択状態自動指定

セレクトボックスのchecked属性を自動設定します。 セレクトボックスタグ内に{$selected}を記述した場合{変数名/opt_selected::値}と同様に扱われます。 データ表示ロジックディクショナリ内にアトリビュート「opt_selected」に対する処理ロジックを実装して使用します。

記法:
<option value="値" {$selected}>
例:
<select name="ITEM_ID">
  <option value="111" {$selected}>A380</option>
  <option value="222" {$selected}>B747-400</option>
  <option value="333" {$selected}>B777</option>
</select>

下記と同義です。

<select name="ITEM_ID">
  <option value="111" {ITEM_ID/opt_selected::111}>A380</option>
  <option value="222" {ITEM_ID/opt_selected::222}>B747-400</option>
  <option value="333" {ITEM_ID/opt_selected::333}>B777</option>
</select>
ラジオボックスchecked属性自動設定

ラジオボックスのchecked属性を自動設定します。 ラジオボックスタグ内に{$checked}を記述した場合{変数名/radio_selected::値}と同様に扱われます。 データ表示ロジックディクショナリ内にアトリビュート「radio_selected」に対する処理ロジックを実装して使用します。

記法:
<input type="radio" name="名前" value="値" {$checked}>
例:
<input type="radio" name="AGE" value="10" {$checked}> 10代
<input type="radio" name="AGE" value="20" {$checked}> 20代
<input type="radio" name="AGE" value="30" {$checked}> 30代以上

下記と同義です。

<input type="radio" name="AGE" value="10" {AGE/radio_selected::10}> 10代
<input type="radio" name="AGE" value="20" {AGE/radio_selected::20}> 20代
<input type="radio" name="AGE" value="30" {AGE/radio_selected::30}> 30代以上
チェックボックスchecked属性自動設定

チェックボックスのchecked属性を自動設定します。 チェックボックスタグ内に{$checked}を記述した場合{変数名/checkbox_selected::値}と同様に扱われます。 データ表示ロジックディクショナリ内にアトリビュート「checkbox_selected」に対する処理ロジックを実装して使用します。

記法:
<input type="checkbox" name="名前" value="値" {$checked}>
例:
<input type="checkbox" name="CATALOGUE" value="1" {$checked}> カタログを送付

下記と同義です。

<input type="checkbox" name="CATALOGUE" value="1"
       {CATALOGUE/checkbox_selected::1}> カタログを送付
Formコントローラパラメータ埋め込み

記法:
{_CONTROL}
例:
<form action="i.php">
{_CONTROL}
<input type="submit" name="_ACTION[next]" value="確認">
</form>
URL文字列用コントローラパラメータ埋め込み

記法:
{_CONTROL_URL}
例:
<a href="i.php?{_CONTROL_URL}&_ACTION[next]=1">確認</a>
アクション -- Submit指定

記法:
<input type="submit" name="_ACTION[アクション名]" value="値">
例:
<form action="i.php">
{_CONTROL}
<input type="submit" name="_ACTION[prev]" value="修正">
<input type="submit" name="_ACTION[next]" value="確認">
</form>
アクション -- Hidden指定

JavaScript等を使用してFormをサブミットする場合に使用します。

記法:
_ACTION_.value='アクション名'
例:
<form action="i.php" name="form1">
{_CONTROL}
<input type="button" name="BTN_1" value="確認"
   onclick="form1._ACTION_.value='next';form1.submit();">
</form>
アクション -- Submit時オプションパラメータ付加

アクション以外にパラメータを追加して渡すことができます。

記法:
<input type="submit" name="_ACTION[アクション名::パラメータ名::パラメータ値]" value="値">
例:
<form action="i.php" name="form1">
{_CONTROL}
<input type="submit" name="_ACTION[edit::ITEM_ID::111]" value="商品111:編集">
<input type="submit" name="_ACTION[edit::ITEM_ID::222]" value="商品222:編集">
</form>
アクション -- Hidden指定オプションパラメータ付加

JavaScript等を使用してFormをサブミットする場合に使用します。 アクション以外にパラメータを追加して渡すことができます。

記法:
_ACTION_.value='アクション名::パラメータ名::パラメータ値'
例:
<form action="i.php" name="form1">
{_CONTROL}
<a href="i.php"
  onclick="form1._ACTION_.value='edit::ITEM_ID::111';form1.submit();">
    編集</a>
<a href="i.php"
  onclick="form1._ACTION_.value='edit::ITEM_ID::222';form1.submit();">
    編集</a>
アクション -- URLパラメータ

記法:
<a href="i.php?{_CONTROL_URL}&_ACTION[アクション名]=1>
例:
<a href="i.php?{_CONTROL_URL}&_ACTION[check]=1&ITEM_ID=111">在庫確認</a>
History Back -- Submit/カウント指定

過去の画面遷移の履歴の中で指定されたカウント数分画面を戻します。

記法:
<input type="submit" name="_ACTION_HISTORY_BACK[ヒストリー戻りカウント]" value="値">
例:
<form action="i.php" name="form1">
{_CONTROL}
<input type="submit" name="_ACTION[next]" value="確認">
<input type="submit" name="_ACTION_HISTORY_BACK[1]" value="戻る">
</form>
History Back -- Submit/ラベル指定

過去の画面遷移の履歴の中でヒストリーマークが設定されているページに画面を戻します。

記法:
<input type="submit" name="_ACTION_HISTORY_BACK[ヒストリーラベル]" value="値">
例:
<form action="i.php" name="form1">
{_CONTROL}
<input type="submit" name="_ACTION[next]" value="確認">
<input type="submit" name="_ACTION_HISTORY_BACK[item_list]" value="商品一覧へ戻る">
</form>
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'item_list.html');
$win->set_values('default_constructor', $_);
$win->set_history_mark('item_list');
$win->finish();
ポートレット画面キャッシュ破棄

一度生成されたポートレットの画面はデータは、キャッシュ有効期間の間、各ユーザのセッションデータ内にキャッシュされます。キャッシュを強制的に破棄する場合に当パラメータを使用します。

記法:
_REFRESH.value=1
例:
<form action="i.php" name="form1">
{_CONTROL}

表示件数:<select name="_PGCTL_PER_PAGE" size="1" 
  onchange="form1._REFRESH.value=1;form1.submit()">
    {_PGCTL_PER_PAGE/select}</select>件
全セッションデータ破棄

ユーザの現在の全セッションデータを破棄します。

記法:
_CLEAR_SESSION.value=1
例:
<a href='i.php?{_CONTROL_URL}&_CLEAR_SESSION.value=1'>LOGOUT;/a>
セッションデータReadOnly状態設定

記法:
_SESSION_READ_ONLY.value=1
例:
<form action="i.php" name="form1">
{_CONTROL}

<input type="button" name="popup" value="別ウィンドウで表示"
      onClick="form1._SESSION_READ_ONLY.value=1; form1.target='new_win'">
セッションデータReadOnly状態設定 -- URLパラメータ

記法:
{_CONTROL_URL_SESSION_READ_ONLY}
例:
<a href="i.php?{_CONTROL_URL_SESSION_READ_ONLY}&_ACTION[view]&ITEM_ID=123"
      target="new_win">
商品表示:123</a>
コメントアウト

記法:
{{ ... }}
例:
<input type="text" name="{#$1}" value="ITEM_NAME" {{ size="12" }} {SIZESTR_$1} >

プログラミング

関数 -- 画面コントロール関連

コンストラクタ

画面プロセスオブジェクトの生成を行ないます。

記法:
画面プロセスオブジェクト変数 = new pm9mvc()
例:
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'cart.html');
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
$win->set_values('default_constructor', $rec);
$win->finish();
テンプレート準備

画面プロセスオブジェクトにテンプレートファイルを割り当てます。

記法1:
画面プロセスオブジェクト変数->init(テンプレートファイル名, キャッシュ有効期限)
例1:
$win->init(TEMPLATE_DIR . 'ITEM_LIST.html', time() + 60);

一度生成されたポートレットの画面データは、キャッシュ有効期間の間、各ユーザのセッションデータ内にキャッシュされます。

記法2:
画面プロセスオブジェクト変数->init(テンプレートファイル名)
例2:
$win->init(TEMPLATE_DIR . 'ITEM_LIST.html');
ブロック生成

<!-- START BLOCK : ブロック名 --> <!-- END BLOCK : ブロック名 --> で定義されたブロックを生成・追加します。

記法:
画面プロセスオブジェクト変数->new_block(ブロック名)
例:
$rs = pm9db_core::query(
      "select * from tbl_ITEM limit $rec_start, {$_['_PGCTL_PER_PAGE']}");
while($rec = pm9db_core::fetch_array($rs)) {
  $win->new_block('LIST_BL');
  $win->set_values('default_constructor', $rec, 'LIST_BL');
}
ブロック有無確認

テンプレート内に指定したブロックが存在するかどうかを確認します。

記法:
画面プロセスオブジェクト変数->is_exist_block(ブロック名)
例:
if ($win->is_exist_block('LIST_BL')) {
  $rs = pm9db_core::query(
        "select * from tbl_ITEM limit $rec_start, {$_['_PGCTL_PER_PAGE']}");
  while($rec = pm9db_core::fetch_array($rs)) {
    $win->new_block('LIST_BL');
    $win->set_values('default_constructor', $rec, 'LIST_BL');
  }
}
処理対象ブロック変更

処理対象のブロックを変更します。 テンプレート上、 <!-- START BLOCK : ブロック名 --> <!-- END BLOCK : ブロック名 --> に囲まれない領域にアクセスする場合は、ブロック名として「PM9MVC_TOP_BLOCK」を指定します。

記法:
画面プロセスオブジェクト変数->goto_block(ブロック名)
例:
$rs = pm9db_core::query("select * from tbl_ITEM limit $rec_start, {$_['_PGCTL_PER_PAGE']}");
while($rec = pm9db_core::fetch_array($rs)) {
  $win->new_block('LIST_BL');
  $win->set_values('default_constructor', $rec, 'LIST_BL');
}
$win->goto_block(PM9MVC_TOP_BLOCK);
$win->set_values('default_constructor', $rec);
データ流し込み

テンプレート上のデータ流し込み用変数にデータを流し込みます。 データ表示ロジックディクショナリの参照は行ないません。

記法:
画面プロセスオブジェクト変数->assign(データ流し込み用変数名, 流し込みデータ)
例:
$win->assign('ITEM_ID', $_['ITEM_ID']);
データ一括流し込み

連想配列に格納されたデータをテンプレートに一括して流し込みます。 流し込み時にデータ表示ロジックディクショナリを参照しながら処理を行ないます。

記法:
画面プロセスオブジェクト変数->set_values(データ表示ロジックディクショナリ関数名,
       流し込みデータ連想配列)
例:
$win->set_values('default_constructor', $_);
データ一括流し込み -- 配列要素名付加

連想配列に格納されたデータをテンプレートに一括して流し込みます。 流し込み時にデータ表示ロジックディクショナリを参照しながら処理を行ないます。 流し込み先変数に「@」が付いている場合に、「@」を配列要素名文字列で置き換えます。

記法:
画面プロセスオブジェクト変数->set_values(データ表示ロジックディクショナリ関数名, 
  流し込みデータ連想配列, ブロック名, 配列要素名文字列)
例:
$win->set_values('default_constructor',
  $_['item'][$i], 'LIST_BL', "a[{$rec['ITEM_ID']}]");
画面組み立て一括処理

画面生成を簡便に処理する為の関数です。

記法:
pm9mvc::construct(テンプレートファイル名, データ表示ロジックディクショナリ関数名,
       流し込みデータ連想配列)
例:
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
pm9mvc::construct(TEMPLATE_DIR . 'ITEM_VIEW.html', 'default_constructor', $rec);

下記と同義です。

$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'item_list.html');
$win->set_values('default_constructor', $rec);
$win->finish();
画面組み立て一括処理拡張

画面生成を簡便に処理する為の関数です。

記法:
画面プロセスオブジェクト変数 = pm9mvc::construct_ex(テンプレートファイル名,
       データ表示ロジックディクショナリ関数名, 流し込みデータ連想配列)
例:
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
$win = pm9mvc::construct_ex(TEMPLATE_DIR . 'ITEM_VIEW.html',
                            'default_constructor', $rec);
$win->finish();

下記と同義です。

$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'item_list.html');
$win->set_values('default_constructor', $rec);
$win->finish();
一覧表示時ページコントロールタブ出力

データを一覧表示する際のページ切替タブを出力します。

記法:
pm9mvc::set_page_control(画面プロセスオブジェクト変数, カレント変数,
       &表示対象レコード番号, &1画面あたりの表示レコード数)
例:
$num_rows = pm9db_core::select_item("select count(*) from tbl_ITEM");
pm9mvc::set_page_control($win, $_, &$rec_start, &$per_page);
$rs = pm9db_core::query("select * from tbl_ITEM limit $rec_start, {$_['_PGCTL_PER_PAGE']}");
while($rec = pm9db_core::fetch_array($rs)) {
  $win->new_block('LIST_BL');
  $win->set_values('default_constructor', $rec, 'LIST_BL');
}
ポートレット変数参照取得

記法:
pm9mvc::get_pvars(ポートレット変数識別子)
例:
$list &= pm9mvc::get_pvars('item_list');
ポートレット変数へのデータコピー

記法:
pm9mvc::copy_pvars(ポートレット変数識別子, コピー対象データ連想配列)
例:
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
pm9mvc::copy_pvars('item_view', $rec);
カレント変数へのデータコピー

記法:
pm9mvc::copy_current_pvars(コピー対象データ連想配列)
例:
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
pm9mvc::copy_current_pvars($rec);
カレント変数の指定ポートレット変数への変更

記法:
$_ =& pm9mvc::current_pvars(ポートレット変数識別子)
例:
$_ =& pm9mvc::current_pvars('item_search');
カレント変数クリア

記法:
pm9mvc::clear_current_pvars()
例:
pm9mvc::clear_current_pvars();
ポートレット変数クリア

記法:
pm9mvc::clear_pvars(ポートレット変数識別子)
例:
pm9mvc::clear_pvars('edit');
出力画面Historyラベル設定

記法:
画面プロセスオブジェクト変数->set_history_mark(Historyラベル)
例:
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'item_list.html');
$win->set_values('default_constructor', $_);
$win->set_history_mark('item_list');
$win->finish();
現在ステータス強制変更

記法:
pm9mvc::set_ap_state(ステータス)
例:
pm9mvc::set_ap_state('edit');
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'edit.html');
$win->set_values('default_constructor', $_);
$win->finish();
HTML生成

記法:
画面プロセスオブジェクト変数->finish()
例:
$win->finish();
画面組み立て結果取得

記法:
pm9mvc::get_contents()
例:
$rec = pm9db_core::select_single("select * from tbl_ITEM where ITEM_ID = '{$_['ITEM_ID']}'");
$win = new pm9mvc();
$win->init(TEMPLATE_DIR . 'item_list.html');
$win->set_values('default_constructor', $rec);
$content = $win->get_contents();
次ステータス変更

記法1:
pm9mvc::exec_portlet(null, ステータス)
例1:
pm9mvc::exec_portlet(null, 'start');
記法2:
pm9mvc::exec_portlet(ポートレット名, ステータス)
例2:
pm9mvc::exec_portlet('item', 'start');
レイアウトテンプレート変更

記法:
pm9mvc::change_frame(レイアウトテンプレートファイル名)
例:
pm9mvc::change_frame(TEMPLATE_DIR . 'index_userreg.html');
ポートレット間インターフェース関数CALL

記法:
pm9mvc::call_portlet_function(ポートレット名, インターフェース名, 引数)
例:
pm9mvc::call_portlet_function('item', 'select_category', $_);

上記の処理により _app/item/_interface.php 内の item__select_category 関数が呼び出されます。 関数名の形式は、つぎのとおり。
ポートレット名__インターフェース名

function item__select_category($var) {
  $_ =& pm9mvc::get_pvars('item_list');

  $_['CATEGORY_ID'] = $var['CATEGORY_ID'];
}
最終ステータス設定

ポートレットの画面遷移として現在のステータスまで達したことを記憶します。

記法:
pm9mvc::set_last_status()
例:
pm9mvc::set_last_status()
最終ステータス問合せ・戻り

ポートレットに最終ステータスが設定されているかどうかを問合せ、もし設定されている場合は最終ステータスの画面まで戻ります。

記法:
pm9mvc::last_status()
例:
if (pm9mvc::check_reload()) {
  if (pm9mvc::last_status()) return;
}

ブラウザの「戻るボタン」により前の画面に戻ったとき、既にデータの更新確定処理を済ませている場合、データ変更画面への画面遷移処理(ステータス変更処理)をスキップする等に使用します。

最終ステータスクリア

ポートレットの最終ステータス情報をクリアします。

記法:
pm9mvc::clear_last_status()
例:
pm9mvc::clear_last_status();
ブラウザリロードチェック

記法:
pm9mvc::check_reload()
例:
if (pm9mvc::check_reload()) {
  if (pm9mvc::last_state()) return;
}

switch ($__action) {
case 'edit_fini':
  pm9db_core::update_record('tbl_ITEM', array('ITEM_ID'), $_);
  break;
}

switch ($__action) {
case 'edit_fini':
  pm9mvc::exec_portlet(null, 'edit_fini');
  break;
}

ブラウザの「戻るボタン」により前の画面に戻ったケースで、既にデータの更新処理を済ませている場合は、データ更新処理および画面遷移(ステータス変更)を行ないません。

データ入力チェック

記法1:
$win->validate(データ入力チェックロジックディクショナリ関数,
                  チェック対象変数, &エラー結果格納配列)
例1:
$win->validate('default_checker', $_['USER_NAME'], $__err_list);
記法2:
$win->validate(データ入力チェックロジックディクショナリ関数, チェック対象変数,
       &エラー結果格納配列, ブロック名)
例2:
$win->validate('default_checker', $_['item_list']['item1']['ITEM_NAME'],
       &$__err_list, 'LIST_BL');

関数 -- DB関連

DB処理開始

記法:
pm9db_core::db_start()
例:
pm9db_core::db_start();
DB処理終了

記法:
pm9db_core::db_end()
例:
pm9db_core::db_end();
クエリー検索条件組み立て

組み立て判定論理式を評価し、TRUEの場合追加検索条件文字列をクエリー文字列格納変数に追加します。

記法:
pm9db_core::add_select_condition(検索条件追加判定論理式, クエリー文字列格納変数,
  追加検索条件文字列)
例:
$sqladd = '';
pm9db_core::add_select_condition($START_ge, $sqladd,
                      "tbl_ITEM.INSERT_DATE >= '$START_ge'");
pm9db_core::add_select_condition($END_ge, $sqladd,
                      "tbl_ITEM.INSERT_DATE <= '$END_ge'");
$rs = pm9db_core::query("select * from tbl_ITEM $sqladd");
クエリー検索条件・検索対象テーブル組み立て

組み立て判定論理式を評価し、TRUEの場合追加検索条件文字列をクエリー文字列格納変数に追加します。 同時に検索対象テーブルのリストを作成します。

記法:
pm9db_core::add_select_cond_tbl(検索条件追加判定論理式, クエリー文字列格納変数,
  検索対象テーブル格納配列, 追加検索条件文字列, 追加対象テーブル配列)
例:
$sqladd = '';
$sqltbl = array();
pm9db_core::add_select_cond_tbl($START_ge, $sqladd,
          $sqltbl, "tbl_ITEM.INSERT_DATE >= '$START_ge'", array('tbl_ITEM'));
pm9db_core::add_select_cond_tbl($END_ge, $sqladd,
          $sqltbl, "tbl_ITEM.INSERT_DATE <= '$END_ge'", array('tbl_ITEM'));
$tbl = join(',', $sqltbl);
$rs = pm9db_core::query("select * from $tbl $sqladd");
クエリー実行

記法:
クエリー実行結果リソース格納用変数 = pm9db_core::query(クエリー文字列);
例:
$rs = pm9db_core::query("select * from tbl_ITEM");

実行結果として、クエリー実行結果リソースを返します。

レコード取得

記法:
レコードデータ格納用連想配列 = pm9db_core::fetch_array(クエリー実行結果リソース)
例:
$rs = pm9db_core::query("select * from tbl_ITEM");
$rec = pm9db_core::fetch_array($rs);
クエリー実行後1レコード取得

記法:
レコードデータ格納用連想配列 = pm9db_core::select_single(クエリー文字列)
例:
$rec = pm9db_core::select_single(
  "select * from INSERT_DATE >= '$START_ge'");
クエリー実行後1レコード目第1カラム取得

記法:
項目データ格納用変数 = pm9db_core::select_item(クエリー文字列)
例:
$rec_count = pm9db_core::select_item(
  "select count(*) from INSERT_DATE >= '$START_ge'");
クエリー実行後レコード一括取得

記法:
全レコードデータ格納用連想配列変数 
      = pm9db_core::select_assoc_array(クエリー文字列, レコード配列格納用連想配列キー(配列)))
例:
$item_list = pm9db_core::select_assoc_array(
  "select * from tbl_ITEM", array(('CATEGORY_ID', 'ITEM_ID'));
クエリー実行後レコード一括取得

記法:
全レコードデータ格納用単純配列変数 = pm9db_core::select_array(クエリー文字列)
例:
pm9db_core::select_array("select * from tbl_ITEM");
レコード挿入

記法1:
pm9db_core::insert_record(テーブル名, レコードデータ格納連想配列,
                     データ設定除外項目格納配列)

// 「データ設定除外項目格納配列」は、省略可
例1:
pm9db_core::insert_record('tbl_ITEM', $rec, array('ITEM_SEQ'));

レコード挿入対象テーブルにautoincrement属性が設定されている場合、 insert_record関数は、新たに生成されたシーケンス番号を返します。

記法2:
シーケンス番号格納変数
     = pm9db_core::insert_record(テーブル名, レコードデータ格納連想配列,
                            データ設定除外項目格納配列)

// 「データ設定除外項目格納配列」は、省略可
例2:
$next_seq = pm9db_core::insert_record('tbl_ITEM', $rec);
レコード挿入・シーケンスインクリメント

記法:
pm9db_core::insert_record_autoinc(テーブル名, プライマリキー項目名の配列、
   シーケンス項目名、レコードデータ格納連想配列, データ設定除外項目格納配列)

// 「データ設定除外項目格納配列」は、省略可
例:
pm9db_core::insert_record_autoinc('tbl_ITEM', array('CATEGORY_ID', 'ITEM_ID'),
                                  'ITEM_SEQ', $rec);
レコード更新

記法:
pm9db_core::update_record(テーブル名,
    プライマリキー項目名の配列,レコードデータ格納連想配列,
    データ更新項目名称の配列,
  データ更新除外項目名称の配列, データ更新チェック除外項目名称の配列)

// 「データ更新項目名称の配列」は省略可 省略時は全項目更新対象
// 「データ更新除外項目名称の配列」は省略可
// 「データ更新チェック除外項目名称の配列」は省略可
例:
pm9db_core::update_record('tbl_ITEM',
         array('CATEGORY_ID', 'ITEM_ID', 'ITEM_SEQ'), $rec);
レコード存在判定後・挿入・更新

記法:
pm9db_core::insert_update_record(テーブル名,
    プライマリキー項目名の配列, レコードデータ格納連想配列,
    レコード挿入時データ設定項目名称の配列, レコード更新時データ設定項目名称の配列,
  データ更新除外項目名称の配列, データ更新チェック除外項目名称の配列)

// 「レコード挿入時データ設定項目名称の配列」は省略可 省略時は全項目更新対象
// 「レコード更新時データ設定項目名称の配列」は省略可 省略時は全項目更新対象
// 「データ更新除外項目名称の配列」は省略可
// 「データ更新チェック除外項目名称の配列」は省略可
例:
pm9db_core::insert_update_record('tbl_ITEM',
               array('CATEGORY_ID', 'ITEM_ID', 'ITEM_SEQ'), $rec);
レコードキー保存

記法:
pm9db_core::save_recordkey(レコードデータ格納連想配列, 保存したいキー項目名称の配列)
例:
pm9db_core::save_recordkey($rec, array('ITEM_ID'));
    ($rec の編集)
pm9db_core::update_record('tbl_ITEM', array('ITEM_ID,save'), $rec);

保存されたレコードキーは、項目名「元のキー名称+",save"」で元の配列変数内に保存されます。

データ文字列クオート付加

記法:
クオート付加後の連想配列 = pm9db_core::escape(元データ格納連想配列)
例:
$_cond = pm9db_core::escape($_);
$rec = pm9db_core::select_single("select * from tbl_ITEM
             where ITEM_NAME like '%{$_cond['ITEM_NAME']}%'");

関数 -- Utility

データ入力一括チェック

記法:
util::validate_root(データ入力チェックロジックディクショナリ関数, &エラー格納配列)
例:
$win_check = util::validate_root('default_validater', &$__err_list);
セレクトボックス選択リスト生成

記法:
util::make_options(連想配列, 前回選択値, 検索用/選択用の別)
例:
$item_list = pm9db_core::select_assoc("select ITEM_ID,ITEM_NAME from tbl_ITEM");
$opts = util::make_options($item_list, $_['ITEM_ID'], false);
$win->assign('ITEM_ID/select', $opts);
テンプレートベースメール送信

記法:
util::tpl_send_mail(メールメッセージ文字列)
例:
$mail = new pm9mvc();
$mail->init_mail(TEMPLATE_MAIL_DIR . 'confirm.tpl');
$mail->set_values('default_constructor', $rec);
util::tpl_send_mail($mail->get_contents());
メールテンプレートの例:
From:           "info@e-shop.com" 
To:             {USER_MAIL}
Subject:        会員登録確認
cc:
Bcc:            staff@e-shop.com


{USER_NAME} 様

■会員登録確認
ご登録された内容に従い会員情報をお知らせ致します。
システムID取得

システムID設定関数により設定されたシステムID値を取得します。

記法:
システムID = pm9mvc::get_system_id()
システムID設定

記法:
pm9mvc::set_system_id(システムID)

特殊変数

ポートレット変数

ポートレット変数は、ポートレットの持つアプリケーションデータを永続的に保持することができる特殊な変数領域です。
ポートレット変数は配列Typeを含めたあらゆる型の変数を辞書式に複数格納可能な連想配列です。
各ポートレット変数には識別子が付いており、状況に応じて使い分けることができます。

$portletvars[ポートレット変数識別子]
カレント変数(ポートレット変数)

この「カレント変数」は$portletvars[実行中のポートレットの名称]と等価です。
状況に応じてカレント変数を他のポートレット変数に割り当て直すことができます。

$_
実行中のポートレット名

$__AP_ID
実行中のポートレットテータス

$__AP_STATE
画面プロセスオブジェクト・メンバー変数

データ表示ロジック表示ロジックディクショナリ内で、画面プロセスオブジェクトの次のメンバー変数を参照することができます。

_CONTROL      -- Formコントロールパラメータ文字列の格納エリア
_CONTROL_URL  -- URL文字列用コントロールパラメータ文字列の格納エリア
リクエストされたアクションパラメータ

Formやリンクに記述する処理分岐判断の為のパラメータです。 Submitもしくはリンククリック時、コントロールロジックは、アクションパラメータを参照してその内容に応じた処理を実行します。

$__action
データ入力チェック結果格納エリア

$__err_list
トレースモード設定フラグ

トレースモードの設定を行なうフラグです。

フラグの値とトレースモードの関係:
p: フォームやリンクからリクエストされたパラメータのダンプ
s: 全セッションデータのダンプ
t: テンプレートファイルのダンプ
a: ポートレット変数のダンプ
h: 生成されたHTMLのダンプ
d: DBクエリーのダンプ
F: フローチャートカバレッジテスト実行
A: アクションカバレッジテスト実行
U: 画面出力処理・未設定項目の抽出
Q: DB更新処理・未設定項目の抽出
例:
$_POST['__trace'] = 'pstadFA';

インストール手順 -- PHP環境対応バージョン

パッケージの展開

DocumentRoot下もしくは、任意のディレクトリを作成して、パッケージを展開して下さい。

cd /var/www/html
mkdir test
cd test
tar xvfz pm9framework.xxx.tgz

pm9framework.soの設定

pm9framework.soをPHP拡張ライブラリ検索Pathの通ったディレクトリの下にコピーして下さい。

cp library/pm9framework.so /usr/lib/php4/.

magic_quotes_gpcをOffに設定

php.iniのディレクティブもしくは.htaccessによりmagic_quotes_gpc をOffに設定して下さい。

php.ini設定例:
magic_quotes_gpc = Off
.htaccess設定例:
php_value magic_quotes_gpc 0

DB設定 -- MySQL

フレームワークの環境設定ファイルに合わせてDBの設定を行なってください。 ポートレットに必要なテーブル類を定義して下さい。 フレームワークエンジンは、DBを使用しません。

環境設定ファイルの例:
define('DB_HOST_GLOBAL', 'localhost');
define('DB_NAME_GLOBAL', 'e-shop-global');

// LOCAL-DB定義
define('DB_HOST', 'localhost');
define('DB_NAME', 'e-shop');

// DBユーザ定義
define('DB_USER', 'e-shop');
define('DB_PASS', 'pass');

Apache再起動

/etc/rc.d/init.d/httpd stop /etc/rc.d/init.d/httpd start

テスト・デバッグの要領

フローチャートカバレッジテストツール

トレースモード設定フラグ(特殊変数)にてフローチャートカバレッジテストの設定を行なった場合、実行プログラムがチェックポイント関数を実行する毎に、フローチャートカバレッジテスト結果ファイルにカバレッジ結果を書き込みます。 フローチャートカバレッジテスト結果ファイルは、設定ファイルの「LOG_DIR」下に"coverage.flow"として作成されます。 テスト実行前およびプログラムの修正時に、カバレッジテスト用テスト項目抽出ユーティリティ(coverage.php)を実行して、フローチャートカバレッジテスト結果ファイルを更新して下さい。 フローチャートカバレッジテスト結果ファイルは、エディタにて編集することができます。

チェックポイント関数の記法:
____(任意のラベル)
チェックポイント関数記述例:
____('start');

switch($action) {
// 該当ポートレットの'検索'ステータスへ推移
case 'search':
  ____('search');
  exec_portlet(null, 'search');
  break;

// レイアウトテンプレートを編句してトップページへ推移
case 'toppage':
  ____('toppage');
  change_frame('index_toppage.html');
  break;
}

____('end');

アクションカバレッジテストツール

トレースモード設定フラグ(特殊変数)にてアクションカバレッジテストの設定を行なった場合、画面からの入力にて各アクションが実行される毎に、アクションカバレッジテスト結果ファイルにカバレッジ結果を書き込みます。 アクションカバレッジテスト結果ファイルは、設定ファイルの「LOG_DIR」下に"coverage.action"として作成されます。 テスト実行前およびプログラムの修正時に、カバレッジテスト用テスト項目抽出ユーティリティ(coverage.php)を実行して、アクションカバレッジテスト結果ファイルを更新して下さい。 アクションカバレッジテスト結果ファイルは、エディタにて編集することができます。

画面出力処理・未設定項目の抽出ツール

トレースモード設定フラグ(特殊変数)にて画面出力処理・未設定項目の抽出の設定を行なった場合、画面出力処理時に値が未設定の画面流し込みフィールドが存在すると、画面出力処理・未設定項目履歴ファイルに未設定項目情報を追加します。 画面出力処理・未設定項目履歴ファイルは、設定ファイルの「LOG_DIR」下に"unassigned.html"として作成されます。 画面出力処理・未設定項目履歴ファイルは、エディタにて編集することができます。

DB更新処理・未設定項目の抽出ツール

トレースモード設定フラグ(特殊変数)にてDB更新処理・未設定項目の抽出の設定を行なった場合、DB更新処理時に値が未設定のフィールドが存在すると、DB更新処理・未設定項目履歴ファイルに未設定項目情報を追加します。 DB更新処理・未設定項目履歴ファイルは、設定ファイルの「LOG_DIR」下に"unassigned.query"として作成されます。 DB更新処理・未設定項目履歴ファイルは、エディタにて編集することができます。

トレースツール

トレースモード設定フラグ(特殊変数)にトレース関連フラグの設定を行なった時、実行ステップ毎にトレースファイルが生成されます。トレースファイルの格納場所は、設定ファイルの「TRACE_FILE」にて定義します。

エラー発生時スナップショットダンプ

処理実行時にエラーが発生するとログファイル格納ディレクトリ下にスナップショットダンプファイルが生成されます。 ログファイル格納ディレクトリは、設定ファイルの「LOG_DIR」にて定義します。

プログラム中の任意のトレース出力

ブログラムの任意の箇所で echoやvar_dump() 等によりトレースを行なうことができます。 echoやvar_dumpの実行結果は、dispatcherのHTMLマージ対象にはなりません。 それらは、ブラウザの画面最上部に出力され、本来のプログラムの実行結果とは区別されます。

ライセンス

速構Web Frameworkのライセンス形態は、次の2つのものがあります。