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"というのもありますが、今回は省略。