Moony

Moonyは、PHPで記述された軽量なWebアプリケーションフレームワークです。
テンプレートエンジンとしてSmartyを利用しています。 (開発日誌: Moony::log

  1. 動作環境
  2. インストール
  3. 概要
  4. チュートリアル
  5. ライセンス

動作環境

インストール

pearを使用してインストールする手順を以下に示します。
pearを使用しない場合は、任意のディレクトリに展開・配置してください。

  1. Moony-0.10.4.tgzをダウンロードします。
  2. 以下のコマンドを実行します。
    $ pear install /path/to/Moony-0.10.4.tgz
  3. Smartyをインストールしていない場合は、以下の手順でインストール可能です。
    $ pear channel-discover pearified.com
    $ pear install pearified/Smarty
  4. Moonyをアンインストールする場合は、以下のコマンドを実行します。
    $ pear uninstall __uri/Moony

概要

処理のフロー

ディスパッチャとしてindex.phpを用意、/index.php/foo.htmlにアクセス:

  1. クライアント → index.php (ディスパッチャ)
  2. index.php → Moony (生成、ディスパッチ)
  3. Moony → Moony_Controller (インスタンス生成、各種設定)
  4. Moony_Controller → Moony_Router (アクション名の決定)
  5. Moony_Controller → Moony_Request (リクエストパラメータを格納)
  6. Moony_Controller → Moony_Response (レスポンス生成)
  7. Moony_Controller → Moony_Session (セッション生成、開始)
  8. Moony_Controller → Moony_Flash (生成、Flash変数リストア)
  9. Moony_Controller → Moony_View (デフォルトテンプレート名称を設定)
  10. Moony_Controller → Moony_Plugins (Smartyのプラグインを設定)
  11. Moony_Controller → Foo (生成)
  12. Moony_Controller → Moony_Injector (生成、インジェクション)
  13. Moony_Controller → Foo (filterメソッドを実行)
  14. Moony_Controller → Foo (validateメソッドを実行)
  15. Moony_Controller → Foo (executeメソッドを実行)
  16. Moony_Controller → Moony_View (画面描画処理)

アクション名の決定方法

URLと動作するスクリプトのマッピングのために設定ファイルを記述する必要はありません。
規約として以下のようにマッピングされます:

URLアクション名アクションクラスファイルテンプレートファイル
/index.php/foo.htmlFooFoo.phpFoo.tpl
/index.php/foo/bar.htmlFooBarFooBar.phpFooBar.tpl
/index.php/foo_bar.htmlFooBarFooBar.phpFooBar.tpl
/index.php/foo/bar/param.htmlFooBarFooBar.phpFooBar.tpl
/index.php/fooFooFoo.phpFoo.tpl
/index.php/foo/FooIndexFooIndex.phpFooIndex.tpl
/index.php/foo/index.htmlFooIndexFooIndex.phpFooIndex.tpl
/index.php/IndexIndex.phpIndex.tpl
/index.php/index.htmlIndexIndex.phpIndex.tpl

拡張子は常に無視され、URLの2階層目までがアクション名として扱われます。
それ以降のURL文字列は、アプリケーションのパラメータとして扱われます。
アクション名として扱う階層数は、Moony.phpの定数定義で設定の変更が可能です。
ディレクトリにアクセスがあった場合は、indexにアクセスがあったものとみなします。

ディレクトリなど、動作環境の設定

アクションクラスの格納先、テンプレートファイルの格納先、 ワークファイルの格納先、ログファイルの出力先などをそれぞれ設定することができます。 Moonyの下記それぞれのインスタンスメソッドを実行してください。

メソッド名機能設定しない場合の既定値
setActionDir($action_dir)アクションクラス格納先ディレクトリの設定action
setTemplateDir($template_dir)テンプレートファイル格納先ディレクトリの設定template
setWorkDir($work_dir)ワークファイル格納先ディレクトリの設定work
setLogDir($log_dir)ログファイル出力先ディレクトリの設定log
setTemplateExtension($template_extension)テンプレートファイルの拡張子の設定tpl
setLeftDelimiter($left_delimiter)Smartyの左区切り文字の設定{
setRightDelimiter($right_delimiter)Smartyの右区切り文字の設定}

エラー時の処理

表示に必要なテンプレートファイルが見つからない場合、404(Not Found)を返します。 また、アプリケーション内でエラーが発生した場合、500(Internal Server Error)を返します。 いずれの場合もロギング処理が行われます。

チュートリアル

ディスパッチャの実装

Smarty.class.phpとMoony.phpをインクルードします。 Moonyのインスタンスを生成、必要に応じて各種設定を行い、dispatchメソッドを実行します。

実装例を以下に示します:

<?php
require_once '/path/to/Moony.php';
require_once '/path/to/Smarty.class.php';
$moony =& new Moony();
$moony->setLeftDelimiter('<{');
$moony->setRightDelimiter('}>');
$moony->dispatch();
?>

インジェクション

アクションクラスのインスタンス変数に対して、 Moonyを構成するコンポーネントのインスタンスがインジェクションされます。 デフォルトで以下のようにインジェクションされます。 インスタンス変数が用意されていない場合、インジェクションは行われません。

インスタンス変数名インジェクションされるクラス
$requestMoony_Request
$responseMoony_Response
$sessionMoony_Session
$flashMoony_Flash
$smartySmarty

また、任意のクラスのインスタンスをインジェクションすることができます。 下記のようなiniファイルを用意、Injectionsセクション内にキー:インスタンス名、値:クラス名を記述します。 クラスのファイルはinclude_pathを基準にして、PEARの命名規則に従ってサーチされます (Foo_Calcクラスの場合Foo/Calc.php、ただしMoony_DBとMoony_Uploaderを除く)。 いずれのインスタンスもアクションクラス内にインスタンス変数が定義されていない場合は生成されません。

[Injections]
calc=Foo_Calc
db=Moony_DB
uploader=Moony_Uploader

作成したiniファイルは、ディスパッチャで読み込み指定をしておきます。

<?php
require_once '/path/to/Moony.php';
require_once '/path/to/Smarty.class.php';
$moony =& new Moony();
$moony->setConfigFile('/path/to/ini_file');
$moony->dispatch();
?>

アクションクラスの実装(実際の処理)

実際の処理はexecuteメソッドに記述します。 特に実装を行わない場合、アクションクラス自体を省略することも可能です。 その場合、規約に従った名称のテンプレートファイルが直接表示されます。

class Foo
{
    function execute()
    {
        // 実際の処理
    }
}

アクションクラスの実装(リクエストパラメータ値の事前変換処理)

リクエストパラメータの値を処理前に変換する場合は、 filterメソッドに処理を記述します。パラメータとしてMoony_Filterのインスタンスが渡されます。

class Foo
{
    var $request;
    function filter($filter)
    {
        // 'furigana'の値を全角カタカナに変換
        $filter->toKatakana('furigana');
        // 'name'の値が'foo'だった場合、'bar'に置換する
        if ($this->request->get('name') == 'foo') {
            $this->request->replace('name', 'bar');
        }
    }
}

アクションクラスの実装(リクエストパラメータ値のチェック処理)

リクエストパラメータの値をチェックする場合は、 validateメソッドに処理を記述します。パラメータとしてMoony_Validatorのインスタンスが渡されます。 エラーがされた場合、入力元のテンプレートが再表示されます(セッションが開始している場合)。

POSTを受け取って処理を行うアクションクラス:

class Register
{
    var $request;
    function validate($validator)
    {
        // validationエラー時の使用テンプレートを指定
        $validator->setTemplate('Entry');

        // Moony_Validatorの機能を使用
        $validator->setRequired('name', '名前は必ず入力してください。');
        $validator->setKatakana('furigana', 'フリガナはカタカナで入力してください。');

        // 独自検証(エラーの場合、エラーメッセージを設定)
        if ($this->request->get('foo_cd') != '1') {
            $validator->addError('foo_cd', 'CDの設定が正しくありません。');
        }
    }
}

validationエラーが検知されて入力元のテンプレートファイルに遷移した場合に、 エラーメッセージを表示したい場合は入力フォームのテンプレートを以下のようにします。 より詳しい説明に関しては、Moony_Pluginsクラスを参照してください。

入力フォームのテンプレートファイル:

{moony_errors header='<ul>' footer='</ul>' prefix='<li>' postfix='</li>'}
<form action="/index.php/register" method="POST">
フリガナ: <input type="text" name="furigana" value="{$furigana}" />
名前: <input type="text" name="name" value="{$name}" />
<input type="submit" />
</form>

リクエストパラメータの取得

リクエストパラメータはMoony_Requestクラスに格納されています。 このクラスに格納されているのは、あらかじめNullバイト文字列が除去され、文字エンコーディングの変換が行われた値です。

class Foo
{
    var $request;
    function execute()
    {
        // それぞれの値
        $user = $this->request->get('user');
        $pass = $this->request->get('pass');

        // パラメータをプロパティとして持つオブジェクトを取得
        $obj = $this->request->toObject();
    }
}

URLとして渡されたパラメータの取得

URLとして渡されたパラメータはMoony_Requestクラスに格納されています。 例えば、/index.php/foo/bar/param1/param2.htmlというURLの場合:

class FooBar
{
    var $request;
    function execute()
    {
        $param1 = $this->request->getPathInfo(0);   // 文字列'param1'を取得
        $param2 = $this->request->getPathInfo(1);   // 文字列'param2'を取得
    }
}

セッションを扱う

セッションにはMoony_Sessionクラス経由でアクセスします。

class Foo
{
    var $request;
    var $session;
    function execute()
    {
        if ($this->session->exists('user')) {    // キーの存在確認
            $user = $this->session->get('user');  // 取得
        } else {
            $user = $this->request->get('user');
            $this->session->set('user', $user);   // 設定
        }
    }
}

Flash変数を扱う

Flash変数は一時的な値を格納する領域です。Moony_Flashクラス経由でアクセスします。 実際の値はセッションに格納され、次のアクションが実行されるときまで保持されます。 その次のアクションが実行されるタイミングで、該当のFlash変数は破棄されます。

class Foo
{
    var $flash;
    function execute()
    {
        $user = $this->flash->get('user');   // 取得
        $this->flash->set('user', $user);    // 設定
        $this->flash->keep('user');          // 次のアクションに引継ぎ
    }
}

テンプレートに値を設定する

Moony_Responseクラスを使用します。

class Foo
{
    var $response;
    function execute($request, $response)
    {
        $this->response->set('user', $user);        // 値はデフォルトでエスケープ
        $this->response->setAll($items);            // 連想配列、値はデフォルトでエスケープ
        $this->response->set('user', $user, false); // 明示的にエスケープしない場合
        $this->response->setAll($items, false);     // 連想配列、明示的にエスケープしない
    }
}

使用するテンプレートファイルの変更

Moony_Responseクラスを使用します。

class Foo
{
    var $response;
    function execute()
    {
        $this->response->setTemplate('Another');   // Another.tplを使用
    }
}

アクションチェーン

Moony_Responseクラスを使用します。 リクエストパラメータとテンプレートに設定した値は次のアクションにも引き継がれます。

class Foo
{
    var $response;
    function execute()
    {
        $this->response->setNextAction('NextAction');
    }
}

別のURLにリダイレクトを行う

Moony_Responseクラスを使用します。

class Foo
{
    var $response;
    function execute()
    {
        $this->response->redirect('http://example.com/');   // example.comへ
    }
}

ユーザに対してファイルのダウンロードを行う

Moony_Responseクラスを使用します。

class Foo
{
    var $response;
    function execute()
    {
        $this->response->sendFile('/path/to/attachment_file');   // attachment_fileをダウンロード
    }
}

ファイルのアップロードを行う

Moony_Uploaderクラスを使用します。

<form action="/index.php/upload" enctype="multipart/form-data" method="POST">
  <input type="file" name="userfile" />
  <input type="submit" value="send" />
</form>

上記のようなフォームがある場合、以下のように記述することでファイルアップロード処理を行うことができます (iniファイルでMoony_Uploaderのインジェクション設定が行われている場合)。

class Upload
{
    var $request;
    var $uploader;
    function execute()
    {
        $uploader->setTarget($this->request, 'userfile');
        $uploader->setEncoding('SJIS');
        if ($uploader->upload('/path/to/save_dir', 'save_file_name', 0644)) {
            // アップロード成功
        } else {
            // アップロード失敗
        }
    }
}

インジェクション設定ファイルでMoony_Uploaderクラスが指定された場合、 Moony_Uploaderのインスタンスがアクションクラスのインスタンス変数としてインジェクションされます。

単純なテキストの出力を行う

Moony_Responseクラスを使用します。Moony_Response::outputは複数回実行することが可能です。 2番目の引数として文字エンコーディングの指定が可能です。この処理が実行された場合、 テンプレートのレンダリング処理は実行されません。Ajaxにも対応可能です。

class Foo
{
    var $response;
    function execute()
    {
        $this->response->output('出力したいテキストの内容', 'UTF-8');
    }
}

トランザクショントークンのチェックを行う

Moony_Requestを使用します。まず、送信フォームのテンプレートに以下のように記述します。

<form action="/index.php/foo" method="POST">
  {moony_token xhtml=true}   {* XHTMLとして出力しない場合、xhtml=trueの記述は不要 *}
</form>
すると、画面表示時に以下のように展開されます(Smartyのプラグイン機能を利用)。
<form action="/index.php/foo" method="POST">
  <input type="hidden" name="_moony_token" value="..." />
</form>
このフォームのPOSTリクエストを受け取るアクションクラスで、トランザクショントークンの妥当性チェックを行います。 以下のように記述することでチェックを行うことができます。
class Foo
{
    var $request;
    var $session;
    function execute()
    {
        if ($this->request->checkToken()) {
            // 正しいトークン
        } else {
            // 不正なトークン
        }
    }
}

Moony_DBを使う

Moony_DBはPEAR::DBを利用した単純なデータベースアクセスクラスです。 リプレースホルダーを含んだSQLを実行し、 検索結果を項目の名称をキーとする連想配列の配列として返します。 また、項目値の文字エンコーディングの変換を自動で行います。

$db =& new Moony_DB();
$db->connect($dsn, 'EUC-JP');   // DBの文字エンコーディングがEUC-JPの場合
$result = $db->query('select id,name from user where id=?', array($user_id));
$db->disconnect();
foreach($result as $row) {
    print 'id: ' . $row['id'] . ', name: ' . $row['name'] . "\n";
}

インジェクション設定ファイルでMoony_DBクラスが指定された場合、 Moony_DBのインスタンスがアクションクラスのインスタンス変数としてインジェクションされます。

ログ出力を行う

Moony_Loggerクラスを利用することでテキストログが出力可能です。 また、Moony.phpのMOONY_LOG_CATEGORYの値を変更することで ログ出力を行うログレベルの閾値の設定を行うことができます。 (初期値はMOONY_LOG_LEVEL_INFOで、debugログは出力されません。)

Moony_Logger::fatal('message');   // 致命的エラー
Moony_Logger::error('message');   // エラー
Moony_Logger::warn('message');    // 警告
Moony_Logger::info('message');    // 通常
Moony_Logger::debug('message');   // デバッグ用
Moony_Logger::info('message', __FILE__);             // ファイル名を出力
Moony_Logger::info('message', __FILE__, __LINE__);   // ファイル名、行番号を出力

ライセンス

Moonyは猫耳舎山岡広幸が個人的に作成しているアプリケーションです。
BSDライセンスに基づいて配布されています。