はじめに
Webアプリケーションを構築する際のアーキテクチャとして、「MVC」が広く用いられています。PHPにおいても、「mojavi」や「Phrame」など、いくつかのフレームワークが実装されています。ググってみると、日本語の解説ページなどを見つけることもできます。
最も有名なMVCフレームワークは、Javaで使える「Struts」でしょう。多くのMVCフレームワークがStrutsの影響を受けています。Strutsは非常に強力なフレームワークですが、その分、お手軽感に欠けるきらいがあります。特に、お手軽感を求めてPHPを使われている諸氏には、馴染みにくいのではないかと思います。
本稿では、手軽に使える、軽量なMVCフレームワークの雛型として、拙作の「nagaMVC」を紹介します。nagaMVCの基本的な構成について解説します。
対象読者
主に、LAMP構成(Linux+Apache+MySQL+PHP)の環境下で、Webアプリケーション構築を行った経験がある方を対象としています。nagaMVCでは、PEARライブラリを使用しますので、pearコマンド、もしくは代替手段によって、PEARライブラリのメンテナンスを行える方を対象とします。また、拙作「Nagadodb」経由でADOdbを使用しますので、「ADOdbでサクサクDBアクセス」を先に読んでおいて下さい。
mojaviを試そうとしたけれども、正直しんどかった人にオススメです。
必要な環境
筆者は、本稿の内容に関して、White Box Enterprise Linux 3.0 Resipin1、CentOS 4.0(x86-64版)といった複数のLAMP環境で開発、動作確認をしています。ADOdb、PEARは、Windows上でも使用できますので、基本的にWindows上でも動作させられます。
MVCとは
MVCとは、元々、GUIアプリケーションを構築するために考案されたアーキテクチャです。名前は、Model、View、Controllerの頭文字に由来しています。
MVCでは、アプリケーションに対するアクセス(ユーザの操作)をControllerが一元して受け取り、必要な処理を行うModelを呼び出し、結果の画面への反映をViewによって行います。
MVCアーキテクチャを取らないWebアプリケーションでは、クライアント(Webブラウザ)とのやりとりの遷移に応じて、スクリプトファイルを用意します。例えば、初回アクセスを「index.php」で受け取り、「index.php」を処理して送出したページ内から遷移できる「exec1.php」が次にリクエストされ、さらにその先の「exec2.php」をリクエストするページが送出され、といった遷移が行われます。
これに対して、MVC(厳密にはMVC2)アーキテクチャを取るWebアプリケーションでは、クライアントからの全てのアクセスを1つのスクリプトファイル(Controller)で受け取ります。ユーザのリクエストする処理の内容は、URL引数やPOSTのクエリー文字列、cookieなどを経由してアプリケーションに伝えられます。Controllerは、ユーザのリクエストする内容に応じて、処理を行うModelを選択し、Modelに処理を実行させます。処理の結果に応じて、表示を行うViewが選択され、ユーザに結果が通知されます。
MVCアーキテクチャを採用することで、ユーザからの情報を一元的にControllerが受け取ることになり、不正なアクセスの排除を考えやすくなったり、セッション管理が容易になったりします。Webアプリケーションに必要なインフラをControllerが用意することで、Modelは行うべき処理に集中できるようになります。
本稿ではMVC自体を解説するのが目的ではありませんので、この程度にとどめますが、以降の話は、MVCとは何か、そこそこ分かっていることを前提として進めます。ですので、MVCを全く知らないという方は、本稿を読むのを一旦やめて、適切な書籍やWebサイトにあたられることをオススメします。
既存MVCフレームワークの問題点
MVCを使わない開発から始めて、ある程度経験を積んでからMVCを使ってみると、非常に便利であることが実感できます。特に、簡単な自作MVCフレームワークを作ってみると、よく分かります。
MVCのことがある程度分かったら、車輪の再発明をしてもしょうがないので、メジャーで機能の揃った既存のMVCフレームワークへの移行を検討するのですが、筆者はここで違和感を覚えました。Webを見ても、同じように感じる方は、少なくないようです。
PHPにおけるメジャーで機能の揃った既存のMVCフレームワークは、MVCであること以外にも、数々の強力な機能を実装しています。これは、Strutsを参考にしているからだと思われます。しかし、Struts級の機能が必要になるWebアプリケーションは、開発的にも、実行速度的にも、かなり「重い」と考えられるので、本当にそれが必要ならJavaでの開発を検討した方が良いと考えられます。様々な面で、開発にPHPを選択する理由と、Struts級MVCフレームワークの特徴が、フィットしないため、違和感を覚えてしまうのだと考えられます。
JavaではなくPHPを選択した開発者には、Struts型ではない、PHPらしいMVCフレームワークも、選択肢として必要だと考えられます。
そこで今回は、手軽に使える、軽量なMVCフレームワークの雛型として、拙作の「nagaMVC」を紹介します。
nagaMVCの基本的な機能
nagaMVCには次のような機能が備わっています。
- MVCによる、Model、View、Controllerの分離
- セッション管理、永続オブジェクトの保持
- Model、Viewの雛型生成
- validate()
- Nagadodb経由でのDB接続、DBの自動作成
- ユーザのログインを求めるアクセス制限
MVCによる、Model、View、Controllerの分離
nagaMVCでは、「nagaMVCController.inc」がControllerとなります。Controllerは、URL引数もしくはPOSTのクエリー文字列で与えられるaction
に指定された文字列をModel名として「Model名.mdl」を読み込みます。「Model名.mdl」には、Model名を持ったクラスを記述することとし、クラスのvalidate()
にパラメータの論理的なcheckを記述し、execute()
に実行するべき処理を記述します。Modelは、Viewに渡す必要のある情報を、全て永続オブジェクトに入れます。Viewには、「Model名.ihtml」が利用され、永続オブジェクトを元に表示を行います。
ユーザから依頼された処理は、与えられたaction
に基づいて決まるクラスのexecute()
を呼び出すことで実行されます。つまり、必要な処理に応じてModelを表現するクラスを作れば、Webアプリケーションの機能を追加できるというわけです。
1つのControllerと、機能ごとに対で作られる複数のModel、Viewによる構成となります。「nagaMVCController.inc」では、永続オブジェクト$po
に格納されている文字列action
を使って、
// 要求されたmodel名の取得 $modelName = $po->get('action');
適用するModelの記述されたファイルを読み込みます。
// 要求に応じたmodelの生成 if((include_once($modelName.'.mdl')) == false) {
読み込まれたファイルには、$modelName
の名前を持ったクラスが記述されているはずと考え、$modelName
の名前を持ったクラスのオブジェクトを生成します。
$model = new $modelName();
あとは、$model
のvalidate()
とexecute()
を呼び出して処理を行い、$po
格納されている文字列view
に拡張子「.ihtml」を付けた名前のファイルを読み込み、ブラウザへ送出します。view
の初期値は$modelName
と同じ内容になっていますが、execute()
内で変更すれば、処理に応じて別のViewを送出できるようになっています。
PHPでは、実行時に動的に生成するオブジェクトを変更するのに、
$model = new $modelName();
という方法が使えます。クラス名を文字列で保持している状態から、そのクラスのオブジェクトの生成まで、たった1行で書けてしまいます。Javaのリフレクションを使って同じことを実現すると、こんなに簡単にはいきません。PHPにも意外とスマートな側面があることが分かります。是非、うまく利用して下さい。
セッション管理、永続オブジェクトの保持
Webによるデータのやりとりは、クライアント(Webブラウザ)がリクエストを出して、サーバがそれに応じたページを送出し、クライアントが受け取ることで終了します。このため、複数のやりとりを、関係した一連のやりとりであると認識するための機能がないと、実用的なサービスを構築できません。この機能をセッション管理と呼び、nagaMVCでは、永続オブジェクトの実装である「persistentObject
」クラスによって実現されています。
永続オブジェクトとは、一連のセッション(複数のページ遷移)において、いつでも参照できる値を保持したもので、ページを跨いで情報を持ち越すことが可能になります。Webアプリケーションの例としてよく挙げられるショッピングカートでは、ページが遷移してもカートに入れた商品情報を保持する必要があり、永続オブジェクトが利用されます。
「persistentObject.inc」に書かれたpersistentObject
クラスは、Controllerが実行される度に、オブジェクトを生成します。「nagaMVCController.inc」内の
$po = new persistentObject();
で生成されます。
PHPにはセッションを実現するためにSID(SessionID)をブラウザに発行する仕組みがあります。SIDの発行が有効になっている場合は、セッションごとに保持されるセッション変数を使って、永続オブジェクトを実現できます。persistentObject
クラスのコンストラクタでは、PHPの設定に応じてSIDを扱えるようになっています。
通常SIDは、発行時刻をハッシュしたものが生成されますが、ここでは自前のSID生成を行っています。
/** * SIDの生成 * <pre> * 構築するシステム毎に*必ず*実装を変えること * そうしないと、このソースを元にして、SIDの偽造される可能性が高まる * 固定文字列を1つ追加するだけで効果はある * 正規の接続が行われた場合に、その状況と$keyから、 * 同じSIDが生成されるようにすること * </pre> * @param string $key 生成時に追加できる、生成用のkeyとなる文字列 * @return string 生成したSID **/ function createSID($key) { return sha1($_SERVER['SERVER_NAME'] .$_SERVER['HTTP_USER_AGENT'] .$_SERVER['REMOTE_ADDR'].$key); }
createSID()
は、サーバとブラウザそれぞれに由来する情報を元にSIDを生成します。これによって、SIDが正しいものであるか確認できるようになります。例えば、IPアドレス192.168.1.2を使って生成されたSIDを、IPアドレス192.168.3.4のブラウザが保持していた場合、そのアクセスを無効として、永続オブジェクトを参照させないようにすることができます。ただし、これらの情報を詐称することは可能なので、完璧だとは思わないで下さい。また、実装が分かっているとSIDの偽造の危険性が高まりますから、sha1()
に与える文字列は、順番を変えたり、固定の文字列を足したりして、必ず変更して下さい。
セッションが正しく復元できた場合は、
$this->_session =& $_SESSION;
によって、persistentObject
内の_session
を経由して、セッション変数が使用可能になります。実際にはget()
、set()
、delete()
を通じて使用することになります。
persistentObject
に保持される変数には2種類あり、セッションを跨いで持ち越される永続的な変数と、ModelからViewに渡したり、form(ユーザ入力)からModelに渡すためだけに使われる一時的な変数があります。一時的な変数は、変数名に接頭語を付ける事で区別できるようになっています。GET/POSTによって送られて来た情報も、全てセッション変数に登録されることで、以前から保持している情報も、新しく与えられた情報も、全てpersistentObject
によって一元管理されることになります。リポジトリに情報を集約できるわけです。persistentObject
内の一時的な変数は
/** * 1timeなkeyの接頭語のsetter * @param string $value 接頭語に設定する文字列 * @return string 接頭語に設定した文字列 **/ function setOTHead($value) { $this->_ot_head = $value; return $this->_ot_head; }
によって登録された接頭語を持つ名前で登録しておき、Viewが送出された時点で破棄するようになっています。「nagaMVCController.inc」内の
// 結果に応じてページ送出 createView(); // 1time値を捨てる $po->delete1time(); exit;
によって、
/** * 永続オブジェクトから1timeな値を削除する * <pre> * $_ot_headな接頭語を持つkeyによって参照される値は、 * 次回の持続的接続時に、参照の必要のないものとし、 * 永続オブジェクトから削除する * </pre> **/ function delete1time() { foreach($this->_session as $key => $value) if(preg_match("/^{$this->_ot_head}/", $key)) $this->delete($key); }
が呼び出されています。
SIDが無効な環境下では、form内にSIDと永続オブジェクトのメンバを埋め込む代替手法も実装されており、PHPの設定に応じて、自動的に機能します。今回のサンプルには実装されていませんが、永続オブジェクトの内容を全てURL引数やform内のhidden要素としてViewに埋め込むために、
/** * 永続オブジェクトの保持する値からform内に埋め込む * hiddenなinputタグの集合を生成 * <pre> * $_mode='form'の場合、永続オブジェクトを維持する為に、 * 永続オブジェクトの保持する値を、hiddenなinputタグとして、 * 送出するページのform内に埋め込む必要がある * そのタグを文字列として生成する * 1time値は対象外とする * </pre> * @return string form内に埋め込むhiddenなinputタグの集合 **/ function createHiddenInput() { if($this->_mode != 'form') return ''; $ret = ''; foreach($this->_session as $key => $value) if(!preg_match("/^{$this->_ot_head}/", $key) && ctype_alnum($key)) { $key = $this->_persistent_head.$key; $value=urlencode($this->_encryptor-> encrypt(serialize($value))); $ret .= "<input type='hidden' name='$key' value='$value'>"; } return $ret; } /** * 永続オブジェクトの保持する値からURL引数を生成 * <pre> * $_mode='form'の場合、永続オブジェクトを維持する為に、 * 永続オブジェクトの保持する値を、 * 次回アクセス時のURL引数に埋め込むことを考えられる * そのURL引数を文字列として生成する * 1time値は対象外とする * </pre> * @return string URL引数 **/ function createURLString() { if($this->_mode != 'form') return ''; $ret = ''; foreach($this->_session as $key => $value) if(!preg_match("/^{$this->_ot_head}/", $key) && ctype_alnum($key)) { $key = $this->_persistent_head.$key; $value = urlencode(urlencode($this->_encryptor-> encrypt(serialize($value)))); $ret .= "&$key=$value"; } return substr($ret, 1); }
が用意されています。この仕組みによって、情報の引き継ぎが、セッション変数なしに実現できます。
永続オブジェクトのうちクライアント側で使いたい情報を、form内のhidden要素やJavaScriptの変数定義などの形でViewに埋め込むと、クライアント側でJavaScriptなどを用いて与えられた値を利用できるため、サーバとクライアントでシームレスな情報共有を実現することも可能です。
こうした仕組みによって、セッションごとにセッションのIDをチェックし、永続オブジェクトを復元します。
Model、Viewの雛型生成
多くのMVCフレームワークでは、Modelごとにサブディレクトリを作成し、Modelのロジックを記述したファイルと結果表示に使うViewを配置するようになっています。Modelごとにコーディング担当者を決め、各自が独立した作業を行う際には、ファイルに対する権限が明確になるのでメリットがあります。しかし、小規模な開発や少人数による開発では逆にファイルが分散してしまうので、作業が面倒に感じられます。統合開発環境を使っていれば感じないのかも知れませんが、統合開発環境の利用を重く感じることもあります。
nagaMVCでは、ほぼ全てのファイルを同一ディレクトリに配置することをポリシーとしています。そのディレクトリの中身さえメンテナンスしていれば、Webアプリケーションの状態を正しく保つことができます。
また、設定ファイルで開発中フラグを設定しておくと、Modelの存在しないactionがリクエストされた場合に、自動的に雛型となるModel、Viewのファイルを生成する機能を持っています。必要性はさておき、最近の開発環境にはこの手の支援機能を持ったものが多いので、興味本位で付けてみました。
// 要求に応じたmodelの生成 if((include_once($modelName.'.mdl')) == false) { // 開発(debug)時には、雛型を自動生成する if(NAGAMVC_DEVEL) { if(!copy(NAGAMVC_PATH.'/baseModel.mdl', NAGAMVC_PATH.'/'.$modelName.'.mdl') || !copy(NAGAMVC_PATH.'/baseView.ihtml', NAGAMVC_PATH.'/'.$modelName.'.ihtml') || !chmod(NAGAMVC_PATH.'/'.$modelName.'.mdl', 0666) || !chmod(NAGAMVC_PATH.'/'.$modelName.'.ihtml', 0666)) createView(true, "雛型のコピーに失敗しました<br>" ."ディレクトリの書き込み権限を確認して下さい"); require_once('File/SearchReplace.php'); $snr = new File_SearchReplace('baseModel', $modelName, NAGAMVC_PATH.'/'.$modelName.'.mdl', "./", false); $snr->doSearch(); require_once($modelName.'.mdl'); $model = new $modelName(); } else error2top('model生成失敗', '不正な引数で接続が試みられた可能性があります', $po->get('user').':'.$po->get('pass').'@'); }
「nagaMVCController.inc」では、開発中の実行において、Modelとなるクラスが記述されたファイルが見つからなかった場合、Modelとなるクラスの雛型が記述された「baseModel.mdl」と、Viewの雛型となる「baseView.ihtml」をコピーして、呼び出されるファイルを生成します。また、「baseModel.mdl」にはbaseModel
クラスが記述されているので、単にコピーするだけでは、Modelとなるクラスが記述されていることにはなりません。そこで、ファイル内の置換を行うPEARライブラリのFile_SearchReplace
クラスを使って、クラス名やコンストラクタの記述を置換します。こうして出来上がったModelとなるクラスが記述されたファイルを読み込んで、Modelとなるオブジェクトを生成しています。
機能をリクエストするmenuを表示するViewを作成し、ブラウザに表示させてクリックすれば、必要なファイルが作られます。作られたファイルにModelの処理とViewを書き込めば、新しい機能を実装できます。
validate()
Controllerが呼び出すModelのメソッドは、コンストラクタを除けば、validate()
とexecute()
になります。execute()
は文字通り、処理を実行するコードを書く部分になりますが、validate()
は何のために用意されているのでしょう。
validate()
は、処理を実行する前に、処理に使われる値が正しいものかどうかを判断するコードを書く部分になります。場合によっては、値を補正して正しくする機能を持たせることもあるでしょう。
処理に用いられる値は、基本的に、永続オブジェクトの中にあるか、DBから取り出されるかのいずれかになるでしょう。これらの値は、そもそもユーザによって与えられたものであり、処理を行う上で想定の範囲内であることが保証されません。このため、処理を行う前に、使用する値が想定の範囲内に収まっていることを確認しておく必要が生じます。例えば、formから正の数を入力してもらったつもりでも、実際には負の数や、文字列である可能性があるので、正の数か確認する必要があります。
更に、値が、そのままhtmlの一部として送出されたり、DBに投入されたり、OSにコマンドとして与えられるとしたら、どうでしょう? XSSやSQLインジェクション、コマンドインジェクションと呼ばれる脆弱性を抱えることになります。こうしたものへの対策として、validate()
内で、htmlspecialchars()
、addslashes()
、escapeshellarg()
などの関数を適切に用いて、処理が行われる時には、必ず値が安全であるようにしておく必要があります。
Nagadodb経由でのDBの自動作成
nagaMVCには、作成したWebアプリケーションのインストールを簡単にするため、Webアプリケーションの使用するDBを自動的に作成する機能を持たせてあります。
オープンソースなWebアプリケーションでは、類似の機能を有するものが多くありますが、サーバ側のアプリケーションを書く仕事をしていると、こうしたケアを忘れがちです。
誰でも簡単にインストールが行えて、すぐ使えるように作っておけば、開発者でなくともインストールが行えるようになります。インストールから先を運用スタッフに面倒を見てもらえれば、開発者は開発に注力できます。また、開発者並みのスキルがないとインストールできないようでは、無用なコストを払うことになってしまいます。
DBの作成は、スキーマを定義ファイルに書くようなものではなく、SQL文が順に実行されることで行われます。つまり、手順の集合によって行われます。SQLに詳しい開発者なら、開発中にカラムを追加した経験のある人もいるでしょう。しかし、その変更をどこかに記録しておかないと、誰にもDBの構造が分からなくなってしまいます。複雑なテクニックを駆使して作られたExcelシートを難解に感じるのは、Excelシートが基本的に手順の集合によって作成されており、その手順に関する情報が欠落しているからです。そうした状況に陥らないように、DBを作成するためのSQL文を完全に記述したファイルのメンテナンスが重要です。nagaMVCでは、「setup.sql」が、その目的のために用意されています。
nagaMVCのユーザ管理機能は、DBのgroupsテーブルとusersテーブルを使って実現されています。
-- ユーザ管理テーブル DROP TABLE users; DROP TABLE groups; CREATE TABLE groups ( id bigint not null auto_increment primary key, name varchar(64) not null unique, info text not null ); INSERT INTO groups values ('', 'admin', '管理者'); INSERT INTO groups values ('', 'guest', 'ゲスト'); INSERT INTO groups values ('', 'worker', '作業者'); CREATE TABLE users ( id bigint not null auto_increment primary key, name varchar(64) not null unique, group_name varchar(64) references groups(name) match full, pass varchar(64) not null, email varchar(64) not null, back_execute_count int ); INSERT INTO users values ('', 'admin', 'admin', 'admin', 'admin@hogehoge.jp', 0); INSERT INTO users values ('', 'guest', 'guest', 'guest', 'guest@hogehoge.jp', 0); INSERT INTO users values ('', 'mnagaku', 'pass', 'worker', 'mnagaku@hogehoge.jp', 0);
このテーブルによって、各ユーザを登録し、グループ単位でアプリケーションへの権限を与えるようにすることができます。ログインの処理は、「nagaMVCController.inc」内の
// Login処理 function nagaMVCLogin() { global $po, $db; if(!$po->get('user') || !$po->get('pass')) return false; if($po->getMode() != 'form' && $po->get('group')) return true; $db->setLoggingLevel('selected'); $db->setTracer($po->get('user').':'.$po->get('pass') .'@'.$_SERVER['REMOTE_ADDR'].'[' .$_SERVER['HTTP_USER_AGENT'].']'); $ret = $db->select('users', 'group_name, email', 'name = \''.$po->get('user').'\' and pass = \'' .$po->get('pass').'\''); $db->setLoggingLevel('off'); if(count($ret) != 1) return false; $po->set('group', $ret[0]['group_name']); $po->set('email', $ret[0]['email']); return true; }
で、行われています。送られて来たユーザ名、パスワードでDB内を検索し、ユーザが見つかった場合は、ユーザのグループとメールアドレスを永続オブジェクトに追加します。
また、DBの操作logへの書き出しに使われるTracer文字列に、ユーザ名とパスワードを追加して、ログイン処理自体の履歴が保存されるようにしています。
nagaMVCを動かしてみる
長々と解説してきましたが、結局は、動作するコードを見るのが、理解への早道でしょう。実際にサンプルプログラムを動かしてみましょう。
index.phpの配置
nagaMVCでは、httpdのDocumentRoot以下に、本体を置きません。httpdのDocumentRoot以下は、正しく設定を行わないと、Webブラウザで簡単に見えてしまうからです。そこで、本体のControllerを呼び出すだけのコードを書いたスクリプトファイルを、index.phpとして、httpdのDocumentRoot以下の適切なディレクトリに配置します。
今回のサンプル「nagaMVCv1.zip」に含まれる「index.php」では、「/var/www/php_modules/nagamvc_modules/」に、nagaMVCの本体を置くことを想定しています。
nagaMVC本体の配置
「nagaMVCv1.zip」に含まれる「nagamvc_modules」を、「/var/www/php_modules/」として配置します。「nagamvc_modules」には、Controller、永続オブジェクトの実装、ログイン機能のModelとView、ModelとViewのテンプレート、設定ファイルなどの各種ファイルが収められています。
nagaMVCには、Model、Viewの雛型生成機能があるため、httpdのプロセスから、「/var/www/php_modules/」に書き込めるよう、パーミッションを設定しておいて下さい。開発が終了すれば書き込む必要はなくなり、書き込めないように設定するべきでしょうが、サンプルの動作を確認する際には、書き込み可能な設定が必要です。
また、「/var/www/php_modules/setup.php」内に、DBに接続するDSN文字列があります。ここでは、DBを作成するためにroot権限で接続する必要があるので、動作環境に合わせて、パスワードを設定して下さい。
「/var/www/php_modules/setup.sql」内に、DBを生成するためのSQL文が書かれています。MySQL以外のDBを使われている場合は、特にアクセス権限の設定個所などを中心に、修正の必要があるかも知れません。
設定ファイル「/var/www/php_modules/nagaMVC.conf」にも、DB接続のためのDSN文字列があります。こちらも、動作環境に合わせて修正の必要があるかも知れません。
ADOdbの配置
「/var/www/php_modules/include/adodb/」に、ADOdbが必要です。ADOdbは、ADOdbの公式ページからリンクをたどってダウンロードできます。Project: ADOdb: File Listから、最新版の「adodb-x.xx-for-php」をダウンロードして下さい。
Nagadodb経由で使用されるので、一部、ハックが必要になります。「ADOdbでサクサクDBアクセス」を参考に、修正して下さい。
PEARライブラリの準備
nagaMVCでは、テンプレートとなるファイルをコピーして書き換えることで、ModelとViewの雛型を自動生成します。この際、PEARライブラリにある、 ファイル群内のテキストを置換する「File_SearchReplace」を使用します。また、永続オブジェクトで、暗号を使用するために「Crypt_Blowfish」を使用します。pearコマンドなどを使って、モジュールのインストールを行って下さい。
動かしてみよう
全ての準備が整ったら、Webブラウザで「index.php」にアクセスしてみましょう。
1回目のアクセスでは、setupが実行され、DBが作成されます。
2回目のアクセスでは、ログイン画面が出てきます。これは設定ファイル「/var/www/php_modules/nagaMVC.conf」にログイン機能を有効とする設定があるからです。ここでユーザ名、パスワード共に「guest」を指定すると、ログインが行われます。
ログイン機能が無効な場合の最初のアクセスや、ログイン後の最初のアクセスは、「first.mdl」と「first.ihtml」によって処理されます。しかし、このサンプルでは、「first.mdl」、「first.ihtml」が存在しないため、自動的に雛型が作られます。実際に、ログイン後、2つのファイルが増えていて、「first.ihtml」が表示されていることを確認して下さい。「first.mdl」、「first.ihtml」の中身を、「first.mdl.org」、「first.ihtml.org」で置き換えると、簡単なアプリケーションの操作が行えるようになります。
新しい機能を追加する場合には、「first.ihtml」をmenuの表示と考え、「first.ihtml」に新しいactionを送信するformを作ります。次に、Webブラウザでアクセスし、そのformの送信を行うと、新しい機能を書くべき.mdlファイルと.ihtmlファイルが生成されます。あとは、雛型の中身を書けば、新しい機能を追加できます。
まとめ
本稿では、拙作MVCフレームワーク「nagaMVC」を通して、軽量な自作MVCフレームワークを提案してみました。皆さんが抱えている案件の中にも、軽量な自作MVCフレームワークに適したものがあるかも知れません。