目次


Ext.Direct を Ajax アプリケーションで使用する

PHP を使ってクライアント・サイドとサーバー・サイドの Ajax アプリケーション開発を効率化する

Comments

はじめに

速度が遅く、応答性も悪く、直観に反する動作をしていた Web アプリケーションは、Ajax の概念が登場したことで、デスクトップ・アプリケーションのように振る舞い、即時に応答を返すようになりました。ページを最新の表示に更新する必要もなく、あらゆる点でこれまでよりも遥かに快適なユーザー・エクスペリエンスが実現されるようになりました。しかし一方で Ajax には、アプリケーション開発の複雑さが増すという問題があります。イベント駆動型のアプリケーションでは、ユーザーがボタンをクリックしたときにアクションを実行することになります。従来のアプリケーション開発では、アクションの実行内容のロジックすべてをイベント・ハンドラーに直接含めることができますが、Ajax ではそう簡単には行きません。Ajax の場合、クライアント・サイドで何らかの検証を行い、検証に合格すると、データを準備して新しい Ajax リクエストを作成することになります。さらに、リクエストに成功した場合のレスポンスやエラーを処理するための関数を定義し、Ajax リクエストを処理して適切なレスポンスを返すサーバー・サイドのコードも作成しなければなりません。レスポンスは、JSON (JavaScript Object Notation) や XML などといった特定のデータ形式にする必要もあるでしょう。しかも、クライアント・サイドが想定している方法でレスポンスを提供しなければなりません。

要するに、Ajax 開発では、Web アプリケーション開発者がクライアント・サイドとサーバー・サイド両方のコードを保守しなければなりませんが、クライアント・サイドとサーバー・サイドとでは、コードの動作の仕方に大きな違いがあります。そのことが、コードのデバッグや保守を困難にしているというわけです。もし、開発者にクライアント・サイドからサーバー・サイドのアクションを呼び出す手段があったとしたら、Ajax リクエストとレスポンスの処理に費やす作業は最小限に減ることでしょう。そこで登場するのが、Ext.Direct です。

最初は、Ext.Direct は小さな問題には大袈裟すぎるソリューションのように思えるかもしれませんが、始めに時間と手間をかけることで、後からその苦労が実を結び始めます。Ext.Direct を構成する要素を動作させるという最初のハードルは難解なように見えるものの、通常、この作業を行うのは一度だけです。いったん動作してしまえば、新しいクラスやメソッドを追加するために必要な変更は極めて単純なものになります。この記事では、Ext.Direct を導入して使えるようにする方法を説明し、実際に Ext.Direct を使って JavaScript からリモートの PHP メソッドを呼び出す方法も紹介します。その後、Ext.Direct が提供する高度な機能をいくつか取り上げ、これらの機能を皆さん独自のアプリケーションでフルに活用する方法を説明します。

前提条件

この記事では Ext.Direct を使用してサーバー・サイドの PHP スクリプトとの通信を行います。PHP がインストールされた稼働中の Web サーバーがない場合には、よく使われている Linux®、Windows®、Mac OS X、および Solaris 対応の XAMPP パッケージを使用することができます。Apache、PHP、MySQL およびその他の製品のインストール方法については、「参考文献」のリンクを参照してください。

Ext.Direct を使用するには、ExtJS JavaScript ライブラリーをダウンロードして、お使いの Web サーバーのドキュメント・ルート内に解凍する必要があります。XAMPP を使用している場合、XAMPP のインストール・ディレクトリー内にある htdocs という名前のサブディレクトリーを探してください。これが、Apache のドキュメント・ルートです。このディレクトリー内に direct という名前のディレクトリーを作成します。ディレクトリーを作成し終わったら、sencha.com (「参考文献」を参照) にアクセスして、ExtJS の最新公開リリース (この記事を執筆している時点では 3.2.1) をダウンロードします。ダウンロードが完了したら、上記で作成した direct ディレクトリーにすべてのファイルを解凍します。あとは、解凍されたディレクトリーの名前を ext-3.x.x から ext に変更すれば、準備は完了です。記事のサンプル・コードでは、バージョンが違ってもそのまま使えるように、このディレクトリーを ext と呼ぶことにします (記事のサンプルのソース・コードを入手するには、「ダウンロード」を参照してください)。

Ext.Direct の導入

Ext.Direct がどのように動作するかを学ぶ最善の方法は、とりあえず使ってみることです。始めは複雑に思えるかもしれませんが、基本を理解できれば、Ext.Direct の潜在的な使い方とその能力が非常に明白なものになります。このセクションでは、Ext.Direct を使用して基本的な Web ページを作成する方法を説明します。この Web ページは、PHP の日付関数を使ってサーバーから現在の日付と時刻を取得します。

コンフィグ・ファイル

Ext.Direct を使用して、サーバー・サイドのクラスのメソッドを ExtJS に公開するには、クライアント・サイドで使用可能なクラスとメソッドを定義するコンフィグ・ファイルを作成する必要があります。このコンフィグ・ファイルは、使用しているプログラミング言語に固有のキーと値のペアのセットにすることも、JSON または XML 文書の形式にすることもできます。この例では、JSON または XML を構文解析しなくても済むように、PHP の配列を使用します。任意のテキスト・エディターを開いて、そこにリスト 1 のコードを追加してください。このファイルに config.php という名前を付けて、先ほど作成した direct ディレクトリーに保存します。

リスト 1. config.php — Ext.Direct のクラスとメソッドを定義する PHP コンフィグ・ファイル
<?php
$API = array(
    'Now'=>array(
        'methods'=>array(
            'getNow'=>array(
                'len'=>0
            )
        )
    )
);

リスト 1 のコードは API を定義しています。外側の配列には、1 つのキーと値のペアが含まれていて、キーは Now に設定されています。これが、公開する PHP クラスの名前です。このクラスは 1 つの配列からなり、配列には 1 つのメンバーが含まれます。メンバーに設定されている methods というキーは、ここに Now クラスから公開されるメソッドが含まれることを示します。methods 配列内の getNow というメンバーは、公開するメソッド、つまり getNow() を参照します。このメソッド自体も配列で、ここに定義された len プロパティーは、getNow() 関数が取る引数の数を示します。この例では引数を渡さないため、値は 0 となっています。

PHP クラス

次は、対応する PHP クラス・ファイルに取り掛かります。direct ディレクトリー内に新しいディレクトリーを作成し、classes という名前を付けてください。このディレクトリー内に、Now.php という名前の新規ファイルを作成し、リスト 2 の内容を追加します。

リスト 2. classes/Now.php — Ext.Direct から呼び出される PHP クラス
<?php
class Now {
    function getNow() {
        return date('jS F Y @ g:i:s a');
    }
}

ご覧のように、クラスの名前は、config.php に宣言したクラス名と同じ Now となっています。このクラスが持つ唯一のメソッドは getNow() です。このメソッドは引数を取りません。getNow() 関数は 27th August 2010 @ 12:21:34 pm というフォーマットで現在時刻を返します。

次に導入する必要のあるブロックは、Ext.Direct で使用できるメソッドを公開する JavaScript API です。PHP を使用して作成するこの API は、config.php ファイルの内容をロードして、Ext.Direct が読み取って理解できるように JSON 形式のファイルを生成します。この API は汎用 API なので、クラスやメソッドを追加する場合でも変更する必要はありません。この後、この API を Web ページ自体にロードする方法を説明します。

API

api.php という名前の新しいファイルを作成して、リスト 3 のコードを追加してください。

リスト 3. api.php — PHP クラスおよびメソッド用の動的 JavaScript API
<?php
require('config.php');
header('Content-Type: text/javascript');

$actions = array();
foreach($API as $aname=>&$a){
    $methods = array();
    foreach($a['methods'] as $mname=>&$m){
        $md = array(
            'name'=>$mname,
            'len'=>$m['len']
        );
        if(isset($m['formHandler']) && $m['formHandler']){
            $md['formHandler'] = true;
        }
        $methods[] = $md;
    }
    $actions[$aname] = $methods;
}

$cfg = array(
    'url'=>'router.php',
    'type'=>'remoting',
    'actions'=>$actions
);

echo 'Ext.app.REMOTING_API = ';

echo json_encode($cfg);
echo ';';

このスクリプトは最初に config.php ファイルをロードし、Web ブラウザーに対して出力のコンテンツ・タイプが JavaScript であることを明確に示します。このファイルは実際には <script> タグを使用して HTML ページにロードされるため、出力は JavaScript として処理されます。config.php ファイルで宣言される $API 変数には、Ext.Direct で使用可能なクラスとメソッドを設定したキーと値のペアが格納されます。リスト 3 のスクリプトは $API 変数をスキャンし、これらのクラスとメソッドの名前を調べて、JavaScript で使用可能なアクションを定義します。続いて $cfg のキーと値の配列を作成し、(次に作成する) ルーターの URL、タイプ (remoting に設定)、および使用可能なアクションを定義します。そして最後に Ext.app.REMOTING_API を定義する JavaScript を出力します。Ext.app.REMOTING_API の値としては、JSON 形式で表した $cfg 変数が設定されます。ブラウザーがこのファイルから実際に読み取る内容は、この先を読んでいくとわかります。

ルーター

あとは最後のコンポーネントとしてルーターを導入すれば、実際に Ext.Direct を使用してサーバー・サイドのメソッドを呼び出せるようになります。この全体像の中でルーターが果たす役割は、クライアント・サイドがサーバー・サイドに対して行うリクエストを受け取り、リクエストが要求するクラスにルーティングした後、該当するメソッドに引数を渡してそのメソッドを呼び出すことです。ルーターが扱わなければならないリクエストのタイプは 2 つあります。1 つは、データを直接 HTTP POST で送信するリクエストで、JSON 形式にしてから送信され、データを取得するために使用されます。もう 1 つは、データを更新するためのフォーム POST リクエストです。

複数のリクエストが同時に送信される場合、HTTP POST リクエストは配列となるため、ルーターは配列に含まれる個々のリクエストをそれぞれに応じて適切にルーティングしなければなりません。

ルーターを作成するには、新しいファイルを作成し、そのファイルを router.php という名前で direct フォルダーに保存します。このファイルの内容は、リスト 4 のコードが反映されたものになっている必要があります。

リスト 4. router.php — リクエストを適切な PHP クラスにルーティングするための PHP スクリプト
<?php
require('config.php');

class ExtAction {
    public $action;
    public $method;
    public $data;
    public $tid;
}

$isForm = false;
$isUpload = false;
if(isset($HTTP_RAW_POST_DATA)) {
    header('Content-Type: text/javascript');
    $data = json_decode($HTTP_RAW_POST_DATA);
} else if(isset($_POST['extAction'])) {
    $isForm = true;
    $isUpload = $_POST['extUpload'] == 'true';
    $data = new ExtAction();
    $data->action = $_POST['extAction'];
    $data->method = $_POST['extMethod'];
    $data->tid = isset($_POST['extTID']) ? $_POST['extTID'] : null;
    $data->data = array($_POST, $_FILES);
} else {
    die('Invalid request.');
}

function doRpc($cdata){
    global $API;
    try {
        if(!isset($API[$cdata->action])) {
            throw new Exception('Call to undefined action: ' . $cdata->action);
        }
        $action = $cdata->action;
        $a = $API[$action];

        doAroundCalls($a['before'], $cdata);

        $method = $cdata->method;
        $mdef = $a['methods'][$method];
        if(!$mdef){
            throw new Exception("Call to undefined method: $method on action $action");
        }
        doAroundCalls($mdef['before'], $cdata);

        $r = array(
            'type'=>'rpc',
            'tid'=>$cdata->tid,
            'action'=>$action,
            'method'=>$method
        );

        require_once("classes/$action.php");
        $o = new $action();

        $params = isset($cdata->data) && is_array($cdata->data) ?
                                             $cdata->data : array();

        $r['result'] = call_user_func_array(array($o, $method), $params);

        doAroundCalls($mdef['after'], $cdata, $r);
        doAroundCalls($a['after'], $cdata, $r);
    } catch(Exception $e) {
        $r['type'] = 'exception';
        $r['message'] = $e->getMessage();
        $r['where'] = $e->getTraceAsString();
    }
    return $r;
}

function doAroundCalls(&$fns, &$cdata, &$returnData=null) {
    if(!$fns) {
        return;
    }
    if(is_array($fns)) {
        foreach($fns as $f) {
            $f($cdata, $returnData);
        }
    } else {
        $fns($cdata, $returnData);
    }
}

$response = null;
if(is_array($data)) {
    $response = array();
    foreach($data as $d) {
        $response[] = doRpc($d);
    }
} else {
    $response = doRpc($data);
}
if($isForm && $isUpload) {
    echo '<html><body><textarea>';
    echo json_encode($response);
    echo '</textarea></body></html>';
} else {
    echo json_encode($response);
}

ルーターのコードはかなりの量がありますが、API と同じく、これは汎用的なコードです。したがって、Ext.Direct で実行できるメソッドやクラスを新しくリストに追加することにした場合でも、コードを変更する必要はありません。ファイルの先頭には、4 つのプロパティーを持つ基本クラスが定義されています。このクラスは、リクエストがフォーム POST の場合に使用されます。クラス定義の後には、リクエストに HTTP POST で直接送信されたデータが含まれているかどうかをチェックするコードが続きます。これに該当するデータが含まれている場合には JSON 形式のレスポンスを返します。そうでなければ、ExtAction クラスをインスタンス化して、フォーム POST データの値をプロパティーに割り当てます。

続いて doRpc という名前の関数が、Ext.Direct が呼び出しているクラスおよびメソッドを調べて関連するクラスにロードし、提供されている引数の値があれば、その値を渡して適切なメソッドを呼び出します。doAroundCalls 関数は、アクションの前または後に呼び出すように設定されているメソッドを呼び出すための関数です。この例では使用しないので、今のところ深く考える必要はありません。

このファイルの最後で、レスポンスを組み立てます。複数のリクエストがある場合、リクエストの配列をループ処理して、リクエストごとに doRpc 関数を呼び出します。リクエストが 1 つしかなければ、doRpc を一度だけ呼び出します。最後に、リクエストがフォーム POST またはファイルのアップロードであったのかをチェックし、そうであれば、<textarea> HTML 要素に JSON 形式にした出力を含めた有効な HTML ページとして、データを出力します。これは、フォーム POST リクエストに応答する際の Ext.Direct 仕様の要件です。直接データを送信する HTTP POST によるリクエストの場合には、単純に JSON 形式にしたレスポンスを発行します (前に、MIME タイプとして text/javascript を使用するレスポンスのヘッダーを定義しました)。

JavaScript でリモート・メソッドを呼び出す

コンフィグ・ファイル、PHP クラス API、ルーターをすべて作成した後は、Ext.Direct を使って Now という PHP クラスの getNow() 関数を呼び出す作業に進むことができます。direct フォルダーに first.php という名前の新規ファイルを作成して、リスト 5 のコードを追加してください。

リスト 5. first.php — 最初の Ext.Direct アプリケーション
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Ext.Direct Server Date/Time</title>
    <link rel="stylesheet" href="ext/resources/css/ext-all.css" />
    <script src="ext/adapter/ext/ext-base.js"></script>
    <script src="ext/ext-all.js"></script>
    <script src="api.php"></script>
</head>
<body>
<h1>Ext.Direct Server Date/Time</h1>
<script>
    Ext.onReady(function(){
        Ext.Direct.addProvider(Ext.app.REMOTING_API);

        Now.getNow(function(provider, response) {
            alert(response.result);
        });
    });
</script>
</body>
</html>

リスト 5 は、極めて単純な HTML 文書です。この文書には、<head> タグに通常の ExtJS ファイル (ext-all.css、ext-base.js、および ext-all.js) と、前に作成したリモート操作用の API (api.php) を組み込んでいるだけです。続いて作成しているのは、API を Ext.Direct プロバイダーとして追加する JavaScript です。これにより、サーバー・サイドの PHP メソッドを呼び出すために使える JavaScript クラスおよびメソッドが作成されます。次に Now クラスからサーバー・サイドの getNow メソッドを呼び出します。Ext.Direct 呼び出しが引数として取る関数は、それ自体が providerresponse という2 つの引数を取ります。この response 引数に、サーバー・サイドの PHP スクリプトから受け取るレスポンスが含まれることになります。

プロジェクトを実行する

ここまでで、最初の Ext.Direct アプリケーションに必要なコードは、すべて作成できました。早速、プロジェクトを実行して、このプロジェクトによって生成される結果を見てみましょう。任意の Web ブラウザーを開いて、http://127.0.0.1:5984/direct/first.php にナビゲートしてください。すると、サーバー・サイドの PHP によって生成およびフォーマット設定された、現在の日付と時刻を示すアラート・メッセージがポップアップ表示されるはずです。このメッセージは、図 1 に示すウィンドウのように表示されます。

図 1. 最初の Ext.Direct アプリケーションが動作しているところ
「27th August 2010」と「4:23:00 pm」いう日時と「OK」ボタンが表示された画面
「27th August 2010」と「4:23:00 pm」いう日時と「OK」ボタンが表示された画面

例えば Firefox などのブラウザーを使っていて、「View Source (ページのソースを表示)」ビューで外部 JavaScript ファイルへのリンクをクリックできる場合には、アラート・ボックスの「OK」ボタンをクリックしてメッセージを閉じてから、ページの任意の場所を右クリックして「View Source (ページのソースを表示)」をクリックしてください。表示されたソースで、<script src="api.php"> という行を探します。

この行の api.php の部分は、クリックできるリンクとなっています。このリンクをクリックすると、config.php に定義されたクラスとメソッドに対して生成された、api.php の JavaScript ソースが表示されます。このソースには、Ext.app.REMOTING_API = {"url":"router.php","type":"remoting","actions":{"Now":[{"name":"getNow","len":0}]}}; という行が含まれているはずです。

この行が宣言しているのは、Ext.app.REMOTING_API の構成です。この API は、コードの中で公開されたメソッドを使うときにプロバイダーとして使用することになります。

次の話題に移る前に、Ext.Direct で新たに使用できるようにするクラスとメソッドを追加する場合には、何が必要になるかを調べてみましょう。例として、Server というクラスと、このクラスの getSoftwareというメソッドを作成します。これは、Web サーバーと PHP インストールの詳細を返すメソッドです。まず、Server.php という名前の新規ファイルを作成し、direct ディレクトリーの classes サブディレクトリー (Now.php ファイルが置かれているディレクトリー) に保存します。このファイルの内容はリスト 6 のとおりです。

リスト 6. classes/Server.php — 2 つ目のクラス
<?php
class Server {
    function getSoftware() {
        return $_SERVER['SERVER_SOFTWARE'];
    }
}

getSoftware メソッドは単に、SERVER_SOFTWARE 環境変数の値を返すだけです。続いて、config.php を変更して、この新しいクラスとメソッドをリモート呼び出しに使用できることを Ext.Direct に通知しなければなりません。そこで、リスト 7 と同じ内容になるように config.php を変更してください。

リスと 7. 更新後の config.php — 新規クラスおよびメソッドの参照
<?php
$API = array(
    'Now'=>array(
        'methods'=>array(
            'getNow'=>array(
                'len'=>0
            )
        )
    ),
    'Server'=>array(
        'methods'=>array(
    	      'getSoftware'=>array(
                'len'=>0
    	      )
        )
    )
);

ご覧のように、このファイルには Server クラスへの参照を追加し、このクラスには getSoftware メソッドが含まれること、そしてこのメソッドは引数を取らないことを定義したにすぎません。最後に必要となる作業は、サーバー・サイドのメソッドを実際に呼び出す first.php ファイルを変更することです。この例では、2 番目のアラート・ボックスに Server.getSoftware() メソッドからのレスポンスを表示するだけなので、first.php ファイルで Now.getNow 呼び出しを閉じている「});」の下に、リスト 8 に記載する行を追加します。

リスト 8. Now.getNow 呼び出し
Server.getSoftware(function(provider, response) {
    alert(response.result);
});

ブラウザーに戻ってページを最新の表示に更新してください。最初はお馴染みの日付の値がポップアップ表示されます。このメッセージを閉じると、2 番目のアラート・ウィンドウが表示され、今度はサーバーのソフトウェア情報が示されます (図 2 を参照)。

図 2. 新しく追加したメソッドからのレスポンス
Apache メッセージと「OK」ボタンを表示するウィンドウ
Apache メッセージと「OK」ボタンを表示するウィンドウ

皆さんにも同意してもらえると思いますが、基礎を固めてしまえば、あとは比較的簡単に新しいクラスとメソッドを追加することができます。最後に、api.php によって生成された JavaScript コードを確認してください。リスト 9 に記載するコードが含まれているはずです。

リスト 9. api.php によって生成された JavaScript コード
Ext.app.REMOTING_API =
 {"url":"router.php","type":"remoting","actions":{"Now":[{"name":"getNow",
 "len":0}],"Server":[{"name":"getSoftware","len":0}]}};

上記を見るとわかるように、このコードには getSoftware メソッドを持つ Server クラスが追加されています。このコードを使うことで、これらの関数を JavaScript で使用できるようになります。

Ext.Direct の基本的な使用方法は以上のとおりです。次のセクションでは、これよりも高度な Ext.Direct の概念として、引数を取るメソッドを操作する方法、複雑なレスポンスを返す方法、そしてデータを直接 HTTP POST で送信するのではなく、リクエストでフォーム・データを送信する方法を紹介します。これらの方法をおさえておけば、この記事で学んだ知識を独自のアプリケーションに適用できるようになります。

次のステップ: その他の Ext.Direct の概念

前のセクションで Ext.Direct 開発の基本を学びましたが、この知識を使って独自のアプリケーションの構築を始める前に、他にも理解しておかなければならない概念がいくつかあります。このセクションでは、これらの概念について説明します。

メソッドで引数を取る

これまでのセクションで Ext.Direct に対して公開した 2 つのメソッドは極めて基本的なメソッドで、引数を取ることすらしません。けれども、作成するサーバー・サイドの関数に引数を渡さなければならないことはよくあります。そこで、これから 2 つの関数のうちの 1 つを、引数を取って、それを使用するように変更します。

まずは、前に作成した config.php ファイルを開き、getNow メソッド参照の len 属性値を 0 から 1 に変更します。こうすることで、Ext.Direct に対し、getNow メソッドが引数を 1 つ取ると想定していることを伝えます。

次に、Now.php のクラスを変更します。このファイルの内容を、リスト 10 に記載するコードに変更してください。

リスト 10. 変更後の classes/Now.php
<?php
class Now {
    function getNow($format) {
        return date($format);
    }
}

上記では、getNow 関数が $format という 1 つの引数を取るようになっていて、この引数は PHP の date() 関数を呼び出す際にも使われていることに注目してください。

最後に必要な作業は、first.php ファイルが remote メソッドを呼び出すときに実際に引数を渡すように、このファイルを変更することです。リスト 11 に記載する行を探してください。

リスト 11. first.php ファイルの変更
Now.getNow(function(provider, response) {
    alert(response.result);
});

このメソッド呼び出しに引数を渡すには、以下のように、callback 関数の前に引数を配置します (リスト 12 を参照)。

リスト 12. callback 関数の前に引数を配置する
Now.getNow('jS F Y', function(provider, response) {
    alert(response.result);
});

次に、ブラウザー・ウィンドウでリロードを実行して、どのように変更されているかを見てください。今度の getNow メソッド呼び出しに対するレスポンスは、日付と時刻ではなく、日付しか返しません (図 3 を参照)。

図 3. 引数に日付のフォーマットを指定した結果
「28th August 2010」という日付と「OK」ボタンが表示された画面
「28th August 2010」という日付と「OK」ボタンが表示された画面

次のセクションでは、1 つの値を返すのではなく、もう少し複雑なレスポンスを返す方法を説明します。

複雑な結果セットを返す

これまでのところ、メソッドによって生成されるレスポンスにはいずれも 1 つの値しかありませんでした。基本的な関数にはこれで十分ですが、実際には、オブジェクトと配列などといった複雑な型を返さなければなければならない場合がよくあります。レスポンスは JSON 形式なので、そのような場合に対応するのは簡単です。PHP クラスのメソッドは配列またはキーと値のペアを返すことができるため、私たちが定義した API は、配列またはキーと値のペアから自動的に JSON 配列またはオブジェクトを生成します。ここで、単純な例を見てみましょう。そのためにはまず、Server クラスを変更する必要があります。classes/Server.php ファイルを開いて、リスト 13 に記載する関数を追加してください。

リスト 13. Server クラスに追加する getEnvVars() 関数
function getEnvVars() {
    return $_SERVER;
}

今度は config.php ファイルを変更して、上記の新しいメソッドを組み込みます。ファイルの内容は、リスト 14 に示すコードのようになっていなければなりません。

リスト 14. 変更後の config.php — 新規 getEnvVars メソッドを追加する
<?php
$API = array(
    'Now'=>array(
        'methods'=>array(
            'getNow'=>array(
                'len'=>1
            )
        )
    ),
    'Server'=>array(
        'methods'=>array(
    	      'getSoftware'=>array(
                'len'=>0
            ),
            'getEnvVars'=>array(
                'len'=>0
            )
        )
    )
);

次に、direct フォルダー内に second.php という名前のファイルを作成します。このファイルは、新しく作成した getEnvVars メソッドを呼び出すための新規 Web ページとして使用します。作成した新規ファイルに、リスト 15 の内容を追加して保存してください。

リスト 15. second.php — 新規 getEnvVars メソッドを使用する
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Ext.Direct Complex Responses</title>
    <link rel="stylesheet" href="ext/resources/css/ext-all.css" />
    <script src="ext/adapter/ext/ext-base.js"></script>
    <script src="ext/ext-all.js"></script>
    <script src="api.php"></script>
</head>
<body>
<h1>Ext.Direct Complex Responses</h1>
<script>
    Ext.onReady(function(){
        Ext.Direct.addProvider(Ext.app.REMOTING_API);

        Server.getEnvVars(function(provider, response) {
            alert(response.result.DOCUMENT_ROOT);
            alert(response.result.HTTP_USER_AGENT);
            alert(response.result.MYSQL_HOME);
        });
    });
</script>
</body>
</html>

これで、ブラウザーを開いて http://127.0.0.1/direct/second.php にアクセスすると、3 つのポップアップ・ウィンドウが表示されます。それぞれ、Web サーバーのドキュメント・ルートの場所を示すウィンドウ、使用しているブラウザーのユーザー・エージェント・ストリングを示すウィンドウ、そして MySQL がインストールされているシステム上の場所を示すウィンドウです。

フォーム POST データを送信する

このセクションでは、フォームからサーバーにデータを送信する方法を説明します。この方法では、データを直接 HTTP POST のリクエストとして送信するのではなく、フォーム POST のリクエストとして送信します。まずは、「Enter a number (数字を入力してください)」というフィールドと「Validate (検証)」というテキストが付いたボタンだけがある単純なフォームを作成します。ここで目標とするのは、サーバー・サイドでフィールドを検証し、フィールドが空ではなく、入力されているのが数値であることを確かめることです。検証で問題があった場合は、ユーザーにエラー・メッセージを表示します。もちろん基本的な JavaScript でも対応できる操作ですが、実際のアプリケーションでは、この概念を簡単にカスタマイズして、例えば要求されたユーザー名が取得されているかどうかなど、入力をデータベースと照合することができます。

この例のために、NumberValidator という新しい PHP クラスを作成します。このクラスに含めるメソッドは唯一、validateNumber だけです。最初のステップとして、この新しいクラスとメソッドを config.php ファイルに追加します。この追加作業は以前とほとんど同じですが、今回、このメソッドは直接 POST したデータのハンドラーを使用するのではなく、フォーム・ハンドラーを使用することを示す必要があります。config.php ファイルをリスト 16 のコードと同じになるように変更してください。

リスト 16. 変更後の config.php — NumberValidator クラスを追加する
<?php
$API = array(
    'Now'=>array(
        'methods'=>array(
            'getNow'=>array(
                'len'=>1
            )
        )
    ),
    'Server'=>array(
    	'methods'=>array(
    		'getSoftware'=>array(
    		    'len'=>0
    		),
    		'getEnvVars'=>array(
    		    'len'=>0
    		)
    	)
    ),
    'NumberValidator'=>array(
        'methods'=>array(
            'validateNumber'=>array(
                'len'=>1,
                'formHandler'=>true
            )
        )
    )
);

次に必要となるのは、新しいクラスです。新規ファイルを作成し、NumberValidator.php という名前で classes サブディレクトリーに保存します。このファイルの内容はリスト 17 に示すとおりです。

リスト 17. classes/NumberValidator.php — 新しい検証クラス
<?php
class NumberValidator {
    function validateNumber($form) {
        $response = array();
        $num = $form['num'];
        if (strlen($num) < 1) {
            $success = false;
            $response['errors'] = array(
                'num'=>'Required field.'
            );
        } else if (!is_numeric($num)) {
            $success = false;
            $response['errors'] = array(
                'num'=>'Not a valid number.'
            );
        } else {
            $success = true;
        }
        $response['success'] = $success;
        return $response;
    }
}

このクラスは比較的単純なもので、送信されたフォームに含まれる値を引数として取ります。ここで作成する num という名前のフィールドが、検証する対象です。このフィールドが空であるかどうか、あるいは数値以外の値が含まれているどうかをチェックし、いずれかの条件が true の場合にはエラーを返します。このメソッドが返す $response オブジェクトには、数値が正しく含まれていることが検証された場合、値が true に設定された success という 1 つのメンバーが含まれることになります。検証で問題があった場合には、2 つのメンバーが含まれることになり、1 つは値が false に設定された success、もう 1 つは、該当するエラーとしてフィールドに表示されるエラー・メッセージが含まれるエラー・オブジェクトです。

最後のステップは、新しい Web ページを作成することです。このページのコードは、フォームの作成、そして「Validate (検証)」ボタンによる送信イベントの処理を行います。この記事は ExtJS のチュートリアルなので、このプロセスには ExtJS UI の利点を活用することにしましょう。third.php という名前の新規ファイルを作成し、direct ディレクトリーに保存してください。このファイルには、リスト 18 に記載する内容を追加します。

リスト 18. third.php — 最後の例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
    <title>Ext.Direct Form Example</title>
    <link rel="stylesheet" href="ext/resources/css/ext-all.css" />
    <script src="ext/adapter/ext/ext-base.js"></script>
    <script src="ext/ext-all.js"></script>
    <script src="api.php"></script>
</head>
<body>
<h1>Ext.Direct Form Example</h1>
<script>
    Ext.onReady(function(){
        Ext.Direct.addProvider(Ext.app.REMOTING_API);

        Ext.QuickTips.init();

        var formExample = new Ext.form.FormPanel({
            title: 'Validation Form',
            padding: 10,
            buttons:[{
                text: 'Validate',
                handler: function(){
                    formExample.getForm().submit();
                }
            }],
            renderTo: Ext.getBody(),
            defaultType: 'textfield',
            items: [{
                fieldLabel: 'Enter a number',
                name: 'num',
                msgTarget: 'side'
            }],
            api: {
                submit: NumberValidator.validateNumber
            }
        });
    });
</script>
</body>
</html>

ExtJS を使い慣れていれば、上記のコードの内容は理解できるはずです。今まで ExtJS を使用した経験がない読者のために説明しておくと、このコードは、「Validate (検証)」というテキストを持つ 1 つのボタンを表示する新しい FormPanel (ExtJS の数多くの美しい UI コントロールのうちの 1 つ) を作成します。このボタンのイベント・ハンドラーは、ボタンがクリックされるとフォームを送信します。コードではこのフォームを、コードが実行されるページの文書本体でレンダリングするように指定しています。これにより、このフォームのレンダリングはページの最下部 (この例の場合、<h1> 要素の下) に追加されます。次にこのコードで定義しているのは、フォームに表示する項目です。この例では唯一、num フィールドが表示対象の項目に該当します。最後に送信用の API が指定されており、この例では NumberValidator.validateNumber Ext.Direct メソッドを使用しています。以降はフォームが送信されるたびに (つまり、「Validate (検証)」ボタンがクリックされるたびに)、このメソッドが呼び出されることになります。

コードの作成は、これで完了しました。ブラウザーを立ち上げて、http://127.0.0.1/direct/third.php にアクセスしてください。すると、1 つのフィールドと「Validate (検証)」ボタンを持つ簡潔なフォームが表示されます。まずは、フィールドを空のままにしてボタンをクリックしてみてください。フィールドが赤く強調表示され、その横にアイコンが示されるはずです (図 4 を参照)。マウスをそのアイコンの上に重ねると、「Required field (必須フィールド)」というメッセージが表示されます。

図 4. 実行中のサンプル・フォーム
赤い枠で囲まれた「Enter a number (数字を入力してください)」フィールドを示す画面
赤い枠で囲まれた「Enter a number (数字を入力してください)」フィールドを示す画面

今度は有効な数値を入力して、「Validate (検証)」ボタンをクリックします。フィールドの強調表示は解除され、アイコンもフィールドの横から消えているはずです。最後に、無効な数値として例えば「test」というテキストを入力して、「Validate (検証)」ボタンをもう一度クリックしてください。フィールドは再び強調表示され、アイコン・ツールチップに「Not a valid number (無効な数値)」というメッセージが表示されます。

まとめ

この記事では Ext.Direct の概要を紹介し、基本的な使用方法を説明しました。まず始めに取り上げたのは、Ext.Direct の概要、そして Ext.Direct によって解決しようとしている問題です。次に、Ext.Direct アプリケーションを構成するさまざまな要素として、コンフィグ・ファイル、API、ルーター、PHP クラス、そして Ext.Direct を使用するアプリケーション・ファイルについて説明しました。その過程で、アプリケーションで Ext.Direct メソッドを呼び出す方法についても説明しました。さらに、サーバー・サイドのメソッドに引数を渡す方法、サーバーからのレスポンスに複雑なデータを返す方法を説明しました。そして最後に、フォーム・データを処理し、フォームの入力を基にサーバー・サイドで検証を行う方法を説明しました。

Ext.Direct について詳しく調べるとよい内容はまだ他にもたくさんあります (Ext.Direct を話題にした記事やガイドへのリンクについては、「参考文献」を参照してください)。今のところ Ext.Direct はまだ登場して間もない技術なので、時間が経つにつれ、拡張されてますます機能が充実してくることが期待できます。今の時点で Ext.Direct の基本を学んでおくことで、将来 Ext.Direct が提供するであろう機能のすべてを活用する上で必要な土台を築くことになります。


ダウンロード可能なリソース


関連トピック

  • Ext JS で作る AJAX アプリケーション」(developerWorks、2008年7月): この記事では、Ext JS の基盤となっている JavaScript によるオブジェクト指向的な設計概念の概要、そしてリッチ・インターネット・アプリケーションの UI 要素に Ext JS フレームワークを適用する方法を説明しています。
  • JavaScript フレームワークの比較」(developerWorks、2010年2月): JavaScript 開発を大幅に強化するフレームワークの概要を理解してください。
  • Use Ext, Aptana, and AIR to build desktop applications」(developerWorks、2008年7月): オープンソースの Aptana Studio IDE、Aptana 用 Adobe AIR プラグイン、そしてオープンソースの JavaScript フレームワーク、Ext を使用して、連絡情報管理ユーティリティーを作成してください。
  • Mastering Ext.Direct, Part 1」: アプリケーションで効率的に Ext.Direct を使用する方法を学んでください。
  • ExtJS - Direct: Ext.Direct に関するプレゼンテーションを見てください。
  • Ajax をマスターする: 第 2 回 JavaScript と Ajax を使用して行う非同期要求」(developerWorks、2006年1月): Ajax と XMLHttpRequest オブジェクトを使用して、ユーザーにサーバーからのレスポンスを待たせることのないリクエスト/レスポンス・モデルを作成する方法を学んでください。
  • モバイル Web 用の Ajax アプリケーションを作成する」(developerWorks、2010年3月): Ajaxを使用して特定のブラウザーに依存しないスマートフォン用 Web アプリケーションを構築する方法を学んでください。
  • Where and when to use Ajax in your applications」(developerWorks、2008年2月): Ajax を利用して、Web サイトを改善すると同時に不快なユーザー・エクスペリエンスを防ぐ方法を学んでください。
  • Ext Direct は、プラットフォームにも言語にも依存せずに、クライアントからサーバー・サイドのメソッドをリモートで操作するための技術です。
  • ExtJS 3.2.1 API Documentation で、Ext.Direct の以下のクラスについて調べてください。
  • Web 2.0 アプリケーションのパフォーマンスを改善する」(developerWorks、2009年12月): この記事では、さまざまなブラウザーのキャッシュ・メカニズムを探っています。
  • JSON の紹介: JSON の構文を学んでください。
  • developerWorks Web development ゾーンでは、多種多様な Web ベースのソリューションを話題にした記事を揃えています。
  • developerWorks チュートリアル・シリーズ「Learning PHP」では、極めて基本的な PHP スクリプトから、データベースの操作、そしてファイル・システムによる効率化に至るまで学ぶことができます。
  • PHP.net は、PHP 開発者の主要な情報源です。
  • Recommended PHP reading list」に目を通してください。
  • IBM developerWorks の PHP project resources にアクセスして、PHP の腕を磨いてください。
  • developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • ExtJS (この記事を書いている時点では 3.2.1) を入手してください。リッチ・インターネット・アプリケーションを構築するための、ブラウザーに依存しない JavaScript ライブラリーです。
  • XAMPP は、Apache、PHP、MySQL などを簡単にインストールする手段となります。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, Open source
ArticleID=576942
ArticleTitle=Ext.Direct を Ajax アプリケーションで使用する
publish-date=10122010