PHP のフレームワーク: 第 4 回 Ajax のサポート

Zend Framework、CakePHP、そして symfony はネイティブ・コードとサードパーティー・ライブラリーをどう処理するか

初期のバージョンの PHP に対する一般的な批判の中に、PHP が MVC (Model-View-Controller) スタイルのアーキテクチャーをサポートしていないというものがありました。現在では、開発者は数多くの PHP フレームワークの中から好きなものを選択することができます。この「PHP のフレームワーク」シリーズは、広く使われている 3 つの PHP フレームワークである、Zend、symfony、そして CakePHP を取り上げます。そして、この 3 つの各フレームワークを使ってサンプル・アプリケーションを作成し、また拡張しながら、各フレームワークの類似点と相違点を検証します。このシリーズの第 1 回ではこのシリーズ全体の概要を示し、このシリーズを進めていく上で必要なことを行いました。第 2 回では 3 つの各フレームワークを使ってサンプル・アプリケーションを作成しました。第 3 回では、このサンプル・アプリケーションを拡張し、またフレームワークのルールから外れた場合の処理について調べました。今回は、各フレームワークで Ajax がどのようにサポートされているかについて調べます。

Duane O'Brien, PHP developer, 自由职业者

Duane O'Brien はゲーム Oregon Trail がテキストのみで構成されていた頃から、万能な技術者として活躍しています。彼の好きな食べ物は寿司です。彼はまだ月に行ったことがありません。



2008年 2月 12日

このシリーズについて

このシリーズは、フレームワークを使いたいと思いながら、現在利用可能なフレームワークの詳細を検討する機会がなかった PHP 開発者のためのものです。このシリーズでは、この 3 つのフレームワークが選ばれた理由と各フレームワークのインストール方法を検証します。また、この 3 つの各フレームワークでテスト・アプリケーションを拡張して適切に扱えるようにします。そう聞くと膨大な作業に思えるかもしれませんが、心配はありません。必要な情報は理解しやすいブロックに分かれています。

第 1 回では、まずこのシリーズ全体の概要を示し、検証対象となるフレームワークを紹介するとともに、そのインストール方法を説明しています。さらに、これから作成する最初のテスト・アプリケーションについても説明しています。

第 2 回では、3 つの各フレームワークを使ってサンプル・アプリケーションを作成するための手順を、それぞれの類似点と相違点に焦点を当てながら説明しています。

第 3 回では、まずテスト・アプリケーションを拡張し、次にフレームワークのルールから外れた場合の処理を扱います。どのフレームワークも、それらのフレームワークが本来目的とする作業を実行する場合は適切に動作します。しかしどのプロジェクトでも、そのフレームワークでは想定されていない作業をしなければならない場合が必ずあります。第 3 回では、そうした例を説明しています。

第 4 回では Ajax のサポートに主な焦点を当て、ネイティブ・コードとサードパーティーのライブラリーを使って Ajax を利用する方法を検証します。具体的には、各フレームワークがどう振る舞い、よく使われる特定のライブラリーをどう扱うかを検証します。

第 5 回では、フレームワークの外部での作業について説明します。1 つのタスク (毎晩更新されるスクリプト) を考え、このタスクを完了するためのプロセスを各フレームワークについて検証します。


この記事について

この記事では、それぞれのフレームワークが Ajax をどのようにサポートしているかについて説明します。少し実地体験ができるように、各フレームワークの Ajax サポートを使って Blahg を拡張し、投稿に対する簡単な評価を追加します。

この記事を読むためには第 1 回第 2 回第 3 回を読み終えておく必要があります。これまでの 3 回では、各フレームワークのインストールと要件、最初のアプリケーション作成と拡張について説明してあります。まだ読んでいない人は今すぐに読んでください。


Zend Framework での Ajax

現時点では、Zend Framework には Ajax のサポートは組み込まれていません。Zend Framework には、アプリケーションに Ajax を追加する際に役に立つライブラリーがいくつかあります (Zend_Json や Zend_XmlRpc など)。また Zend Framework には、Flickr など人気のあるアプリケーションの既存の Web API を利用できるライブラリーもいくつか含まれています。しかし、アプリケーションに Zend を使って Ajax を追加したい場合には、自分の手で追加する必要があります。

これによる不便な点は、望む動作をさせるためにはコードを作成しなければならないことです。逆に良い点は、Ajax 関連の特定のライブラリーに統合されていないおかげで、自分の好みのライブラリーを選択することができ (あるいはまったくライブラリーを使わないという選択ができ)、目的に合った自由な方法で Ajax 機能を作成できることです。


symfony での Ajax

symfony フレームワークには Prototype ライブラリーと script.aculo.us ライブラリーが同梱されています。第 2 回では、プロジェクトを初期化し、Web ディレクトリーの内容を /column/protected/symfony にコピーした際、これらのライブラリーのコピーをアプリケーションで使用できる場所に移動しました。(これは確認しておく必要があります。このコピーはディレクトリー /column/htdocs/symfony/sf/prototype/js/ にあるはずです。)

symfony は Prototype を組み込むことで、いくつかのヘルパー関数を提供することができ、Blahg に Ajax を追加するために作成するコードの量を削減することができます。しかしこれは裏返すと、Prototype 以外の何かを使おうとすると、すべてを自分の手でしなければならないということです。


CakePHP での Ajax

CakePHP は Prototype ライブラリーと script.aculo.us ライブラリーを組み込むことができます。ライブラリーを使用したい場合には、そのライブラリーをダウンロードする必要があります (ダウンロードしたライブラリーは /column/htdocs/cakephp/js の中に置きます)。Ajax ヘルパー関数を使うために必要なものは、実際には Prototype ライブラリーのみです。script.aculo.us ライブラリーは見栄えを良くするためのものです。

CakePHP は symfony の場合と同じく Prototype を組み込むことで、Blahg の Ajax 機能を作成する際の作業が少し楽になります。しかし同様に裏返すと、Prototype 以外の何かを使おうとすると、すべてを自分でしなければならず、Ajax ヘルパー関数は役に立ちません。

注意: もし皆さんの好みのライブラリーが JQuery であるなら、CakePHP の JavaScript ヘルパー関数を使うと便利です。これを適切に使うと非常にスマートなコードを作成できますが、それに関してはこの記事では取り上げません。


データベースを設定する

まず、投稿に対する評価を保管するテーブルを作成します。同じ SQL を使って、このテーブルを 3 つのデータベースそれぞれの中に作成します。

リスト 1. 投稿に対する評価を保管するテーブルを作成する
CREATE TABLE 'ranks' ( 
'id' INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
'post_id' INT( 10 ) NOT NULL ,
'rank' INT( 10 ) NOT NULL 
) ENGINE = MYISAM ;

注意: 投稿に対する評価を保管するために、まったく新しいテーブルが必要なわけではありません。modified 列の更新方法を変更すれば、posts テーブルに列を追加して評価を保管することもできます。誰かが投稿に対する評価を行うたびに投稿データを変更するのは避けたいですが、Blahg の設計では、MySQL またはフレームワークのいずれかがこの対処を行ってくれます。また投稿に対する評価に関して、例えば、送信された評価の件数を保管したり、最後に投稿の評価が行われた日時を保管したりするといった、他のことも行いたい場合は、評価を評価専用のテーブルに保管する方が適切になってきます。


Zend での Blahg に投稿に対する評価を追加する

Ajax リクエストを処理するために何を使用するかを決める必要があります。おそらくそれほど苦労せずに独自のソリューションを作成できると思いますが、この記事では各フレームワークは Prototype ライブラリーを使います (「参考文献」を参照)。そのため、このライブラリーを保持するためのディレクトリーを作成する必要があります。このディレクトリーはブラウザーからアクセスできる必要があります (例えば /column/htdocs/zend/scripts/ など。コード・アーカイブではこのディレクトリーを使用しています)。

ここでは Ranks.php という基本的な評価モデルを作成する必要があります。このモデルは投稿とコメントで行った場合と同じように、単なるモデル・シェルでなければなりません。そしてもちろん、評価コントローラーも作成する必要があります。評価に対するビューは作成しません。単純にコントローラーが評価を含んだリクエストの結果をエコー出力します。ここでは 2 つのアクションが必要です。readAction は投稿の評価を調べ、そして writeAction は送信された評価を取り込み、テーブルの中にその投稿に対する行があるかどうかを調べます。もしその行があれば評価は新しい値を使って更新され、ない場合はその投稿用の新しい行が評価とともに挿入されます。どちらの場合も新しい評価が出力されるため、ビューでの評価を更新することができます。これらはどれも非常に単純であり、そのコードがコード・アーカイブに含まれています。今度はビューにAjax を追加する必要があります。

ここでは評価専用のビューを追加しないことを思い出してください。しかし Ajax コードを含むように、投稿を読むためのビューを変更する必要があります。ファイル /column/protected/zend/views/scripts/post/read.php を開き、ここですべての作業を行います。まず、先頭で Prototype ライブラリーを組み込む必要があります ( <script type="text/javascript" src="/zend/scripts/prototype.js"></script>)。

JavaScript を作成する前に、他の必要な部分を用意します。現在の評価を示す何かが必要です。評価の中では、送信されたリクエストに基づいて評価の値を更新できるように、設定 ID を持つ span が必要です。投稿の下には、おそらく <h4>Rank: <span id="rank"></span></h4> のようなものが必要です。

次に、その投稿を好むか好まないかを示すためにユーザーがクリックできる、1 対のボタンが必要です (リンクでも構いません)。これらのボタンに気の利いた独自の名前を付け、評価の下に配置します (<input type='button' onclick='rankUp();' value='Hot' /> or <input type='button' onclick='rankDown()' value='Not' />)。

Prototype が隠し入力フィールド post_id を容易に利用できるように、このフィールドの ID が post_id であることを確認します。

そして最後に、現在の評価を取得するための onLoad イベントを本体に追加します (<body onload='fetchRank();'>)。

当然のことですが、3 つの JavaScript 関数 (rankUprankDownfetchRank) を作成する必要があります。これらの関数が実際の Ajax リクエストを実行します。これらの関数は非常に単純であり、他のフレームワークでもほとんど同じようになるはずです。これらの関数をヘッダーの <script> 部分に配置します。

リスト 2. 3 つの JavaScript 関数
        function fetchRank() {
                var ajax = new Ajax.Request(
                        '/zend/rank/read',
                        {
                                method : 'get',
                                parameters : {'post_id' : $('post_id').value},
                                onComplete: parseRank
                        }
                );
        }
        function rankUp() {
                var ajax = new Ajax.Request(
                        '/zend/rank/write',
                        {
                            method : 'get',
                            parameters : {'post_id' : $('post_id').value, 'rank' : '1'},
                            onComplete: parseRank
                        }
                );
        }
        function rankDown() {
                var ajax = new Ajax.Request(
                        '/zend/rank/write',
                        {
                           method : 'get',
                           parameters : {'post_id' : $('post_id').value, 'rank' : '-1'},
                           onComplete: parseRank
                        }
                );
        }

各関数の終了時に parseRank が呼び出されていることに気が付いたことと思います。この関数は、とにかく Ajax リクエストに対するレスポンスをどんなレスポンスでも取得し、それを先ほど作成した評価の span の中に配置します。

リスト 3. parseRank 関数を呼び出す
        function parseRank(trans) {
                $('rank').innerHTML = trans.responseText;
        }

こうしたすべての変更を行うか、あるいはコード・アーカイブからインポートすると、Blahg の中の投稿を読むことができ、そして投稿に対する評価を行えるはずです。さらには、いんちきをしてその評価を何倍も高くすることさえできます。さて、これが Zend で投稿に対する評価を行う方法でした。では同じことを symfony で行うにはどうするのでしょう。

注意: 以上の作業は、Ajax.Request ではなく Ajax.Updater を使って行った方がおそらく適切だったことでしょう。Ajax が始めての人は、それをリファクタリングしてみてください。


symfony での Blahg に投稿に対する評価を追加する

symfony で投稿に対する評価を追加するためには、まず schema.yml (/column/protected/sf_column/config の中にあるはずです) から始め、そして ranks テーブルを定義します。

リスト 4. symfony で投稿に対する評価を追加する
  ranks :
    _attributes: {phpName: Rank }
    id:
    post_id:
    rank:    integer

ranks はスペース 2 つ分インデントし、フィールド定義はスペース 4 つ分インデントすることを忘れないでください。

次は何をするのでしょう。Propel モデルを作成し、キャッシュをクリアーします。/column/protected/sf_column (アプリケーションのルート) ディレクトリーの symfony コマンドを思い出してください。

リスト 5. Propel モデルを作成し、キャッシュをクリアーする
php /column/src/symfony/data/bin/symfony propel-build-model

php /column/src/symfony/data/bin/symfony clear-cache

これらのコマンドを実行すると、/column/protected/sf_column/lib/model ディレクトリーに Rank.php ファイルと RankPeer.php ファイルができているはずです。では早速、rank モジュールに init コマンドを実行します (php /column/src/symfony/data/bin/symfony init-module blahg rank)。

評価のアクション・クラス (/column/protected/sf_column/apps/blahg/modules/rank/actions/actions.class.php) には 2 つのアクション (executeReadexecuteWrite) が含まれているはずです。評価の読み取りまたは更新が行われたら、評価をエコー出力し、各アクションの最後で exit を呼び出します (これによって symfony は、ここでは作成する必要のない、関連のビュー・テンプレートを探さなくなります)。これらのアクションがどのように作成されているかはコード・アーカイブを見てください。

最後に、投稿の readSuccess テンプレート (/column/protected/sf_column/apps/blahg/modules/post/templates/readSuccess.php) を更新し、symfony の JavaScript ヘルパーを使えるように、またいくつかの Ajax リンクを含むようにする必要があります。まず、ファイルの先頭に <?php use_helper('Javascript') ?> という行を追加します。この行によって Prototype ライブラリーが組み込まれることになり、さまざまな Ajax ヘルパー関数にアクセスできるようになります。そうしたヘルパー関数の 1 つを使って、最初の評価をロードする呼び出しと、評価送信用のいくつかのリンクを作成します。現在の評価を表示する span を追加することを忘れないでください。

リスト 6. 最初の評価をロードする呼び出しを作成する
<h4>Rank: <span id="rank"></span></h4>
<?php echo javascript_tag(remote_function(array('update' => 'rank', 
                                   'url' => 'rank/read?post_id=' . $id))) ?>
<?php echo link_to_remote('Hot', array('update' => 'rank', 
                    'url' => 'rank/write?post_id=' . $id . '&rank=1')) ?> or
<?php echo link_to_remote('Not', array('update' => 'rank', 
                       'url' => 'rank/write?post_id=' . $id . '&rank=-1')) ?>

必要なことはこれだけです。あるいは別の言い方をすると、実際に JavaScript で何も作成する必要はありません。symfony フレームワークのヘルパー関数が代わりに作成してくれたのです。私に言っていることを信じられませんか? すべてをセットアップし (あるいはコード・アーカイブからコードをインストールし)、symfony バージョンの Blahg で投稿を読んでください。そしてソースを表示してみてください。そこに見える JavaScript のどれかを作成した覚えはあるでしょうか。


CakePHP に投稿に対する評価を追加する

CakePHP バージョンの Blahg に投稿に対する評価を追加する前に、/column/htdocs/cakephp/js ディレクトリーに Prototype がダウンロード済みであることを確認します。デフォルトのレイアウト・テンプレートを変更し、ヘッダーに Prototype ライブラリーを組み込めるようにする必要があります。そのテンプレートは、/column/protected/cakephp/app/views/layouts/ ディレクトリーにある default.ctp ファイルです。ヘッダーに <?php echo $javascript->link('prototype') ?> という行を追加します。

このテンプレートを使う前に、後で必要となる JavaScript と Ajax のヘルパー関数を含む、基本的な AppController コントローラーを作成する必要があります。/column/protected/cakephp/app ディレクトリーの中に app_controller.php ファイルを作成します。このファイルはリスト 7 のような内容のファイルです。

リスト 7. app_controller.php ファイルを作成する
<?php

class AppController extends Controller {
        var $helpers = array('Html', 'Form', 'Javascript', 'Ajax');
}
?>

注意: 本来は、このコントローラーを作成する必要はありません。JavaScript や Ajax のヘルパー関数を単純に投稿コントローラーや評価コントローラーで使うことはできるのです。しかし基本的なアプリケーション・コントローラーを作成することで、そうしたヘルパー関数をヘルパー関数のリストに追加しなくても任意のコントローラーで使うことができます。これはベースとなる AppController オブジェクトをオーバーロードするための正しい方法です。

今度は基本的な評価モデルと評価コントローラーを作成する必要があります。これらは、これまで作成したモデルとコントローラーとほとんど同じようなものです。評価モデルを作成する場合には、評価モデルと投稿モデルとの間にモデルのアソシエーション (関連) を設定する必要があります。後でもっと堅牢な評価機能を追加することを決定するのでない限り、実際には評価にモデルのアソシエーションを追加する必要はありません。コード・アーカイブには、両方のアソシエーションが形式的に設定されています。

この評価コントローラーでは、さらにいくつか新しいものを追加したいと思います。そこで、RequestHandler コンポーネントを使えるようにして、beforeFilter 関数を追加します。beforeFilter 関数の中で RequestHandler をチェックし、もしリクエストが Ajax によるものであればデバッグ・コードをオフにします。それ以外の点は、このコントローラーは皆さんがここまで読んだ時点で想像しているようなものになります。2 つのメソッド (readwrite) は post_id を探し、評価を出力します。

注意:コード・アーカイブの評価コントローラーのコードは単に評価を返すだけですが、もっと複雑な Ajax 呼び出しを行う場合には、テンプレートを作成し (例えば views/ranks/viewrank.ctp など)、$this->render('viewrank', 'ajax'); を使ってビューをレンダリングすることができます。しかしここでは現在の評価しか必要ないため、そこまでする必要はありません。

これで、あとは投稿を読むためのビューに評価の span といくつかの Ajax リンクを追加するだけで、すべて完了です。

リスト 8. 評価の span を追加する
<h4>Rank: <span id="rank"><?php echo (int) $post['Rank']['rank'] ?></span></h4>
<?php echo $ajax->link('Hot', '/ranks/write/' . $post['Post']['id'] . '/1', array
('update' => 'rank')); ?> or
<?php echo $ajax->link('Not', '/ranks/write/' . $post['Post']['id'] . '/-1', array
('update' => 'rank')); ?>

こうした Ajax リンクが言っていることは基本的に、「Ajax を使ってこの URL を呼び出し、そして何であれ返されるものを使って DOM 要素 rank を更新しなさい」ということです。(幸いなことにデバッグ・メッセージはオフしてあります)。すべてが用意できたら、早速投稿をロードして試してみます。ソースを表示し、私達が作成したものではない JavaScript について考えてみてください。素晴らしいと思いませんか。


まとめ

これで、それぞれのフレームワークが Ajax をどのようにサポートしているか (あるいはサポートしていないか) を基本的に理解できたはずです。もっと複雑な Ajax を実際に試してみる必要がありますが、ここまでの説明で、皆さんは問題なく先に進めるはずです。


ダウンロード

内容ファイル名サイズ
Part 4 sample codeos-php-fwk4.zip30KB

参考文献

学ぶために

製品や技術を入手するために

  • Prototype は動的な Web アプリケーションの開発に役立つ JavaScript フレームワークです。
  • PHP V5.2.3 をダウンロードしてください。
  • 皆さんの次期オープン・ソース開発プロジェクトを IBM trial software を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
  • IBM 製品の評価版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=294019
ArticleTitle=PHP のフレームワーク: 第 4 回 Ajax のサポート
publish-date=02122008