BEARで始めるWebアプリケーション開発 その4「ページを作ってみる 〜そして(一旦は)完成へ〜」

久々にPHP勉強会(第49回)に参加する事にしまして、BEARの布教活動をしてこようかと企む今日この頃、皆様いかがお過ごしでしょうか。(ここまで挨拶)*1

さて、前回までで、DBを使わないようなシンプルなリソースの作り方について学びました。今回は、リソースを利用する側である"ページ"を作成して、実際に動作するWebアプリケーション完成までやっていきたいと思います。

"ページ"の概念

ページに関しては、本家Wikiページの説明の辺りを見ると、概念がよく分かります。

最低限必要なのは、onInject・onInit・onOutputの3つのメソッドで、

  1. onInjectで必要なコンポーネントなどのインジェクトを行う。
  2. onInitでリソースからのデータの読み込みとテンプレートへの値のセットを行う。
  3. onDisplayで実際の出力を行う。

というような流れが基本という感じみたいですね。他のメソッドに関しては必要になった時にまた学習しようと思います。

実際にページを作ってみる

ページ作成は割と簡単そうなので、サンプル作成で学習する過程はすっ飛ばして、前回までで作成したsentenceリソースを使って実際に画面表示を行うページを作ってみました。

ページ名はindexでもいいんですが、index.phpにはデフォルトでサンプル用のコードが既に入っているので、今回はtopというページにしました。サンプルのindex.phpの内容を参考に、"htdocs/top.php"を以下のような内容で作成しました。

<?php
/**
 * @APP@
 *
 * @package Page
 */
require_once 'App.php';

/**
 * Topページ
 *
 * <pre>
 * </pre>
 *
 * @package Page
 * @author  $Author:$
 * @version SVN: Release: $Id:$
 */
class Page_Top extends App_Page
{

    /**
     * インジェクト
     *
     * @return void
     */
    public function onInject()
    {
        parent::onInject();
        $this->injectArg('s', $_GET['s']);
    }

    /**
     * 初期化
     *
     * @return void
     */
    public function onInit(array $args)
    {
        $uri = 'sentence';
        $sentence = ( isset($args['s']) ? $args['s']
                      : 'これはサンプルです' );
        $values = array('s' => $sentence);
        $params = array(
                        'uri' => $uri,
                        'values' => $values,
                        'options' => array(),
                       );
        $this->_resource->read($params)->set('preview');
        $this->set('sentence', $sentence);
    }

    /**
     * 出力
     *
     * @return void
     */
    public function onOutput()
    {
        $this->display();
    }
}
$options = array();
App_Main::run('Page_Top', $options);
?>

以下、簡単に解説。

onInject

まずは、親のonInjectを呼んでいます。これはほとんどおまじないのようなものだと考えても良さそうですね。あとは、クエリパラメータ"s"の値を、ページ引数としてインジェクトしています。

このように、onInjectは、ページで利用するコンポーネントや値を"注入"する役割を担うという事ですね。

$_GETの値をそのまま使っているのは何だか気持ち悪い感じがしますが、フォームを利用した値の受け渡しに関しては、もっとセキュアに行う仕組みが用意されているようなので、それはまた学習する事として、今回はこんな書き方で…。

onInit

onInitで、実際にリソースからデータを読み込んで、テンプレートに値をセットしています。

リソースへのアクセスは、連想配列URIとパラメータとオプションを引数にして、$this->_resourceのメソッドを呼ぶ事で行います。

今回の場合は、"GET /sentence?s={文章}"というリクエストを行っているという事ですね。このリクエストで得られた値を"preview"というテンプレート変数にセットしています。

また、入力された文章も出力画面で表示したいので、"sentence"というテンプレート変数にセットするようにしています。

この辺りの書き方が何とも直観的で気持ちがいいですな。( ̄ー ̄)

onDisplay

onDisplayで、セットされた値を出力します。

デフォルトではテンプレートエンジンとしてSmartyが利用されますが、普通にHTMLで出力するだけでなく色々な形式の出力に対応していて、エクセル形式で出力するなんて事もできるみたいですね。

ページ起動部

ページはドキュメントルート配下にある、実際にアクセスされるファイルなので、BEARの起動部を書いておく必要があります。

今回は特にオプション指定はしていませんが、ここでインジェクタの設定やキャッシュの設定などを行う事ができるようです。その辺の学習もまたその内…。

テンプレートを作成する

テンプレートは、ファイル名の命名規則に従っていれば、自動的にファイルを発見して読み込んでくれます。

今回の場合は、ファイル名の命名規則により"App/views/pages/top.tpl"というファイル名になるので、その名前でテンプレートを記述しました。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
 <title>逆さ語</title>
</head>
<body>

<div id="header">
    <h1>逆さ語</h1>
</div>

<div id="content">
    <dl id="controlbox"><form action="" method="get">
        <dt class="description">変換したい文を入力して下さい(最大50文字)</dt>
        <dd class="inputform">
            <input type="text" name="s" size="50" maxlength="50">
            <input type="submit" value="変換">
        </dd>
    </form></dl>
{if isset($preview)}
    <dl id="preview">
        <dt class="sentence">{$sentence}</dt>
        <dd class="convertedkana">
            逆さ語 ⇒ {$preview.kana}
        </dd>
        <dd class="convertedroman">
            ローマ字 ⇒ {$preview.roman}
        </dd>
    </dl>
{/if}
</div>

</body>
</html>

完成!

これで完成! 何とも、いとも簡単に仕様を満たすWebアプリケーションが完成してしまいました。エラー処理とか、バリデーションとか一切やっていないので、ホントに基本的な部分だけではありますが、後は枝葉の部分なので、徐々に付け足していけばいいだけですね。

とりあえず、ここまでは"1リソース1画面"のWebアプリケーションの例なので、CakePHPなんかのMVCフレームワークでも比較的楽に作れるのではないかと思います。しかし、1画面で複数のリソースを扱うようになると、なかなかそうもいかないのではないかなと。

次回は?

そんな訳で、ここからがリソース指向たるBEARの本領発揮!という事で、次回から、DBを扱うリソースを一つ追加して、1画面で複数のリソースを扱うようなWebアプリケーションの作成に挑んでみたいと思います。

*1:今回の連載をベースに紹介プレゼンしてもいいかなとも考えたんですが、連載がそこまで進められていないので、それはまたの機会に…。