PHP WebアプリケーションでのAjax入門

このドキュメントでは、Ajaxの概要を説明し、Ajax関連のテクノロジを使用するときにより短時間で効率よくプログラミングできるNetBeans IDEの機能を示します。Ajaxの基本的な機能を学びながら、テキスト・フィールドの自動補完を行う単純なアプリケーションをビルドします。このドキュメントでは、Javaテクノロジを使用するAjaxの使用に公開しているGreg Murrayの記事とサンプル・アプリケーションを使用します。

Ajaxは「Asynchronous JavaScript and XML」(非同期JavaScriptとXML)の略です。Ajaxは基本的に、ユーザーによるWebページの操作をWebアプリケーションで効率的に処理する方法であり、ユーザーが操作するたびにページをリフレッシュしたり、ページ全体を再ロードしたりする必要を減らします。その結果、デスクトップ・アプリケーションやプラグインに基づいたWebアプリケーションのような、ブラウザを使用したスムーズな操作が可能になります。Ajaxの相互作用はバックグラウンドで非同期で処理されます。このとき、ユーザーはページの操作を続けることができます。Ajaxの相互作用はJavaScriptコードによって開始されます。Ajaxの相互作用が完了したら、JavaScriptがそのページのHTMLソースを更新します。変更は、ページをリフレッシュすることなく、すぐに反映されます。Ajaxの相互作用を使用して、ユーザーがフォームに入力している間にサーバー側ロジックを使用してフォーム・エントリを検証したり、サーバーから詳細なデータを取り出したり、ページ上のデータを動的に更新したり、ページから部分フォームを送信したりできます。

目次

このページの内容は、NetBeans IDE 7.2、7.3、7.4および8.0に適用されます

このチュートリアルを完了するには、次のソフトウェアとリソースが必要です。

ソフトウェアまたはリソース 必須バージョン
NetBeans IDEのPHPバンドル版 7.2, 7.3, 7.4, 8.0
Java Development Kit (JDK) 7または8
PHPエンジン PHP5
Apache Webサーバー 2.2

注意:

  • 使用しているオペレーティング・システムによっては、*AMPパッケージを使用してPHPの開発環境を構成できる場合があります。このパッケージにはPHPエンジンとApache Webサーバーが含まれます。環境の構成方法については、PHPの学習を参照してください。
  • このチュートリアルは、使用する各テクノロジ(HTML、CSS、JavaScript、およびPHPなど)に関する実用的な知識がある方を対象としています。コードによって提供される機能の概要は説明しますが、コード行ごとの処理は説明しません
  • プロジェクトを、正常に機能するソリューションと比較する必要がある場合は、サンプル・アプリケーションをダウンロードできます。IDEの新規プロジェクト・ウィザード([Ctrl]-[Shift]-[N]、Macの場合は[⌘]-[Shift]-[N])で「PHP」を選択し、「既存のソースを使用するPHPアプリケーション」プロジェクト・タイプを選択します。ウィザードで、コンピュータにダウンロードされているソースを指定します。

アプリケーションの概要

ユーザーが作曲家に関する情報を検索できるWebページを考えます。このページには、ユーザーが作曲家の名前を入力できるフィールドがあります。サンプル・アプリケーションのエントリ・フィールドには、オートコンプリート機能があります。つまり、ユーザーが作曲家の名前の一部を入力すると、Webアプリケーションでは、入力した文字から名または姓のいずれかが始まるすべての作曲家のリストを表示してその名前を補完します。オートコンプリート機能によってユーザーは作曲家の名前を完全に覚えている必要がなく、また求めている情報を直観的かつ容易に入手できます。

ブラウザに表示されたサンプル・アプリケーション

検索フィールドへの自動補完の実装は、Ajaxを使用して実行できます。Ajaxは、XMLHttpRequestオブジェクトを使用してクライアントとサーバーの間でリクエストとレスポンスを非同期で受け渡しすることで機能します。次の図は、クライアントとサーバーの間で行われる通信のプロセス・フローを示します。

Ajaxのプロセス・フロー図

この図には、次の手順のプロセス・フローを示しています。

  1. ユーザーが、たとえば名前を入力しているときにキーを解除して、イベントをトリガーします。すると、XMLHttpRequestオブジェクトを初期化する関数へのJavaScriptコールが行われます。
  2. XMLHttpRequestオブジェクトが、イベントをトリガーしたコンポーネントのIDを含むリクエスト・パラメータと、ユーザーが入力した値で構成されます。次に、XMLHttpRequestオブジェクトがWebサーバーへの非同期リクエストを実行します。
  3. Webサーバーでは、サーブレットやリスナーなどのオブジェクトがリクエストを処理します。データ・ストアからデータが取り出され、XMLドキュメント形式のデータを含むレスポンスが作成されます。
  4. 最後に、コールバック関数を使用してXMLHttpRequestオブジェクトがXMLデータを受け取って処理し、新しいデータを含むページを表示するようにHTMLのDOM (Document Object Model)を更新します。

このチュートリアルでは、前述の図で示したプロセス・フローに従ってオートコンプリートのシナリオを構築する方法を示します。最初に、プレゼンテーション用、およびXMLHttpRequestオブジェクトの生成に必要な機能用のクライアント側ファイルを作成します。次に、PHPベースのテクノロジを使用してデータ・ストアとビジネス・ロジックを作成してサーバー側を設定します。最後に、クライアント側に戻り、callback()と、HTMLのDOMを更新するためのその他のJavaScript機能を実装します。


クライアント側のプログラミング: 第1部

最初に、IDEで新しいPHPアプリケーション・プロジェクトを作成します。

  1. 「ファイル」>「新規プロジェクト」を選択します。「カテゴリ」から「PHP」を選択します。「プロジェクト」で「PHPアプリケーション」を選択し、「」をクリックします。
  2. ステップ2の「名前と場所」で、プロジェクト名に「MyAjaxApp」と入力します。「ソース・フォルダ」フィールドでコンピュータ上でのプロジェクトの場所を指定できます。他のオプションはデフォルトのままにして、「」をクリックします。
    新規PHPプロジェクト・ウィザード - 「名前と場所」パネル
  3. ステップ3の「実行構成」で、アプリケーションのデプロイ方法を指定します。*AMPパッケージを構成してPHP開発環境を設定した場合は、ドロップダウン・リストから「ローカルWebサイト」を選択し、ブラウザに表示するプロジェクトのURLを指定します。
  4. 「ファイルをソース・フォルダから別の場所にコピー」オプションを選択します。次に、「フォルダにコピー」フィールドに、サーバー上のデプロイ先のパスを入力します。(Apacheでは、デフォルトのhtdocsディレクトリを使用します。)
    新規PHPプロジェクト・ウィザード - 「実行構成」パネル
  5. 終了」をクリックします。IDEによってプロジェクト・フォルダがファイル・システム内に作成され、プロジェクトがIDEで開きます。

    プロジェクト・ウィザードを使用して、 フレームワークのサポートをプロジェクトに追加することもできます(ウィザードのステップ4)。

    デフォルトのindex.phpインデックス・ページが生成され、IDEのエディタで開きます。また、「プロジェクト」ウィンドウにプロジェクトが表示されます。

    新規作成されたプロジェクトが表示された「プロジェクト」ウィンドウ
  6. コーディングを始める前に、アプリケーションを実行してみて、IDE、サーバー、ブラウザの間の構成が正しく設定されていることを確認します。

    IDEのエディタで、indexページに次のecho文を追加します。
    <?php
        // put your code here
        echo "<h2>Hello World!</h2>";
    ?>
    
  7. 「プロジェクト」ウィンドウでプロジェクト・ノードを右クリックし、「実行」を選択します。IDEによってデフォルトのブラウザが開き、index.phpで作成したメッセージ「Hello World」が表示されます。

    注意: プロジェクトを設定できない場合、またはIDE、サーバー、およびブラウザ間で通信を確立できない場合は、PHPプロジェクトの設定を参照して、詳細な手順を確認してください。環境の構成については、PHPの学習を参照してください。

HTMLエディタの使用

HTML要素が表示されたパレット

環境が正しく設定されていることを確認したら、まず、ユーザーに表示するオートコンプリート・インタフェースの開発から始めます。作成するインデックス・ページにはサーバー側のスクリプト要素は必要ないため、まずHTMLページを作成し、そのページをアプリケーションのエントリ・ポイントとして設定します。

IDEを使用する利点の1つは、作業を行うエディタには一般にコード補完機能が用意されていて、コーディングするときに適用すれば生産性を大幅に向上できることです。IDEのエディタは通常、使用しているテクノロジに適応するので、HTMLページで作業しているときにコード補完のキーの組合せ([Ctrl]-[Space])を押すとHTMLのタグと属性の候補が表示されます。後述するように、CSSやJavaScriptなどその他のテクノロジも同様です。

IDEのパレットも便利な機能です。パレットには、コーディングするテクノロジで一般的に適用される要素の使いやすいテンプレートが用意されています。項目をクリックして、ソース・エディタで開いているファイル内の任意の位置にドラッグするのみです。

この図のように大きなアイコンを表示するには、パレット内を右クリックし、「大きなアイコンを表示」を選択します。


  1. 「プロジェクト」ウィンドウで「MyAjaxApp」プロジェクト・ノードを右クリックし、「新規」>「HTMLファイル」を選択します。
  2. HTMLファイル・ウィザードで、ファイル名に「index」と入力し、「終了」をクリックします。新しいindex.htmlファイルがエディタで開きます。
  3. このファイルの既存の内容を次の内容に置き換えます。
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
    
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Auto-Completion using AJAX</title>
        </head>
        <body>
            <h1>Auto-Completion using AJAX</h1>
        </body>
    </html>
    
  4. テキスト・フィールドの目的を説明するテキストを追加します。次のテキストをコピーして、<h1>タグのすぐ下に貼り付けることもできます。
    <p>This example shows how you can do real time auto-completion using Asynchronous
        JavaScript and XML (Ajax) interactions.</p>
    
    <p>In the form below enter a name. Possible names that will be completed are displayed
        below the form. For example, try typing in "Bach," "Mozart," or "Stravinsky,"
        then click on one of the selections to see composer details.</p>
    
  5. ページにHTMLフォームを追加します。この操作を行うには、IDEのパレットに表示されている要素を使用します。パレットが開いていない場合は、メイン・メニューから「ウィンドウ」>「パレット」を選択します。次に「HTMLフォーム」の下にある「フォーム」要素をクリックし、ページ内に追加した<p>タグの下までドラッグします。「挿入フォーム」ダイアログ・ボックスが表示されます。次の値を指定します。

    • アクション: autocomplete.php
    • メソッド: GET
    • 名前: autofillform
    「挿入フォーム」ダイアログ

    「OK」をクリックします。指定した属性を含むHTMLの<form>タグがページに挿入されます。(GETはデフォルトで適用されるので、明示的に宣言しません。)

  6. HTML表をページに追加します。パレットの「HTML」カテゴリの下で「表」要素をクリックし、<form>タグの間の位置までドラッグします。「挿入表」ダイアログ・ボックスが開きます。次の値を指定します。

    • 行: 2
    • 列: 2
    • 境界線のサイズ: 0
    • 幅: 0
    • セルの間隔: 0
    • セルのパディング: 5
    「挿入表」ダイアログ
  7. ソース・エディタ内を右クリックし、「フォーマット」を選択します。これでコードの体裁が整います。フォームは次のようになります。
    <form name="autofillform" action="autocomplete.php">
      <table border="0" cellpadding="5">
        <thead>
          <tr>
            <th></th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td></td>
            <td></td>
          </tr>
          <tr>
            <td></td>
            <td></td>
          </tr>
        </tbody>
      </table>
    </form>
    
  8. 表の1行目の1列目に次のテキストを入力します(太字部分が変更箇所)。
    <td><strong>Composer Name:</strong></td>
  9. 1行目の2列目では、パレットから「テキスト入力」フィールドをドラッグしないで、次のコードを手動で入力します。
    <input type="text"
        size="40"
        id="complete-field"
        onkeyup="doCompletion();">
    
    入力するときは、IDEに組み込まれているコード補完サポートを使用してみてください。たとえば、「<i」と入力して[Ctrl]-[Space]を押します。カーソルの下に候補のリストが表示され、選択されている要素の説明が上のボックスに表示されます。ソース・エディタでコーディングしているときはいつでも[Ctrl]-[Space]を押して候補を表示できます。候補が1つのみの場合は、[Ctrl]-[Space]を押すと要素名が自動的に補完されます。
    ソース・エディタに表示されたコード補完
    入力したonkeyup属性はJavaScript関数doCompletion()を指しています。この関数は、フォームのテキスト・フィールド内でキーが押されるたびにコールされ、Ajaxのフロー図に示したJavaScriptコールに対応します。
  10. JavaScriptエディタでの作業に移る前に、アプリケーションのエントリ・ポイントとしてindex.phpファイルを新しいindex.htmlファイルに置き換えます。

    これを行うには、「プロジェクト」ウィンドウでプロジェクト・ノードを右クリックし、「プロパティ」を選択します。「実行構成」カテゴリを選択し、「開始ファイル」フィールドに「index.html」と入力します。「プロジェクト・プロパティ」ウィンドウ - 実行構成
  11. 「OK」をクリックして変更を保存し、「プロジェクト・プロパティ」ウィンドウを終了します。
  12. プロジェクトを実行して、ブラウザでどのように表示されるかを確認します。「プロジェクトの実行」(「プロジェクトの実行」ボタン)ボタンをクリックします。index.htmlファイルがデフォルトのブラウザに表示されます。
    ブラウザに表示されたインデックス・ページ

JavaScriptエディタの使用

IDEのJavaScriptエディタには、インテリジェントなコード補完、意味解釈の強調表示、名前の即時変更機能とリファクタリング機能など、多数の高度な編集機能が用意されています。IDEでのJavaScriptの編集機能の詳細は、NetBeans IDEによるアプリケーションの開発ユーザーズ・ガイドJavaScriptファイルの作成を参照してください。詳細は、http://wiki.netbeans.org/JavaScriptを参照してください。

JavaScriptのコード補完は、.jsファイル内でコーディングするとき、および他のテクノロジ(HTML、RHTML、JSP、PHPなど)を使用しているときに<script>タグ内で自動的に提供されます。JavaScriptエディタの使用中は、IDEによって、JavaScriptの「オプション」パネルで指定するブラウザのタイプとバージョンに従って、ブラウザの互換性情報が表示されます。JavaScriptの「オプション」パネルを開くには、「ツール」>「オプション」(Macの場合は「NetBeans」>「プリファレンス」)を選択してから「その他」>「JavaScript」を選択します。

JavaScriptの「オプション」パネル

IDEでは、Firefox、Internet Explorer、Safari、およびOperaをデフォルトでサポートしています。JavaScriptの「オプション」パネルでは、コード補完を適用するJavaScriptエンジンのバージョンを指定することもできます。

アプリケーションにJavaScriptファイルを追加し、doCompletion()の実装を始めます。

  1. 「プロジェクト」ウィンドウでプロジェクト・ノードを右クリックし、「新規」>「JavaScriptファイル」を選択します。(「JavaScriptファイル」がリストにない場合は「その他」を選択します。次に、新規ファイル・ウィザードで「その他」カテゴリから「JavaScriptファイル」を選択します。)
  2. ファイル名をjavascriptにし、「終了」をクリックします。新しいJavaScriptファイルが「プロジェクト」ウィンドウに表示され、エディタで開きます。
  3. 次のコードをjavascript.jsに入力します。
    var req;
    var isIE;
    
    function init() {
        completeField = document.getElementById("complete-field");
    }
    
    function doCompletion() {
            var url = "autocomplete.php?action=complete&id=" + escape(completeField.value);
            req = initRequest();
            req.open("GET", url, true);
            req.onreadystatechange = callback;
            req.send(null);
    }
    
    function initRequest() {
        if (window.XMLHttpRequest) {
            if (navigator.userAgent.indexOf('MSIE') != -1) {
                isIE = true;
            }
            return new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            isIE = true;
            return new ActiveXObject("Microsoft.XMLHTTP");
        }
    }
    

    上のコードは、Firefox 3およびInternet Explorerバージョン6と7の単純なブラウザ互換性チェックを行います。互換性の問題に対してさらに堅牢なコードを取り込むには、http://www.quirksmode.orgブラウザ検出スクリプトを使用することを検討してください。

  4. index.htmlに戻り、JavaScriptファイルへの参照を<head>タグの間に追加します。
    <script type="text/javascript" src="javascript.js"></script>
    

    [Ctrl]-[Tab]を押すと、エディタ内で開いているページを簡単に切り替えることができます。

  5. init()へのコールを開始<body>タグ内に挿入します。
    <body onload="init()">
    
    このようにすると、ページがロードされるたびにinit()がコールされます。

doCompletion()には次の役割があります。

  • サーバー側で利用できるデータを含むURLを作成すること
  • XMLHttpRequestオブジェクトを初期化すること
  • 非同期リクエストをサーバーに送信するようにXMLHttpRequestオブジェクトに要求すること

XMLHttpRequestオブジェクトはAjaxの中核であり、HTTPを使用してXMLデータを非同期で送信するときの事実上の標準になっています。相互作用が非同期であるということは、リクエストの送信後にブラウザではページ内で引続きイベントを処理できることを意味します。データはバックグラウンドで送信され、ページをリフレッシュしないで自動的にページにロードできます。

XMLHttpRequestオブジェクトは実際にはinitRequest()で作成し、これはdoCompletion()からコールされます。この関数では、ブラウザでXMLHttpRequestを認識できるかどうかを確認し、認識できる場合はXMLHttpRequestオブジェクトを作成します。そうでない場合は、ActiveXObject (Internet Explorer 6でXMLHttpRequestに相当する)を確認し、識別された場合はActiveXObjectを作成します。

相互作用が非同期であるかどうかに関係なく、XMLHttpRequestオブジェクトを作成するときは、URL、HTTPメソッド(GETまたはPOST)の3つのパラメータを指定します。前述の例では、これらのパラメータは次のとおりです。

  • URL autocomplete.php、およびユーザーがcomplete-fieldに入力したテキスト
    var url = "autocomplete.php?action=complete&id=" + escape(completeField.value);
  • GET (HTTPの相互作用でGETメソッドを使用することを示します)
  • true (相互作用は非同期であることを示します)
    req.open("GET", url, true);

相互作用を非同期に設定する場合は、コールバック関数を指定します。この相互作用のコールバック関数は次の文で設定します。

req.onreadystatechange = callback;

そして、callback()関数を後で定義する必要があります。HTTPの相互作用はXMLHttpRequest.send()のコール時に開始します。このアクションは、前述のフロー図でWebサーバーに送信されているHTTPリクエストに対応します。


サーバー側のプログラミング

NetBeans IDEでは、PHPを使用したWeb開発が総合的にサポートされています。*AMPパッケージを使用して開発環境を設定し、IDEで短時間で効率よく編集とデプロイができます。IDEでは、ローカル・サーバーに加えて、FTPまたはSFTPを使用してリモートでも環境を構成できます。また、XDebugなど外部のデバッガを構成し、IDEの「PHPオプション」ウィンドウから(「ツール」>「オプション」を選択、Macの場合は「NetBeans」>「プリファレンス」を選択し、「PHP」タブを選択)、PHPUnitを使用した単体テストを設定できます。PHPエディタには、コード補完、構文の強調表示、出現箇所のマーク、リファクタリング、コード・テンプレート、ドキュメントのポップアップ、コード・ナビゲーション、エディタの警告、およびNetBeans 6.9の場合は形式の不正な構文のエラー・バッジなどの、標準の編集機能があります。PHPのサポートのスクリーンキャストについては、NetBeansのビデオ・チュートリアルとデモのページを参照してください。

アプリケーションにデータベースが必要な場合、IDEでは、ほとんどの主要なデータベース、特にMySQLがサポートされています。詳細は、NetBeansのMySQLのスクリーンキャストデータベース統合の説明を参照してください。

ここでビルドしているオートコンプリート・アプリケーションのビジネス・ロジックでは、データ・ストアからデータを取り出してリクエストを処理し、レスポンスを作成して送信する必要があります。これは、autocompleteという名前のPHPファイルを使用して、ここで実装します。ファイルのコーディングを始める前に、データ・ストアと、ファイルからデータにアクセスするために必要な機能を設定します。

データ・ストアの作成

この単純なアプリケーションでは、ビジネス・ロジックでcomposers配列に含まれるエントリからデータを取得できるようにするComposerというクラスを作成します。次に、その配列を使用して作曲家のデータを保持するComposerDataというクラスを作成します。

  1. 「プロジェクト」ウィンドウで「MyAjaxApp」プロジェクト・ノードを右クリックし、「新規」>「PHPクラス」を選択します。
  2. クラス名をComposerにし、「終了」をクリックします。クラスが作成され、エディタで開きます。
  3. 次のコードをクラス内に貼り付けます(変更箇所は太字で表示)。
    <?php
    
    class Composer {
    
        public $id;
        public $firstName;
        public $lastName;
        public $category;
    
        function __construct($id, $firstName, $lastName, $category) {
            $this->id = $id;
            $this->firstName = $firstName;
            $this->lastName = $lastName;
            $this->category = $category;
        }
    }
    
    ?>

ComposerDataクラスを作成します。

  1. 「プロジェクト」ウィンドウで「MyAjaxApp」プロジェクト・ノードを右クリックし、「新規」>「PHPクラス」を選択します。
  2. クラス名をComposerDataにし、「終了」をクリックします。クラスが作成され、IDEのエディタで開きます。
  3. require文をクラスの先頭に追加し、作成したComposer.phpクラスをこのクラスが要求するように指定します(変更箇所は太字で表示)。
    <?php
    
    require "Composer.php";
    
    class ComposerData {
    
    }
  4. エディタで、次のコードをクラス内に貼り付けます(変更箇所は太字で表示)。
    <?php
    
    require "Composer.php";
    
    class ComposerData {
    
        public $composers;
    
        function __construct() {
            $this->composers = array(
                new Composer("1", "Johann Sebastian", "Bach", "Baroque"),
                new Composer("2", "Arcangelo", "Corelli", "Baroque"),
                new Composer("3", "George Frideric", "Handel", "Baroque"),
                new Composer("4", "Henry", "Purcell", "Baroque"),
                new Composer("5", "Jean-Philippe", "Rameau", "Baroque"),
                new Composer("6", "Domenico", "Scarlatti", "Baroque"),
                new Composer("7", "Antonio", "Vivaldi", "Baroque"),
    
                new Composer("8", "Ludwig van", "Beethoven", "Classical"),
                new Composer("9", "Johannes", "Brahms", "Classical"),
                new Composer("10", "Francesco", "Cavalli", "Classical"),
                new Composer("11", "Fryderyk Franciszek", "Chopin", "Classical"),
                new Composer("12", "Antonin", "Dvorak", "Classical"),
                new Composer("13", "Franz Joseph", "Haydn", "Classical"),
                new Composer("14", "Gustav", "Mahler", "Classical"),
                new Composer("15", "Wolfgang Amadeus", "Mozart", "Classical"),
                new Composer("16", "Johann", "Pachelbel", "Classical"),
                new Composer("17", "Gioachino", "Rossini", "Classical"),
                new Composer("18", "Dmitry", "Shostakovich", "Classical"),
                new Composer("19", "Richard", "Wagner", "Classical"),
    
                new Composer("20", "Louis-Hector", "Berlioz", "Romantic"),
                new Composer("21", "Georges", "Bizet", "Romantic"),
                new Composer("22", "Cesar", "Cui", "Romantic"),
                new Composer("23", "Claude", "Debussy", "Romantic"),
                new Composer("24", "Edward", "Elgar", "Romantic"),
                new Composer("25", "Gabriel", "Faure", "Romantic"),
                new Composer("26", "Cesar", "Franck", "Romantic"),
                new Composer("27", "Edvard", "Grieg", "Romantic"),
                new Composer("28", "Nikolay", "Rimsky-Korsakov", "Romantic"),
                new Composer("29", "Franz Joseph", "Liszt", "Romantic"),
    
                new Composer("30", "Felix", "Mendelssohn", "Romantic"),
                new Composer("31", "Giacomo", "Puccini", "Romantic"),
                new Composer("32", "Sergei", "Rachmaninoff", "Romantic"),
                new Composer("33", "Camille", "Saint-Saens", "Romantic"),
                new Composer("34", "Franz", "Schubert", "Romantic"),
                new Composer("35", "Robert", "Schumann", "Romantic"),
                new Composer("36", "Jean", "Sibelius", "Romantic"),
                new Composer("37", "Bedrich", "Smetana", "Romantic"),
                new Composer("38", "Richard", "Strauss", "Romantic"),
                new Composer("39", "Pyotr Il'yich", "Tchaikovsky", "Romantic"),
                new Composer("40", "Guiseppe", "Verdi", "Romantic"),
    
                new Composer("41", "Bela", "Bartok", "Post-Romantic"),
                new Composer("42", "Leonard", "Bernstein", "Post-Romantic"),
                new Composer("43", "Benjamin", "Britten", "Post-Romantic"),
                new Composer("44", "John", "Cage", "Post-Romantic"),
                new Composer("45", "Aaron", "Copland", "Post-Romantic"),
                new Composer("46", "George", "Gershwin", "Post-Romantic"),
                new Composer("47", "Sergey", "Prokofiev", "Post-Romantic"),
                new Composer("48", "Maurice", "Ravel", "Post-Romantic"),
                new Composer("49", "Igor", "Stravinsky", "Post-Romantic"),
                new Composer("50", "Carl", "Orff", "Post-Romantic"),
            );
        }
    }
    
    ?>
    

ビジネス・ロジックの作成

受信リクエストによって受け取るautocomplete URLを処理するロジックを実装します。前の項で説明したように、ファイル・ウィザードを使用して新しいPHPファイルを作成するかわりに、ここでは既存のindex.phpファイルを変更します。

  1. 「プロジェクト」ウィンドウでindex.phpファイル・ノードをクリックします。ファイル名が編集可能になり、名前を変更できるようになります。
    編集可能なファイル名が表示された「プロジェクト」ウィンドウ
  2. ファイル名をautocompleteにし、[Enter]を押します。新しいautocomplete.phpファイルをダブルクリックし、エディタに表示します。
  3. このファイルの既存のコードを次のスクリプトに置き換えます。
    <?php
    
    require_once("ComposerData.php");
    
    session_start();
    
    $composerData = new ComposerData();
    $composers = $composerData->composers;
    
    $results = array();
    $namesAdded = false;
    
    // simple matching for start of first or last name, or both
    if(isset($_GET['action']) && $_GET['action'] == "complete") {
        foreach($composers as $composer) {
            if(!is_numeric($_GET['id']) &&
    
                // if id matches first name
                (stripos($composer->firstName, $_GET['id']) === 0 ||
    
                // if id matches last name
                stripos($composer->lastName, $_GET['id']) === 0) ||
    
                // if id matches full name
                stripos($composer->firstName." ".$composer->lastName, $_GET['id']) === 0) {
    
                    $results[] = $composer;
            }
        }
    
        // prepare xml data
        if(sizeof($results) != 0) {
            header('Content-type: text/xml');
            echo "<composers>";
            foreach($results as $result) {
                echo "<composer>";
                echo "<id>" . $result->id . "</id>";
                echo "<firstName>" . $result->firstName . "</firstName>";
                echo "<lastName>" . $result->lastName . "</lastName>";
                echo "</composer>";
            }
            echo "</composers>";
        }
    }
    
    // if user chooses from pop-up box
    if(isset($_GET['action']) && isset($_GET['id']) && $_GET['action'] == "lookup") {
        foreach($composers as $composer) {
            if($composer->id == $_GET['id']) {
                $_SESSION ["id"] = $composer->id;
                $_SESSION ["firstName"] = $composer->firstName;
                $_SESSION ["lastName"] = $composer->lastName;
                $_SESSION ["category"] = $composer->category;
    
                header("Location: composerView.php");
            }
        }
    }
    
    ?>

注意: composerView.phpファイルについては、このチュートリアルでは説明しません。そのようなファイルを作成して検索の最終結果を確認できます。ファイルのサンプルは、sample applicationに含まれています。

このように、Ajax処理用のサーバー側コードを記述するために新たに学習することはありません。XMLドキュメントを交換する場合は、レスポンスのコンテンツ・タイプをtext/xmlに設定します。Ajaxでは、プレーン・テキストを交換でき、クライアントのコールバック関数によって評価または実行できるJavaScriptのスニペットを交換することもできます。一部のブラウザでは結果がキャッシュに保存される場合があるので、Cache-Control HTTPヘッダーをno-cacheに設定する必要がある場合もあります。

この例では、autocomplete.phpファイルによってXMLドキュメントが生成され、このXMLドキュメントには、名または姓のいずれかがユーザーが入力した文字で始まる作曲家がすべて含まれています。このドキュメントは、前述のフロー図に示すXMLデータに対応します。XMLHttpRequestオブジェクトに返されるXMLドキュメントの例を示します。

<composers>
    <composer>
        <id>12</id>
        <firstName>Antonin</firstName>
        <lastName>Dvorak</lastName>
    </composer>
    <composer>
        <id>45</id>
        <firstName>Aaron</firstName>
        <lastName>Copland</lastName>
    </composer>
    <composer>
        <id>7</id>
        <firstName>Antonio</firstName>
        <lastName>Vivaldi</lastName>
    </composer>
    <composer>
        <id>2</id>
        <firstName>Arcangelo</firstName>
        <lastName>Corelli</lastName>
    </composer>
</composers>

クライアント側のプログラミング: 第2部

サーバーのレスポンスを処理するコールバック関数を定義し、ユーザーに表示するページに変更を反映するために必要な機能を追加する必要があります。そのためには、HTMLのDOMを変更する必要があります。最後に、IDEのCSSエディタを使用して、単純なスタイル・シートをプレゼンテーションに追加できます。

コールバック機能の追加

コールバック関数は、HTTPの相互作用中にXMLHttpRequestオブジェクトの「readyState」プロパティが変化したとき、非同期でコールされます。ここでビルドしているアプリケーションでは、コールバック関数はcallback()です。doCompletion()では、callbackを関数の「XMLHttpRequest.onreadystatechange」プロパティとして設定しました。ここで、コールバック関数を次のように実装します。

  1. javascript.jsをエディタで開き、次のコードを入力します。
    function callback() {
        if (req.readyState == 4) {
            if (req.status == 200) {
                parseMessages(req.responseXML);
            }
        }
    }
    

readyStateが「4」のとき、HTTPの相互作用は完了しています。XMLHttpRequest.readStateのAPIは、設定できる値が5つあることを示します。これらを次に示します。

readyStateの値 オブジェクト・ステータスの定義
0 非初期化
1 ロード中
2 ロード済
3 対話式
4 完了

parseMessages()関数は、XMLHttpRequest.readyStateが「4」で、status (リクエストのHTTPステータス・コード定義)が「200」、つまり成功の場合にのみコールされます。parseMessages()は、次のHTML DOMの更新で定義します。

HTML DOMの更新

受信するXMLデータはparseMessages()関数で処理します。このとき、appendComposer()getElementY()、およびclearTable()などの補助的関数を使用します。また、オートコンプリート・ボックスとして機能する2番目のHTML表、要素をjavascript.jsで参照可能にするための要素のIDなど、新しい要素をindexページに追加する必要があります。最後に、index.php内の要素のIDに対応する新しい変数を作成し、前に実装したinit()関数で初期化し、index.phpがロードされるたびに必要とされる機能を追加します。

注意: 次の手順で作成する関数と要素は、相互に依存して動作します。この項の手順を最後まで行い、コードが完成してからその内容を確認することをお薦めします。

  1. index.htmlをエディタで開き、前に作成したHTML表の2行目として次のコードを入力します。
    <tr>
        <td id="auto-row" colspan="2">
    
        <td/>
    </tr>
    この新しい行は「auto-row」として識別でき、オートコンプリート・ボックスを形成する新しいHTML表を挿入するための、JavaScriptコード用のハンドルの役割を果たします。
  2. javascript.jsをエディタで開き、次の3つの変数をファイルの先頭に追加します。
    var completeField;
    var completeTable;
    var autoRow;
  3. 次の太字の行をinit()関数に追加します。
    function init() {
        completeField = document.getElementById("complete-field");
        completeTable = document.createElement("table");
        completeTable.setAttribute("class", "popupBox");
        completeTable.setAttribute("style", "display: none");
        autoRow = document.getElementById("auto-row");
        autoRow.appendChild(completeTable);
        completeTable.style.top = getElementY(autoRow) + "px";
    }
    init()の目的の1つは、indexページのDOMを変更する他の関数からindex.html内の要素にアクセスできるようにすることです。上記のスクリプトは、新しいHTMLを作成し、popupBoxクラスを追加して、要素のスタイルをdisplay: noneに変更します。最後に、idauto-rowである要素を取得し、ここに新しいを挿入します。つまり、このコードを実行するときには、変更されたHTMLは次のようになります。
    <tr>
        <td id="auto-row" colspan="2">
            <table class="popupBox" style="display: none"></table>
        <td/>
    </tr>
  4. appendComposer()javascript.jsに追加します。
    function appendComposer(firstName,lastName,composerId) {
    
        var row;
        var cell;
        var linkElement;
    
        if (isIE) {
            completeTable.style.display = 'block';
            row = completeTable.insertRow(completeTable.rows.length);
            cell = row.insertCell(0);
        } else {
            completeTable.style.display = 'table';
            row = document.createElement("tr");
            cell = document.createElement("td");
            row.appendChild(cell);
            completeTable.appendChild(row);
        }
    
        cell.className = "popupCell";
    
        linkElement = document.createElement("a");
        linkElement.className = "popupItem";
        linkElement.setAttribute("href", "autocomplete.php?action=lookup&id=" + composerId);
        linkElement.appendChild(document.createTextNode(firstName + " " + lastName));
        cell.appendChild(linkElement);
    }
    この関数は、表の新しい行を作成し、3つのパラメータによって関数に渡されたデータを使用して作曲家へのリンクを挿入してから、行をindexページのcomplete-table要素に挿入します。
  5. clearTable()javascript.jsに追加します。
    function clearTable() {
        if (completeTable.getElementsByTagName("tr").length > 0) {
            completeTable.style.display = 'none';
            for (loop = completeTable.childNodes.length -1; loop >= 0 ; loop--) {
                completeTable.removeChild(completeTable.childNodes[loop]);
            }
        }
    }
    この関数はcomplete-table要素の表示を'none'に設定し(非表示にし)、作成された既存の作曲家の名前エントリを除去します。
  6. getElementY()javascript.jsに追加します。
    function getElementY(element){
    
        var targetTop = 0;
    
        if (element.offsetParent) {
            while (element.offsetParent) {
                targetTop += element.offsetTop;
                element = element.offsetParent;
            }
        } else if (element.y) {
            targetTop += element.y;
        }
        return targetTop;
    }
    この関数は、親要素の縦方向表示位置を見つけるために適用します。これは、要素の実際の表示位置はブラウザのタイプとバージョンによって異なることが多いため必要です。complete-table要素は、作曲家の名前が表示されるときに、この要素が存在する表の右下にシフトします。正しい縦方向の配置はgetElementY()で決まります。

    注意: http://www.quirksmode.org/にあるoffsetに関する説明を参照してください。

  7. callback()関数を変更して、サーバーから新しいデータを受け取るたびにclearTable()をコールするようにします。オートコンプリート・ボックスに作曲家のエントリがある場合は、新しいエントリが入力される前に除去されます。
    function callback() {
    
        clearTable();
    
        if (req.readyState == 4) {
            if (req.status == 200) {
                parseMessages(req.responseXML);
            }
        }
    }
  8. parseMessages()javascript.jsに追加します。
    function parseMessages(responseXML) {
    
        // no matches returned
        if (responseXML == null) {
            return false;
        } else {
    
            var composers = responseXML.getElementsByTagName("composers")[0];
    
            if (composers.childNodes.length > 0) {
                completeTable.setAttribute("bordercolor", "black");
                completeTable.setAttribute("border", "1");
    
                for (loop = 0; loop < composers.childNodes.length; loop++) {
                    var composer = composers.childNodes[loop];
                    var firstName = composer.getElementsByTagName("firstName")[0];
                    var lastName = composer.getElementsByTagName("lastName")[0];
                    var composerId = composer.getElementsByTagName("id")[0];
                    appendComposer(firstName.childNodes[0].nodeValue,
                        lastName.childNodes[0].nodeValue,
                        composerId.childNodes[0].nodeValue);
                }
            }
        }
    }

parseMessages()関数は、autocomplete.phpファイルから返されるXMLドキュメントのオブジェクト表現をパラメータとして受け取ります。この関数はプログラムでXMLドキュメント内を横断し、各エントリのfirstNamelastName、およびidを抽出して、このデータをappendComposer()に渡します。その結果、complete-table要素の内容が動的に更新されます。たとえば、次のようなエントリが生成され、complete-tableに挿入されます。

<tr>
    <td class="popupCell">
        <a class="popupItem" href="autocomplete?action=lookup&id=12">Antonin Dvorak</a>
    </td>
</tr>

complete-table要素の動的な更新は、Ajaxを使用して行われる通信のプロセス・フローの中で最後の手順を表します。この更新は、前述のフロー図のプレゼンテーションに送信されるHTMLとCSSデータに対応します。

スタイル・シートの添付

これで、アプリケーションの機能に必要なコードが完成しました。作業の結果を確認するため、今すぐアプリケーションを実行してみてください。

  1. プロジェクトを実行して、ブラウザでどのように表示されるかを確認します。「プロジェクトの実行」(「プロジェクトの実行」ボタン)ボタンをクリックします。index.htmlファイルがブラウザに表示されます。
    スタイル・シートなしでブラウザに表示されたアプリケーション

アプリケーションにスタイル・シートを添付するには、CSS (Cascading Style Sheet)ファイルを作成し、プレゼンテーション・ページからそのファイルにリンクします。CSSファイルで作業する場合、IDEには、コード補完サポートや、スタイル・シート・ルールの作成に役立つ他のいくつかの機能が提供されています。これには次のものが含まれています。

  • CSSスタイル・ビルダー: 選択したコントロールやウィジェットを使用してルールを作成できるように設計されたインタフェースです(「ウィンドウ」>「その他」>「CSSスタイル・ビルダー」)。
  • CSSプレビュー: ルール内にカーソルを置くと、そのルールの宣言ブロックに従ってサンプル・テキストがレンダリングされるプレビュー・ウィンドウです(「ウィンドウ」>「その他」>「CSSプレビュー」)。
  • スタイル・ルール・エディタ: クラス、ID、HTML要素に基づいてルールを作成し、ドキュメント階層における位置を設定できるダイアログです(CSSエディタのツールバーの左上側にある「ルールを作成」(スタイル・ルール・エディタ)ボタン)。

NetBeans 6.9は、「名前の変更のリファクタリング」機能と「使用状況を検索」機能をサポートしています。これは、CSSファイルのみでなく、CSSコードが埋め込まれているすべてのファイルでサポートされます(HTML、PHPなど)。CSSのクラス、ID、およびタイプ要素を、すべてのプロジェクト・ファイルでリファクタリングできます。このリファクタリングのサポートを利用するには、任意のCSS要素上で[Ctrl]-[R]を押し、表示されたダイアログで名前変更アクションを実行します。また、名前変更アクションを実行する前に、変更をプレビューすることもできます。「使用状況を検索」機能のサポートを利用するには、CSS要素を右クリックし、「使用状況を検索」を選択します。詳細は、NewAndNoteworthy69m1を参照してください。

スタイル・シートをアプリケーションに添付するには、次の手順を行います:

  1. 「プロジェクト」ウィンドウでプロジェクト・ノードを右クリックし、「新規」>「Cascading Style Sheet」を選択します(「Cascading Style Sheet」が表示されない場合は、「その他」を選択します。次に、新規ファイル・ウィザードで「その他」カテゴリから「Cascading Style Sheet」を選択します。)
  2. 「CSSファイル名」テキスト・フィールドに、「stylesheet」と入力します。
  3. 「終了」をクリックします。新しいファイルが「プロジェクト」ウィンドウに追加され、IDEのエディタで開きます。
  4. stylesheet.cssに、次のルールを入力します。IDEのコード補完サポートを利用するには、候補を呼び出したい場所で[Ctrl]-[Space]を押します。
    body {
       font-family: sans-serif;
       font-size: smaller;
       padding: 50px;
       color: #555;
       width: 650px;
    }
    
    h1 {
       letter-spacing: 6px;
       font-size: 1.6em;
       color: #be7429;
       font-weight: bold;
    }
    
    h2 {
       text-align: left;
       letter-spacing: 6px;
       font-size: 1.4em;
       color: #be7429;
       font-weight: normal;
       width: 450px;
    }
    
    table {
       width: 550px;
       padding: 10px;
       background-color: #c5e7e0;
    }
    
    td {
       padding: 10px;
    }
    
    a {
      color: #be7429;
      text-decoration: none;
    }
    
    a:hover {
      text-decoration: underline;
    }
    
    .popupBox {
      position: absolute;
      top: 170px;
      left: 140px;
    }
    
    .popupCell {
       background-color: #fffafa;
    }
    
    .popupCell:hover {
      background-color: #f5ebe9;
    }
    
    .popupItem {
      color: #333;
      text-decoration: none;
      font-size: 1.2em;
    }

    CSSエディタ内を右クリックして「CSSの確認」を選択し、CSSコードの妥当性のチェックを実行します。エラーがあった場合は「出力」ウィンドウ(「ウィンドウ」>「出力」)に表示されます。

  5. 「ウィンドウ」>「その他」>「CSSプレビュー」を選択し、「CSSプレビュー」ウィンドウを開きます。
  6. テキストと色を調整するルール内にカーソルを置きます(たとえばh1)。「CSSプレビュー」ウィンドウに、テキストがブラウザにどのようにレンダリングされるかを示すサンプル表示が生成されます。
    h1ルールのサンプル・テキストが表示された「CSSプレビュー」ウィンドウ
  7. エディタでindex.htmlページに切り替え([Ctrl]-[Tab]を押します)、<head>タグの間にスタイル・シートへの参照を追加します。
    <link rel="stylesheet" type="text/css" href="stylesheet.css">
    
  8. アプリケーションをもう一度実行します。インデックス・ページが、作成したスタイル・シートを使用してブラウザに表示されます。文字を入力するたびに非同期のリクエストがサーバーに送信され、autocomplete.phpによって作成されたXMLデータが返されます。さらに文字を入力すると、新しい一致リストを反映して作曲家の名前の数が減ります。

まとめ

これでAjax入門を終了します。ここでは、Ajaxは単にHTTPを使用してバックグラウンドで情報を交換し、その結果に基づいてページを動的に更新していることを学習しました。

ここでビルドしたアプリケーションは、オートコンプリート・ボックスで作曲家の名前を選択しても何も起こらないなど、完全ではありません。サンプル・アプリケーションをダウンロードすると、PHPテクノロジを使用して、これを実装する方法を確認できます。また、ユーザーがデータ・ストアにない名前をリクエストしないように検証する方法を検討することもできます。これらの手法については、NetBeansのPHPの学習にある他のチュートリアルで紹介しています。


関連項目

netbeans.orgでのAjaxおよびPHPテクノロジの詳細は、次のリソースを参照してください。

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo