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程度の抽象化されたモデル)
きわめて簡潔なプログラム記述
ルールの数を必要最小限にまで減らす
学習容易性に主眼を置いたシステム構造、処理の抽象化
一つのHTMLウィンドウ内に独立して動作する複数のアプリケーションポートレット(以下、単にポートレットと呼びます)を表示させることができます。
一見複雑に見えるコマースサイトやEIP等は、複数の単機能ポートレットの集合体とみなすことができます。 それぞれのポートレットの開発・テスト・デプロイ・運用を独立した単位で行なうことができます。
このシステムは、一般的なウィンドウシステムに近い構造により実現されています。
(ディスパッチャ、イベントドリブンによる動作構造)
外面的なデザインと内部処理ロジックを完全分離するために、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の内容等を反映した表示画面の組み立てを行ないます。 ブラウザ用画面組み立ての際、ディスパッチャにより画面表示に必要なプレゼンテーションロジックが起動されます。
各ポートレットステータス毎に、対応したプレゼンテーションロジックを用意する必要があります。
どのプレゼンテーションロジックが画面表示の為に実行されるかは、表示対象のポートレットの現在のステータス値によって決まります。
ポートレットのプレゼンテーションロジックの内容は、通常下記のようになります。
テンプレートへのデータの流し込みについては、各種のユーティリティ関数が用意してあり、データディクショナリとの組み合わせで、少ないステップで表示ロジックを組立てることができます。
プレゼンテーションロジックの実装例:$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時と同様にコントロールロジックの起動、カレント変数の上書きが行なわれます。
ポートレットのコントロールロジックの内容は、通常下記のようになります。
ポートレットの為のプログラムロジック格納ディレクトリにポートレットコモンロジック定義ファイルを設置すると、プレゼンテーションロジック、コントロールロジックの実行の直前にポートレットコモンロジックが実行されます。 ポートレットコモンロジック定義ファイルの名称は、「_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]); } } }
select, insert, update処理に関する抽象化されたサービスを提供します。 例えば、レコード内のフィールドを意識することなく、ポートレット変数の内容で一括してレコードを挿入、更新を行なう等の処理ができます。
DBデータの画面への表示についてもselectインターフェースにより取得した値setを一括して画面テンプレートに流し込みが行なえます。
画面テンプレートと同様の値setの一括設定とメール送信が簡単な記述で行なえます。
マルチメディアデータを含む複雑な形式の大量のデータをInfoPathを介して登録できるようにするソリューションを提供いたします。
画面テンプレートと同様の値setの一括設定を利用したXML、PDF、テキストの生成を簡単な記述で行なえます。
/システムルートディレクトリ/ … 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> <body> <table> <tr> <td>{&menu}</td><td>{&shopcart}</td> </tr> </table> </body> </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}
記法:
{変数名/アトリビュート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に対する処理は、データ入力チェックロジックディクショナリに記述します。
記法:
{?入力フィールド名/アトリビュート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}を記述した場合{変数名/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}を記述した場合{変数名/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}> カタログを送付
記法:
{_CONTROL}例:
<form action="i.php"> {_CONTROL} <input type="submit" name="_ACTION[next]" value="確認"> </form>
記法:
{_CONTROL_URL}例:
<a href="i.php?{_CONTROL_URL}&_ACTION[next]=1">確認</a>
記法:
<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>
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>
アクション以外にパラメータを追加して渡すことができます。
記法:<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>
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>
記法:
<a href="i.php?{_CONTROL_URL}&_ACTION[アクション名]=1>例:
<a href="i.php?{_CONTROL_URL}&_ACTION[check]=1&ITEM_ID=111">在庫確認</a>
過去の画面遷移の履歴の中で指定されたカウント数分画面を戻します。
記法:<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>
過去の画面遷移の履歴の中でヒストリーマークが設定されているページに画面を戻します。
記法:<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>
記法:
_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'">
記法:
{_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');
記法:
画面プロセスオブジェクト変数->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();
記法:
画面プロセスオブジェクト変数->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');
記法:
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');
記法:
pm9db_core::db_start()例:
pm9db_core::db_start();
記法:
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);
記法:
レコードデータ格納用連想配列 = pm9db_core::select_single(クエリー文字列)例:
$rec = pm9db_core::select_single( "select * from INSERT_DATE >= '$START_ge'");
記法:
項目データ格納用変数 = 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']}%'");
記法:
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 = pm9mvc::get_system_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';
DocumentRoot下もしくは、任意のディレクトリを作成して、パッケージを展開して下さい。
cd /var/www/html mkdir test cd test tar xvfz pm9framework.xxx.tgz
pm9framework.soをPHP拡張ライブラリ検索Pathの通ったディレクトリの下にコピーして下さい。
cp library/pm9framework.so /usr/lib/php4/.
php.iniのディレクティブもしくは.htaccessによりmagic_quotes_gpc をOffに設定して下さい。
php.ini設定例:magic_quotes_gpc = Off.htaccess設定例:
php_value magic_quotes_gpc 0
フレームワークの環境設定ファイルに合わせて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');
/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更新処理・未設定項目履歴ファイルは、設定ファイルの「LOG_DIR」下に"unassigned.query"として作成されます。 DB更新処理・未設定項目履歴ファイルは、エディタにて編集することができます。
トレースモード設定フラグ(特殊変数)にトレース関連フラグの設定を行なった時、実行ステップ毎にトレースファイルが生成されます。トレースファイルの格納場所は、設定ファイルの「TRACE_FILE」にて定義します。
処理実行時にエラーが発生するとログファイル格納ディレクトリ下にスナップショットダンプファイルが生成されます。 ログファイル格納ディレクトリは、設定ファイルの「LOG_DIR」にて定義します。
ブログラムの任意の箇所で echoやvar_dump() 等によりトレースを行なうことができます。 echoやvar_dumpの実行結果は、dispatcherのHTMLマージ対象にはなりません。 それらは、ブラウザの画面最上部に出力され、本来のプログラムの実行結果とは区別されます。
速構Web Frameworkのライセンス形態は、次の2つのものがあります。