BEAR.Sunday meetup #2に行ってきました

何と、前回の記事の日付が2年前という恐ろしい状況!…止まった時計を再び動かすべく、はてなダイアリーに戻って参りました。

という事で、BEAR.Sunday meetup #2にお邪魔させて頂いてきたので、ご報告を。

会場はとってもオシャレなHubTokyoさん。WebSterさんの提供で、食べ物・飲み物に困らずに非常にリラックスした状況で、なるほど、これが勉強会ではなくmeetupなんだと実感しました。

全員が自己紹介も兼ねてLT必須という事で、何の話をしようかと思ったんですが、ちょうどTDDフレームワークWaltzを作っていて、DocTestが動く状態になったところだったので、その紹介をさせて頂きました。

http://www.slideshare.net/stellaqua/bea-rmeetup2-lt

他の方が時間節約の為に1台のPCに資料をまとめてプレゼンしている中、どうしてもDemoをやりたい、というわがままで自分のPCでLTさせて頂きました。頑張ってビジュアルにこだわったテスト結果の楽譜表示は、特に女性陣には好評だったようで、満足しとりますw Waltzのもっと深い話は、またいつかどこかで…。

自分のLTはともかくとして、みなさん3分間という短い時間なのに(自分も含めてオーバーしてた人多数ではありましたがw)、とっても濃い内容で素敵でした。

また、メインセッションの方も、@koriymさん、@mackstarさん、果ては、NateさんのAngularJSの話が直に聞けるという何とも贅沢なmeetupでございました。特に、@koriymさんのプレゼンは、「いよいよBEARの世界進出が始まる…!?」と思いながら、本当にワクワクしながら聞いていました。

自分もBEARを応援し続けてきた一人として、このワクワク感をもっと世に広めるべく、自分にできる事を進めていこうと心新たにしたところで、筆を置きたいと思います。

BEARで始めるWebアプリケーション開発 その12「Ajaxアクセスを試してみる」

現在、今まで作ったWebサービス達をBEARベースに移行しようとしていまして、どうせならAjaxも使いたいなと思って、BEARでのAjax周りの学習をしていました。そんな訳で、今回はBEARでのAjaxアクセスに関するお話です。

今回は例として、Googleの検索APIを叩いて検索結果を返す処理をAjaxで実現するアプリケーションを作ってみたいと思います。*1

事前準備

BEARではJavaScript周りはjQueryベースのパッケージスクリプトが用意されていて、Ajaxでサーバ側のBEARアプリケーションとデータをやり取りする事ができるようになっています。

init-appした直後はその辺りのJavaScriptファイルは用意されないので、PEARインストールディレクトリからコピペして用意します。

$ mkdir $BEAR_DIR/htdocs/js
$ cp -ir $PEAR_DIR/BEAR/data/htdocs/bear $BEAR_DIR/htdocs/js/

$PEAR_DIRはPEARのインストールディレクトリ、$BEAR_DIRはinit-appした時のディレクト*2です。コピー先はhtdocsの下ならどこでもいいんですが、今回は、"htdocs/js/bear"というディレクトリの下に置くようにしました。

テンプレートを作成する

テンプレートから作成すると見通しが良いと思うので、まずはテンプレートから作成します。"App/views/pages/ajaxindex.tpl"というファイルを以下のような内容で作成します。

<html>
<head>
<script type="text/javascript" src="/js/bear/jquery.bear.min.js?{appinfo version}"></script>
<script type="text/javascript" src="/js/app.js?{appinfo version}"></script>
</head>

<body>
<h2>Ajaxテスト</h2>
<form id="ajaxform">
    <input type="text" name="keyword" size="20">
</form>
{a rel="ajax" href="./ajax.php" click="post"}検索{/a}
<dl>
    <dt>結果</dt>
    <dd id="response"></dd>
    <dd id="result"></dd>
</dl>
</body>
</html>

ポイントの一つ目は、"jquery.bear.min.js"というファイルを読み込んでいる点ですね。このファイルには、jQuery本体とBEARのJavaScript機能がパッケージされているので、Ajax処理をするには、何はなくともこのファイルが必須です。

次に、"app.js"というファイルを読み込んでいますが、これについては後述します。

続いてのポイントは、"{a}"というBEARの独自タグです。これは、HTMLのaタグの上位互換性を持っていて、いくつか拡張機能が使えるようになっています。特にclick属性は、JavaScriptの"onClick"イベントのような感覚でサーバ側アプリの処理を呼び出せる感じで、なかなか面白い機能だと思います。*3

ここでは、「Ajaxアクセスで、"ajax.php"の"post"クリックハンドラを呼び出す」というリンクを定義しています。

後は、Ajaxアクセスの結果を格納するボックスをIDを付与して置いているだけですね。

このテンプレートに対するページファイルは、単純に表示するだけのものなので、以下のように中身が何も無いクラスファイルを作っておけばオッケーですね。

<?php
require_once 'App.php';

class Page_Ajaxindex extends App_Page
{
}
App_Main::run('Page_Ajaxindex');
?>

これを、"App/htdocs/ajaxindex.php"として作成しておきます。

Ajaxで呼び出されるページファイルを作成する

次に、Ajaxアクセスで呼び出されるページファイルを作成します。"htdocs/ajax.php"というファイルを以下の内容で作成します。

<?php
require_once 'App.php';

class Page_Ajax extends App_Page
{
    public function onInject()
        $this->_ajax = BEAR::dependency('BEAR_Page_Ajax');
        $this->injectAjaxRequest();
    }

    public function onClickPost ( $args )
    {
        $keyword = $args['form']['ajaxform']['keyword'];
        $result = $this->_resource->read($params)->getBody();
        if ( is_null($responses = json_decode($result[0], true)) === false ) {
            if ( $responses['responseStatus'] === 200 ) {
                $response = 'OK';
            } else {
                $response = $responses['responseDetails'];
            }
        } else {
            $response = 'API取得エラー';
        }
        $this->_ajax->addAjax('html', array('response' => $response));
        $this->_ajax->addAjax('js', array('display' => $result[0]));
    }

    public function onOutput()
    {
        $this->output('ajax');
    }
}
App_Main::run('Page_Ajax');
?>

ここはポイントがたくさんですね。順を追って見ていきたいと思います。

まず、onInject()でBEARのAjaxコンポーネントの準備と、Ajaxアクセスのリクエストパラメータ受け取りの処理をしています。

次に、onClickPost()で、テンプレートで書いた{a}タグがクリックされた時の処理を書いています。Ajaxアクセスした時のパラメータは$argsに自動的に格納されて、フォームの内容は$args['form']で受け取る事ができます。フォームに付けたID毎に連想配列として格納されるので、複数のフォームを作ってもちゃんと値を区別して受け取る事ができます。

受け取ったキーワードを使ってGoogle検索APIにアクセスした結果の内、処理結果を$response、検索結果を$resultに入れています。

この結果を、addAjax()というメソッドで返していますが、"html"と"js"という2種類の方法で返すようにしています。*4

"html"で返した場合は、HTMLの中の該当するIDの場所にBEARが自動的に挿入してくれます。また、"js"の場合は、引数として値を渡しつつ、自分で定義したJavaScriptメソッドを呼び出す事ができます。今回の場合は、Google検索APIの処理結果のJSONを引数にして、"display"というメソッドを呼び出すようにしています。

アプリケーション独自のJavaScriptを定義する

続いて、Ajax呼び出し後に結果を格納したりする処理を作成します。"htdocs/js/app.js"というファイルを以下の内容で作成します。

(function($) {
    $.app = {
        display : function(result) {
            eval('var results=' + result);
            var html = '<ul>';
            $.each(results.responseData.results, function(i, item){
                html += '<li>' + item.titleNoFormatting + '</li>';
            });
            html += '</ul>';
            $("#result").html(html).show('slow');
        }
    }
})($);

$(document).ready( function() {
    // rel=ajaxとなっているAタグをAjaxLink化する。
    $("a[rel^='ajax']").bearAjaxLink({form:true});
});

一つ目のブロックがクリックハンドラ側から呼び出されるメソッドの定義で、JSONをevalして、HTML内に埋め込む処理をしています。

二つ目のブロックはHTMLの読み込み後の初期化処理で、BEARのパッケージの機能を使って、rel属性が"ajax"となっているaタグに対してAjax処理を行うイベントを設定しています。引数で"{form:true}"としておくと、クリックハンドラを呼び出す時に、自動的にHTML内のフォームの内容をパラメータとして渡すようになります。

Ajaxアプリケーションの完成!

ここまでで、HTMLからのAjaxでの値の送信、サーバでの処理結果の受け取りと表示、という基本的な部分について作成できました。

キャプチャした時には、init-appした時に作成されるデフォルトのCSSを適用したものを使ったので、今回の記事のテンプレートファイルだとこの画像の通りにはなりませんが、まぁイメージ映像という事で…。

ちなみに、画像だと伝わりませんが、結果を表示する時にjQueryのエフェクトを入れているので、ボワッという感じで表示されます。jQuery使うと、ちょっとしたエフェクトが簡単に入れられてなかなか良いですな。

雑感

という訳で、AjaxなアプリケーションをBEARで作ってみましたが、「参考までに」と思ってCakePHPAjaxヘルパーの使い方をちょっとだけググって見てみたら、基本的なやり方は同じような感じっぽい印象でした。

ただBEARの場合、「aタグにイベントを定義して、そのクリックハンドラを"サーバ側の"ページに定義する」というメタファーになっているところが個人的に気にいっていたりします。

次回は?

次回は、テンプレート周りの話にしようかなという予定です。

*1:実際には、Google検索APIは直接JavaScriptから呼び出して使った方が断然便利なので、わざわざAjaxアクセスしてサーバ側でAPI叩くなんてのは全くスマートとは言えませんが、まぁ、サンプルとしてこんなもんで…。

*2:"bear show-app"で確認する事ができます。

*3:{a}タグの詳細は、本家Wikiクリックハンドラのページ参照。

*4:もう一つ"val"というのもありますが、今回は省略。

BEARで始めるWebアプリケーション開発 その11「リソースをWebAPIとして外部に公開する」

今回は、リソースをWebAPI*1として外部に公開する為の方法について学びます。

リソースをWebAPIとして提供する場合、外部からはGETのみで、かつ返す表現がXMLJSONの場合は非常に簡単で、PageのonOutputハンドラでdisplayメソッドを使っていたところを、outputメソッドに変えるだけです。

<?php
    public function onOutput()
    {
        $this->output('xml');
        //$this->output('json');
    }
?>

BEARでは、リソースが値を返す時点では、表現を伴わない単なるデータ構造になっているので*2、状況に応じた表現の変更を極めて容易に行う事ができます。

この、表現形式を決めるアウトプットフィルタは自分で作る事もできて、"App/Resource/output"というディレクトリを作って、その中に"{形式名}.php"というファイル名でPHPファイルを作成すると、それを利用する事ができるようになります。

デフォルトで用意されているアウトプットフィルタは、PEARディレクトリ配下の"BEAR/Resource/output"の中にあります。デフォルトのアウトプットフィルタの動作を変えたい場合は、ここから"App/Resource/output"にコピーしてきて中身を書き換えてやれば、そちらが優先して使われるようになります。

今回は試しに、何らかの画像生成を行ってIMAGICKオブジェクトを返すリソースを作った時に、それを画像ファイルとしてHTTP出力するアウトプットフィルタを作ってみました。

<?php
/**
 * イメージ出力
 *
 * @param array $values  出力データ
 * @param array $options オプション(type:gif|jpeg|jpg|png , expire:有効期限)
 *
 * @return BEAR_Ro
 */
function outputImage($values, array $options)
{
    $ro = BEAR::factory('BEAR_Ro');
    $type = ( isset($options['type']) === true ) ? $options['type'] : 'png';
    switch ( $type ) {
        case 'gif':
            $mime = 'image/gif';
            break;
        case 'jpeg':
        case 'jpg':
            $mime = 'image/jpeg';
            break;
        case 'png':
            $mime = 'image/png';
            break;
    }
    $expire = ( isset($options['expire']) === true && $options['expire'] > 0 )
        ? $options['expire'] : 0;
    $headers = array();
    $headers['X-BEAR-Output: IMAGE'] = 'Content-Type: '.$mime;
    $headers[] = 'Expires: '.$expire;
    $headers[] = 'Last-Modified: '.gmdate('D, d M Y H:i:s ', time()).' GMT';
    $headers[] = 'Cache-Control: public';
    $headers[] = 'Pragma: ';
    $ro->setHeaders($headers);
    $ro->setBody(array_shift($values));
    return $ro;
}
?>

これを、"App/Resource/output/image.php"として作成しておいて、Pageファイルのアウトプットフィルタを以下のようにすると画像データを返すようになるので、imgタグのsrcとかで使えるようになります。

<?php
    public function onOutput()
    {
        $this->output('image', array('type' => 'png'));
    }
?>

今回は、リソース側で画像生成するような場合の想定でしたが、「リソース自体は普通に連想配列を返すけど、出力する時にその情報を利用して画像生成してHTTP出力する」*3なんていうアウトプットフィルタも簡単に作れる事が分かるかと思います。

次回は?

今回は実は元々、外部からリソースのCRUD操作を行えるような、RESTfulWebAPI用Page作成にしようと思っていたんですが、現状、PUTやDELETEも含めた外部向けWebAPIを作る予定は無かったし、むしろアウトプットフィルタの方が使いどころが多いかなと思って、アウトプットフィルタの話にしました。

次回の内容はまだ決めていないのですが、イベント駆動の辺りかAjaxか、そんな辺りの話にしようと思います。

*1:予告では"RESTfulWebサービス"という言い方をしましたが、"Webを支える技術"での使い分けに倣って、"WebAPI"としました。

*2:"リソース自体は表現を決めない"という特徴がある故に、リソース自体で考えると対人用とか対機械用とかの区別が無いモノと言えるので、"Webを支える技術"で言うところの「WebサービスとWeb APIを分けて考えない」という事を実現できているのではないかと思います。

*3:具体例で言うと、はてブAPIみたいな感じで、リソースは数値データだけを返すようにしておいて、アウトプットフィルタで画像生成するようにするイメージ。

BEARで始めるWebアプリケーション開発 その10「アスペクト指向プログラミングしてみる」

今回は、BEARの特徴の内の一つである"アスペクト指向"について学びます。概要の説明は例によって本家Wikiに譲ります。

Google Code Archive - Long-term storage for Google Code Project Hosting.

アスペクト指向してみる

BEARの場合AOPは、phpdoc形式のコメントに記述する、アノテーションにより実現されていますね。

例えば、DBアクセスのあるリソースでトランザクションがかかるようにしたい場合、該当のメソッドで以下のようにコメントに書いておくだけという、何ともお手軽な感じですね。

<?php
class App_Ro_Entry extends App_Ro
{
    /**
     * リソース作成
     *
     * @aspect around App_Aspect_Transaction
     */
    public function onCreate($values)
    {
        $values['created_at'] = _BEAR_DATETIME; //現在時刻
        $result = $this->_query->insert($values);
        if ($this->_query->isError($result)) {
            throw $this->_exception('投稿できませんでした');
        }
    }
}
?>

Transactionアドバイスに関してはinit-appした時に自動的に作成されるので、わざわざ自分でアドバイスを作成する必要もなく、トランザクション処理を簡単に行う事ができます。

AOPはうまく利用すると、コードを書く量を劇的に減らす事ができますね。

アドバイスの実行順序

アドバイスは一つのメソッドに複数指定した場合、before→around→afterの順で実行され、beforeやafterが複数ある場合は、before・after毎に指定した順で実行されるようです。

<?php
/**
  * @aspect after App_Aspect_After1
  * @aspect before App_Aspect_Before2
  * @aspect after App_Aspect_After2
  * @aspect around App_Aspect_Around1
  * @aspect before App_Aspect_Before1
  * @aspect around App_Aspect_Around2
  */
?>

こんな書き方をすると、"Before2→Before1→Around1→After1→After2"という順で実行されます。

aroundに関しては複数記述した場合は、最初に記述したものだけが実行される仕様のようです。(上記例の場合、Around2は実行されない。)

アノテーション

コメント部分に書く事ができるアノテーションは、今のところAOPの@aspectと、メソッドの必須項目を定義できる@requiredが使えます。

とりあえずは@requiredだけあれば困らなさそうですが、リソースに対する入力値の事前チェックなんかをやりたいと思ったら、@aspectでチェック用のアドバイスを作っちゃえば良さそうですね。

という訳で、AOPに関してはさらっと見てみただけですが、実際には周到に最初から準備するというよりは、リソースをいくつも作っていく内に、よく出てくる処理をアドバイスとして切り出す…というような形で使っていくのが良さそうな感じがしました。

また、アノテーション機構は、実際のコードの近くに定義が来るので、コードの見通しが良くなってよいですね。DocTestも併用すれば、テストもコメント部分に書けて、そのメソッドに関する情報が一箇所に集まる感じで非常に素晴らしいですね。

次回は?

次回は、BEARでのRESTfulWebサービスの提供の方法について、またはその前段としてDIに関して書こうかなと思っています。

BEARで始めるWebアプリケーション開発 その9「フォーム関連機能を学んでみる」

今回はBEARでのフォーム関連の機能を学習します。

…とは言ってもBEARの場合、フォーム関連はPEAR::QuickFormのラッパー的な感じなので、フォームの構築方法自体はQuickFormの方を学ぶ必要がありそうです。なので、QuickFormの細かい使い方はひとまず置いておいて、今回はBEARでのフォームの使い方を学んでいく事にしたいと思います。

フォーム構築の方法

基本的な使い方は本家Wikiデモページを見ると非常によく分かるので、そちらを参照しながらフォーム構築方法を見ていきましょう。

フォームは、一つのまとまった単位(formタグで括られる範囲)毎にクラスファイルを作成して、その中でそのフォームに関する設定・処理を全て書いていくというスタイルが推奨されるようです。

という事で、よくある"入力→確認→完了"という画面遷移の場合のフォームクラスのサンプルを見ていきます。

http://code.google.com/p/bear-demo/source/browse/trunk/App/Form/Preview.php

基本的な流れとしては、フォームの状況(初期状態/確認画面/入力修正)に応じたonInjectメソッドを用意しておいて、そこで各状況毎の設定を行って、実際のフォーム部品の内容は、buildメソッドで定義する感じですね。

バリデーションルールもこのクラスの中で定義するので、このフォームに関する設定の全てが一つのクラスファイルに集まっていて、非常に見通しが良くて素晴らしいですね。

続いて、このフォームを利用するページファイルの方も見てみます。

http://code.google.com/p/bear-demo/source/browse/trunk/htdocs/form/preview/index.php

各メソッドの処理は、

onInjectメソッド
フォームの状況切り替え
onInitメソッド
DI経由でフォームクラスのbuildメソッド呼び出し
onActionメソッド
実際にsubmitボタンが押された場合の処理

という感じですね。

BEARは処理の役割分担が明確なので、一つのメソッドにダラダラ書いていく感じにならなくて、スッキリ書けて良いですね。

これだけで、Smartyテンプレート内で"{$form}"とだけ書けば、入力画面・確認画面の区別無く、必要な情報が全てレンダリングされた状態でフォームを表示する事ができます。

セキュリティに関しても、CSRFの防止や二重投稿の防止も自動的に考慮されるようになるので、難しい事を何も考えなくてもフォームでの値入力UIが作成できちゃいますね。

フォーム関連で、特に"入力→確認→完了"の画面遷移を伴う処理はとかく面倒な事が多いですが、BEARでは非常に簡単にフォーム処理ができる事が分かりました。

とは言え"簡単"という事は、QuickFormが自動的に処理している部分が多い訳で、QuickFormのデフォルトに乗っかる事ができる部分が大きければ非常に便利に使えますが、カスタマイズが必要な部分が多かったり、極めて単純なフォームの場合は、むしろフォームは自前で用意するようにした方がよいのかもしれないですね。

とりあえず、今のところQuickFormを使った方がよい程のフォームは扱わないので、今回はBEARでのフォームの扱い方をざっくり学んだ…というところまでにしておこうと思います。

次回は?

次回はアノテーションアスペクト指向の辺りを学習しようと思います。

BEARで始めるWebアプリケーション開発 その8「リンクを使ってリソース同士を接続する」

今回は、リソース同士を接続する事ができる"リンク"の機能について学習します。

今回の題材

今までは"逆さ語"を題材としてきたんですが、現状の逆さ語の仕様だとリソース同士がリンクしていなくて、題材としてはよろしくないので、他の題材を探す事にしました。

という訳で色々考えた末、リンク機能の面白さが分かるようなものがいいかなという事で、はてなブックマークの人気エントリを題材にしてみる事にしました。

はてなブックマークの人気エントリは以下のような形で、特定のURLを含むページの人気エントリをRSSで取得する事ができます。

http://b.hatena.ne.jp/entrylist?sort=count&url=http://d.hatena.ne.jp/stellaqua/&mode=rss

ただ、このRSSにはブックマークコメントは入っていないので、コメントを見る為には該当のブックマークページを見に行かなくてはいけません。

一方、特定のページに付けられたブックマークコメントは、以下のようなURLでRSSを取得する事ができます。

http://b.hatena.ne.jp/entry/rss/http://d.hatena.ne.jp/stellaqua/20090305/1236222223

という事は、人気エントリのリソースにブックマークコメントのリソースをリンクしてやれば、人気エントリのブックマークコメントが一気に取れるんじゃね?…って事で、実際にやってみましょう。

人気エントリのリソースを作る

App/Ro/bookmarks.phpというファイル名にして、onReadメソッドを以下のようにしました。

<?php
    public function onRead($values)
    {
        $resource = BEAR::dependency('BEAR_Resource');
        $uri = 'http://b.hatena.ne.jp/entrylist?sort=count&url=http://d.hatena.ne.jp/stellaqua/&mode=rss';
        $options['cache']['life'] = 60 * 60 * 3;
        $params = array('uri' => $uri, 'options' => $options);
        $result = $resource->read($params)->getBody();
        return $result;
    }
?>

毎回RSSを取得しにいくと重たくなってしまうので、今回は3時間のキャッシュを保存する設定を追加しました。

BEARはこのように、リソース、ページ、テンプレート変数など、様々な場所でいとも簡単にキャッシュを利かせる事ができるので、多くのAPIを使うようなマッシュアップサイトでも、それなりな負荷に耐えられるWebアプリケーションを簡単に作る事ができそうですね。

ブックマークコメントのリソースを作る

続いてブックマークコメントのリソースを作ります。App/Ro/comments.phpというファイル名にして、onReadメソッドを以下のようにしました。

<?php
    public function onRead($values)
    {
        $resource = BEAR::dependency('BEAR_Resource');
        $uri = 'http://b.hatena.ne.jp/entry/rss/'.$values['link'];
        $options['cache']['life'] = 60 * 60 * 3;
        $params = array('uri' => $uri, 'options' => $options);
        $results = $resource->read($params)->getBody();
        return $results;
    }
?>

$values['link']には、bookmarksリソースからリンク機能を介してブックマーク先のURLが渡ってくるので、それを使ってブックマークコメントを取得するURLを構築しています。

人気エントリリソースからブックマークコメントリソースへリンクを張る

あとはリンク元となるbookmarksリソースのonLinkメソッドに、commentsリソースへのリンク設定を書いてやる事で、リンク機能が使えるようになります。

<?php
    public function onLink ( $values )
    {
        $links['comments'] = array(
                                   'uri' => 'comments',
                                   'values' => array('link' => $values['link']),
                                  );
        return $links;
    }
?>

当然、更に別のリソースへのリンクを書く事もできますし、commentsリソースにonLinkを書けばcommentsリソースから更にリンクする事もできます。

リンク機能を使ってページから情報を取得する

このようにリンク設定を行ったリソースから関連データを取得するのは非常に簡単で、ページから以下のような感じでごっそりと必要な情報を取ってくる事ができます。

<?php
    public function onInit(array $args)
    {
        $uri = 'bookmarks';
        $params = array('uri' => $uri);
        $this->_resource->read($params)->link('comments')->set();
    }
?>

これだけで、きちんと階層構造を持って必要な情報が取ってこれます。あとは、テンプレート側で以下のようにループを回してやれば、はてブ人気エントリのブックマークコメント一覧の完成です。

{foreach from=$bookmarks item="bookmark"}
    <p>{$bookmark.title}</p>
    <ul>
    {foreach from=$bookmark.comments item="comment"}
        <li>{$comment.description|default:''}(id:{$comment.title})</li>
    {/foreach}
    </ul>
{/foreach}

上記テンプレートから若干書き換えた後のものですが、実際に動作させてみた画面は以下の通り。

こんな風に、外部API同士を組み合わせたサーバサイドのマッシュアップが非常に簡単にできるのがBEARの強みだと思います。

もちろん内部リソースとも全く同じ形で組み合わせる事ができるので、外部APIから何かしら情報を取ってきて、それに内部リソースをリンクして付加価値を付けて、Webアプリケーションとして公開…なんて事がお手軽にできそうですね!

次回は?

BEARはフォーム関連の機能は、PEAR::QuickFormが使われているんですが、QuickFormは使った事がなくてあまりよく分かっていないので、次回から何回かはフォーム関連の機能について学習していきたいと思います。

余談

今回、元々は"最新はてブられコメント一覧"が欲しいと思って、はてブを題材にして、その過程で色々調べてて知ったんですが、はてブの特定URL以下のページの最新ブックマーク一覧って、"http://b.hatena.ne.jp/bookmarklist/?url=〜"で取れるんですね。

記事の中で挙げたentrylistだとソート基準が、"今まで1件もブックマークされていないページが初めてブックマークされた日時"になるようで、古いページにブックマークが付けられてもなかなか気付けなかったんですが、これで、はてブられ状況をリアルタイムで追う事ができそうです。

BEARで始めるWebアプリケーション開発 その7「複数のリソースからデータを取得して画面に表示する」

今回は、前回作成したリソースを使って、"逆さ語"の画面に"最近変換した文章"を表示させてみます。

ページに表示するリソースを定義する

と言ってもそんなに難しくもなく、以前作成したページのonInitメソッドにちょこっと追加するだけになります。

<?php
    /**
     * 初期化
     *
     * @return void
     */
    public function onInit(array $args)
    {
        // 文章が与えられていたらsentencesリソースに書き込む
        if ( isset($args['s']) === true ) {
            $values = array('s' => $args['s']);
            $params = array(
                            'uri' => 'sentences',
                            'values' => $values,
                            'options' => array(),
                           );
            $this->_resource->create($params);
        }

        // sentencesリソースから最近変換した文章のリストを取得する
        $params = array('uri' => 'sentences');
        $this->_resource->read($params)->set('history');

        // 文章の変換結果を取得する
        $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);
    }
?>

"ちょこっと"と言いながら、何だかいっぱい増えてしまってますが…。

最初のブロックでは、文章が与えられてページが呼ばれた場合に、文章変換の履歴として、sentencesリソースに書き込んでいます。

真ん中のブロックでは、sentencesにGETリクエストを投げて、最近変換した文章のリストを取得しています。

最後のブロックは以前のまま変更はありません。

これでテンプレートの$historyに最近変換した文章がアサインされるので、後はテンプレート側で適当に見た目を整えてやればオッケーですね。

BEARではリソースに対して、HTTPでアクセスするのと同じ感覚でアクセスできるので、ページからアクセスする場合は、このように必要なリソースアクセスを順番に並べていく感じになります。

今回は利用したリソースが同じアプリ内のものだけでしたが、ここに例えば外部URLのRSSフィードを追加したり、都道府県一覧を定義してあるCSVを読み込んで使ったり、というように、様々な情報を"リソース"という形で簡単に追加していけるという事が分かって頂けるのではないかと思います。

これはかなり強力な仕組みで、例えば「ブログサイトを作ろう」という事で、メインとなる記事の表示・投稿機能なんかをリソースとして作った後に、「コメント機能を追加しよう」とか「ブログパーツを入れよう」とか「twitterの関連つぶやきを載せたいな」とか仕様が増えても、後から非常に簡単に機能を追加する事ができます。*1

これに更に"リンク"の機能を使うと、リソース同士を組み合わせて付加価値を付けた情報を取得したりなんて事ができるようになるので、更にできる事の幅が広がるようになります。

次回は?

という事で、次回は、リソース同士の関連付けを定義する、"リンク"について学習したいと思います。

*1:この辺り、MVCCakePHPとかだと、どういう設計・実装になるのかな…? MVCフレームワークで大きな規模の開発をした事がないので、素朴な疑問です…。