<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 24249 -->
<sect1 id="zend.amf.server">
    <title>Zend_Amf_Server(日本語)</title>

    <para>
        <classname>Zend_Amf_Server</classname> は <acronym>RPC</acronym> スタイルのサーバで、
        Adobe Flash Player からの <acronym>AMF</acronym> プロトコルによるリクエストを処理します。
        他の Zend Framework のサーバクラス群と同様に SoapServer <acronym>API</acronym> にしたがっており、
        サーバを作成するための習得しやすいインターフェイスを提供します。
    </para>

    <example id="zend.amf.server.basic">
        <title>基本的な AMF サーバ</title>

        <para>
            さまざまな public メソッドを持つクラス <classname>Foo</classname>
            を作ったものとしましょう。<acronym>AMF</acronym> サーバを作成するためのコードは次のようになります。
        </para>

        <programlisting language="php"><![CDATA[
$server = new Zend_Amf_Server();
$server->setClass('Foo');
$response = $server->handle();
echo $response;
]]></programlisting>

        <para>
            もうひとつの方法として、単純な関数をコールバックとしてアタッチすることもできます。
        </para>

        <programlisting language="php"><![CDATA[
$server = new Zend_Amf_Server();
$server->addFunction('myUberCoolFunction');
$response = $server->handle();
echo $response;
]]></programlisting>

        <para>
            複数のクラスや関数を混ぜて使用することもできます。
            その場合は、それぞれに名前空間を指定してメソッド名の衝突を回避させることをおすすめします。
            名前空間を指定するには、<methodname>addFunction()</methodname> あるいは
            <methodname>setClass()</methodname> の 2 番目の引数に文字列を指定します。
        </para>

        <programlisting language="php"><![CDATA[
$server = new Zend_Amf_Server();
$server->addFunction('myUberCoolFunction', 'my')
       ->setClass('Foo', 'foo')
       ->setClass('Bar', 'bar');
$response = $server->handle();
echo $response;
]]></programlisting>

        <para>
        <classname>Zend Amf Server</classname> は、
        指定したディレクトリパスから動的にサービスに読み込ませることもできます。
        好きなだけのディレクトリをサーバに指定することが可能です。
        サーバに後から追加したディレクトリから順に (<acronym>LIFO</acronym>: 後入れ先出し)
        検索を行い、クラスにマッチするディレクトリを探します。
        ディレクトリの追加は <methodname>addDirectory()</methodname> メソッドで行います。
        </para>

        <programlisting language="php"><![CDATA[
$server->addDirectory(dirname(__FILE__) .'/../services/');
$server->addDirectory(dirname(__FILE__) .'/../package/');
]]></programlisting>

        <para>
        リモートサービスをコールする際には、アンダースコア ("_") およびドット
        (".") をディレクトリ区切り文字として使用します。
        アンダースコアを使用すると、<acronym>PEAR</acronym> や
        Zend Framework のクラス命名規約に従った形式となります。
        つまり、サービス com_Foo_Bar をコールした場合は、
        インクルードされたパスのどこかにある
        <filename>com/Foo/Bar.php</filename> を探します。ドット記法を使用してリモートサービスを
        <filename>com.Foo.Bar</filename> のように指定すると、
        インクルードされたパスの最後に <filename>com/Foo/Bar.php</filename>
        を追加して <filename>Bar.php</filename> を自動的に読み込みます。
        </para>

        <para>
            スクリプトに送られたすべての <acronym>AMF</acronym> リクエストがサーバで処理され、
            その結果の <acronym>AMF</acronym> レスポンスが返されます。
        </para>
    </example>

    <note>
        <title>アタッチされるすべてのメソッドや関数には docblock が必要</title>

        <para>
            Zend Framework の他のサーバコンポーネント群と同様、クラスのメソッドには
            <acronym>PHP</acronym> docblock 形式のドキュメントが必要です。
            少なくとも必須引数と返り値についてのアノテーションが必要となります。
            次の例をごらんください。
        </para>

        <programlisting language="php"><![CDATA[
// アタッチする関数

/**
 * @param  string $name
 * @param  string $greeting
 * @return string
 */
function helloWorld($name, $greeting = 'Hello')
{
    return $greeting . ', ' . $name;
}
]]></programlisting>

        <programlisting language="php"><![CDATA[
// アタッチするクラス

class World
{
    /**
     * @param  string $name
     * @param  string $greeting
     * @return string
     */
    public function hello($name, $greeting = 'Hello')
    {
        return $greeting . ', ' . $name;
    }
}
]]></programlisting>

        <para>
            その他のアノテーションを使用することもできますが、無視されます。
        </para>
    </note>

    <sect2 id="zend.amf.server.flex">
        <title>サーバへの Flex からの接続</title>

        <para>
            <classname>Zend_Amf_Server</classname> に Flex プロジェクトから接続するのはきわめて簡単です。
            エンドポイントの <acronym>URI</acronym> を
            <classname>Zend_Amf_Server</classname> スクリプトに指定するだけでよいのです。
        </para>

        <para>
            たとえば、作成したサーバをアプリケーションルートに
            <filename>server.php</filename> という名前で配置したとしましょう。<acronym>URI</acronym> は
            <filename>http://example.com/server.php</filename> となります。
            この場合は、services-config.xml ファイルを編集して、
            チャンネルのエンドポイント URI 属性をこの値に変更します。
        </para>

        <para>
            まだ <filename>service-config.xml</filename> ファイルを作っていない場合は、
            まずナビゲータウィンドウでプロジェクトを開きます。
            そしてプロジェクト名のところを右クリックして 'プロパティ' を選択します。
            プロジェクトのプロパティダイアログで 'Flex ビルドパス' を選択し、
            'ライブラリパス' タブで '<filename>rpc.swc</filename>'
            ファイルがプロジェクトに追加されていることを確認したら、
            OK を押してウィンドウを閉じます。
        </para>

        <para>
            また、リモートオブジェクトのエンドポイントを探す際に <filename>service-config.xml</filename>
            を使用することをコンパイラに指定する必要もあります。
            ナビゲータのプロジェクトフォルダを右クリックしてプロパティを選択し、
            もういちどプロジェクトのプロパティパネルを開きます。
            そこで 'Flex コンパイラ' を選択して、
            <command>-services "services-config.xml"</command> を追加します。
            適用、そして OK を押してオプションを更新します。
            これで結局何をやったのかというと、実行時の変数を
            <filename>services-config.xml</filename> から読み込んで RemotingObject クラスで使うよう
            Flex コンパイラに指示したということです。
        </para>

        <para>
            それから、リモートメソッドへの接続の際に使用するサービス設定ファイルを
            Flex に教えてやる必要があります。そこで、Flex プロジェクトの src フォルダに
            '<filename>services-config.xml</filename>' ファイルを新たに作成します。
            プロジェクトフォルダで右クリックして '新規作成' 'ファイル'
            を選択すると新しいウィンドウが開きます。プロジェクトフォルダを選択し、
            ファイル名を '<filename>services-config.xml</filename>' と指定して終了を押します。
        </para>

        <para>
            Flex は新しい <filename>services-config.xml</filename> ファイルを作成し、それを開きます。
            次の例のとおりに <filename>services-config.xml</filename> ファイルを作成してください。
            エンドポイントの部分はあなたが使用するサーバに書き換えます。
            そしてファイルを保存することを忘れないようにしましょう。
        </para>

        <programlisting language="xml"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service id="zend-service"
            class="flex.messaging.services.RemotingService"
            messageTypes="flex.messaging.messages.RemotingMessage">
            <destination id="zend">
                <channels>
                    <channel ref="zend-endpoint"/>
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    <channels>
        <channel-definition id="zend-endpoint"
            class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://example.com/server.php"
                class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
    </channels>
</services-config>
]]></programlisting>

        <para>
            この例にはポイントがふたつあります。まず
            <acronym>AMF</acronym> チャネルを作成し、そしてエンドポイントの <acronym>URL</acronym> を
            <classname>Zend_Amf_Server</classname> に指定します。
        </para>

        <programlisting language="xml"><![CDATA[
<channel-definition id="zend-endpoint"
    <endpoint uri="http://example.com/server.php"
        class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
]]></programlisting>

        <para>
            このチャネルの ID として "zend-endpoint" を指定したことに注意しましょう。
            この例では、このチャネルを指すサービスを作成して、その ID を指定しました。
            この場合の ID は "zend" となります。
        </para>

        <para>
            Flex の <acronym>MXML</acronym> ファイルで、
            RemoteObject をサービスにバインドしなければなりません。
            <acronym>MXML</acronym> で次のように記述します。
        </para>

        <programlisting language="xml"><![CDATA[
<mx:RemoteObject id="myservice"
    fault="faultHandler(event)"
    showBusyCursor="true"
    destination="zend">
]]></programlisting>

        <para>
            ここでは、新しいリモートオブジェクトに "myservice" という名前をつけ、
            さきほど <filename>services-config.xml</filename> で定義した "zend"
            にそれをバインドしています。ActionScript からメソッドをコールするには、
            "myservice.&lt;method&gt;" とするだけです。例を示します。
        </para>

        <programlisting language="ActionScript"><![CDATA[
myservice.hello("Wade");
]]></programlisting>

        <para>
            名前空間を使う場合は
            "myservice.&lt;namespace&gt;.&lt;method&gt;" のようにします。
        </para>

        <programlisting language="ActionScript"><![CDATA[
myservice.world.hello("Wade");
]]></programlisting>

        <para>
            Flex RemoteObject の実行についてのより詳細な情報は <ulink
                url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">
            Adobe Flex 3 のヘルプサイト</ulink> をごらんください。
        </para>
    </sect2>

    <sect2 id="zend.amf.server.errors">
        <title>エラー処理</title>

        <para>
            デフォルトでは、アタッチしたクラスや関数からスローされた例外はすべて捕捉され、
            <acronym>AMF</acronym> ErrorMessage として返されます。しかし、この ErrorMessage
            オブジェクトの中身は、サーバが "production" モード (デフォルトの状態)
            であるか否かによって異なります。
        </para>

        <para>
            production モードの場合は、例外コードのみが返されます。
            production モードを無効にする (これはテスト時にしか行ってはいけません)
            と、例外についての詳細が返されるようになり、
            例外メッセージや行番号、バックトレースがすべて返されます。
        </para>

        <para>
            production モードを無効にするには、次のようにします。
        </para>

        <programlisting language="php"><![CDATA[
$server->setProduction(false);
]]></programlisting>

        <para>
            再度有効にするには、<constant>TRUE</constant> を渡します。
        </para>

        <programlisting language="php"><![CDATA[
$server->setProduction(true);
]]></programlisting>

        <note>
            <title>production モードの無効化は慎重に!</title>

            <para>
                production モードを無効にするのは、開発時のみにすることを推奨します。
                例外メッセージやバックトレースにはシステムに関する重大な情報が含まれる可能性があり、
                外部からアクセスされることは好ましくありません。
                <acronym>AMF</acronym> はバイナリ形式ではありますが、その仕様は公開されています。
                つまり、誰でもメッセージを解読できる可能性があるということです。
            </para>
        </note>

        <para>
            もうひとつ、特に注意を要するのが <acronym>PHP</acronym> のエラーです。
            <acronym>INI</acronym> 設定 <emphasis>display_errors</emphasis> が有効になっていると、
            エラー報告レベルに応じてあらゆる <acronym>PHP</acronym> のエラーが直接出力されてしまいます。
            これは、<acronym>AMF</acronym> のレスポンスを壊してしまう可能性があります。
            運用時には <emphasis>display_errors</emphasis> を無効にし、
            この問題を回避することを推奨します。
        </para>
    </sect2>

    <sect2 id="zend.amf.server.response">
        <title>AMF レスポンス</title>

        <para>
            レスポンスオブジェクトを操作したくなることもあるかもしれません。
            メッセージヘッダを追加したい場合などが考えられます。サーバの
            <methodname>handle()</methodname> メソッドはレスポンスオブジェクトを返すので、これが利用できます。
        </para>

        <example id="zend.amf.server.response.messageHeaderExample">
            <title>AMF レスポンスへのメッセージヘッダの追加</title>

            <para>
                この例では、'foo' という MessageHeader に値
                'bar' を設定したものをレスポンスに追加してからそれを返します。
            </para>

            <programlisting language="php"><![CDATA[
$response = $server->handle();
$response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
echo $response;
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.amf.server.typedobjects">
        <title>型付きオブジェクト</title>

        <para>
            <acronym>SOAP</acronym> と同様、
            <acronym>AMF</acronym> でもクライアントとサーバの間でオブジェクトをやりとりできます。
            これにより、クライアントとサーバの間での柔軟性と一貫性を確保できます。
        </para>

        <para>
            <classname>Zend_Amf</classname> には、
            ActionScript と <acronym>PHP</acronym> オブジェクトを関連付けるための 3 つのメソッドが用意されています。
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    まず、サーバ側で明示的なバインドを行うには
                    <methodname>setClassMap()</methodname> メソッドを使用します。
                    最初の引数は ActionScript クラス名で、2 番目の引数は関連付ける
                    <acronym>PHP</acronym> クラス名となります。
                </para>

                <programlisting language="php"><![CDATA[
// ActionScript クラス 'ContactVO' と PHP クラス 'Contact' を関連付けます
$server->setClassMap('ContactVO', 'Contact');
]]></programlisting>
            </listitem>

            <listitem>
                <para>
                    次に、<acronym>PHP</acronym> クラス内で public プロパティ
                    <varname>$_explicitType</varname> を設定する方法があります。
                    ここには、関連付けたい ActionScript クラス名を指定します。
                </para>

                <programlisting language="php"><![CDATA[
class Contact
{
    public $_explicitType = 'ContactVO';
}
]]></programlisting>
            </listitem>

            <listitem>
                <para>
                    3 番目の方法として、PHP クラスの public メソッド
                    <methodname>getASClassName()</methodname> を使用することもできます。
                    このメソッドは、適切な ActionScript クラスを返すようにしなければなりません。
                </para>

                <programlisting language="php"><![CDATA[
class Contact
{
    public function getASClassName()
    {
        return 'ContactVO';
    }
}
]]></programlisting>
            </listitem>
        </itemizedlist>

        <para>
            サーバ側で ContactVO を作成したら、
            サーバオブジェクトに対応するクラスを <acronym>AS3</acronym> で書かなければなりません。
        </para>

        <para>
            Flex プロジェクトの src フォルダを右クリックし、新規作成 ->
            ActionScript ファイルを選択します。ファイルに ContactVO
            という名前をつけて終了を押すと、新しいファイルがあらわれます。
            次のコードをコピーして、クラスを作成しましょう。
        </para>

        <programlisting language="as"><![CDATA[
package
{
    [Bindable]
    [RemoteClass(alias="ContactVO")]
    public class ContactVO
    {
        public var id:int;
        public var firstname:String;
        public var lastname:String;
        public var email:String;
        public var mobile:String;
        public function ProductVO():void {
        }
    }
}
]]></programlisting>

        <para>
            このクラスは、同名の <acronym>PHP</acronym> のクラスと構文的に同等となります。
            変数名はまったく同じで、大文字小文字もあわせておかなければ正しく動作しません。
            このクラスでは、<acronym>AS3</acronym> 独特のメタタグが 2 つ用いられています。
            最初のタグは bindable で、これは更新時に change イベントを発火させます。
            2 番目のタグは RemoteClass で、このクラスがリモートオブジェクトを保持できること、
            そのエイリアス名が (ここでは) <emphasis>ContactVO</emphasis> であることを定義します。
            このタグに設定される値は、<acronym>PHP</acronym> のクラスと正確に一致していなければなりません。
        </para>

        <programlisting language="as"><![CDATA[
[Bindable]
private var myContact:ContactVO;

private function getContactHandler(event:ResultEvent):void {
    myContact = ContactVO(event.result);
}
]]></programlisting>

        <para>
            サービスコールの後の result イベントは即時に Flex の ContactVO にキャストされます。
            myContact にバインドされているすべての内容は、返された
            ContactVO データで更新されます。
        </para>
    </sect2>

    <sect2 id="zend.amf.server.resources">
        <title>リソース</title>

        <para>
            <classname>Zend_Amf</classname> には、サービスクラスが返すリソース型を
            ActionScript で使用可能な形式のデータにマッピングするツールが用意されています。
        </para>

        <para>
            リソース型を扱うには、そのリソース名に対応する名前のプラグインクラスを作成する必要があります。
           クラス名は、リソース名の単語の先頭を大文字化してスペースを除去したものとなり
            (つまり、リソース型 "mysql result" の場合は MysqlResult となります)、
            それに何らかのプレフィックスをつけてたとえば <classname>My_MysqlResult</classname>
            のようになります。このクラスは <methodname>parse()</methodname>
            メソッドを実装しなければなりません。
            このメソッドはリソースを引数として受け取り、ActionScript に送信する値を返します。
            このクラスを記述するファイル名は、クラス名の最後の部分と同じ名前にしなければなりません。
            たとえば先ほどの例の場合は <filename>MysqlResult.php</filename> となります。
        </para>

        <para>
            リソース用のプラグインを含むディレクトリは、
            <classname>Zend_Amf</classname> 型ローダーで登録しなければなりません。
        </para>

        <programlisting language="php"><![CDATA[
Zend_Amf_Parse_TypeLoader::addResourceDirectory(
    "My",
    "application/library/resources/My"
);
]]></programlisting>

        <para>
            プラグインのロードに関する詳細は、
            <link linkend="zend.loader.pluginloader">プラグインローダー</link> を参照ください。
        </para>

        <para>
            <classname>Zend_Amf</classname> リソース用のデフォルトディレクトリは自動的に登録されており、
            現在ここには "mysql result" リソースおよび "stream" リソースのプラグインが格納されています。
        </para>

        <programlisting language="php"><![CDATA[
// Example class implementing handling resources of type mysql result
class Zend_Amf_Parse_Resource_MysqlResult
{
    /**
     * Parse resource into array
     *
     * @param resource $resource
     * @return array
     */
    public function parse($resource) {
        $result = array();
        while($row = mysql_fetch_assoc($resource)) {
            $result[] = $row;
        }
        return $result;
    }
}
]]></programlisting>

        <para>
            未知のリソース型 (つまり、処理用プラグインが存在しない型)
            を返そうとすると、例外が発生します。
        </para>

    </sect2>

    <sect2 id="zend.amf.server.flash">
        <title>サーバへの Flash からの接続</title>

        <para>
            <classname>Zend_Amf_Server</classname> に Flash プロジェクトから接続する方法は、
            Flex からの場合とは多少異なります。しかし、いったん接続してしまえば
            <classname>Zend_Amf_Server</classname> は flex の場合と同じように動作します。
            次の例は Flex <acronym>AS3</acronym> ファイルからでも使用できます。
            同じ <classname>Zend_Amf_Server</classname> 設定ファイルを用い、
            World クラスを用いて接続します。
        </para>

        <para>
            Flash CS を開き、新規 Flash ファイル (ActionScript 3) を作成します。
            そのドキュメントに <filename>ZendExample.fla</filename> という名前をつけ、
            このサンプルを使用するフォルダに保存します。
            次に、同じディレクトリに新規 <acronym>AS3</acronym> ファイルを作成し、
            <filename>Main.as</filename> という名前をつけます。
            そして両方のファイルをエディタで開きます。
            これから、ドキュメントクラスを通じてふたつのファイルをつないできます。
            ZendExample を選択し、ステージ上でクリックします。
            ステージのプロパティパネルで、ドキュメントクラスを Main に変更します。
            これで、ActionScript ファイル <filename>Main.as</filename> が
            <filename>ZendExample.fla</filename> のユーザインターフェイスとつながります。
            Flash ファイル ZendExample を実行すると、
            <filename>Main.as</filename> クラスが実行されるようになるのです。
            次に、<acronym>AMF</acronym> をコールする ActionScript を追加します。
        </para>

        <para>
            それでは、Main クラスを作成していきましょう。
            これを用いてデータをサーバに送信し、結果を表示します。
            次のコードを <filename>Main.as</filename> にコピーしましょう。これから、
            このコードの中身を追いかけながら何をやっているのかを説明していきます。
        </para>

        <programlisting language="as"><![CDATA[
package {
  import flash.display.MovieClip;
  import flash.events.*;
  import flash.net.NetConnection;
  import flash.net.Responder;

  public class Main extends MovieClip {
    private var gateway:String = "http://example.com/server.php";
    private var connection:NetConnection;
    private var responder:Responder;

    public function Main() {
      responder = new Responder(onResult, onFault);
      connection = new NetConnection;
      connection.connect(gateway);
    }

    public function onComplete( e:Event ):void{
      var params = "Sent to Server";
      connection.call("World.hello", responder, params);
    }

    private function onResult(result:Object):void {
      // Display the returned data
      trace(String(result));
    }
    private function onFault(fault:Object):void {
      trace(String(fault.description));
    }
  }
}
]]></programlisting>

        <para>
            まず、さまざまな作業をするための ActionScript ライブラリをインポートする必要があります。
            ひとつめが NetConnection で、これはクライアントとサーバの間でパイプのような働きをします。
            もうひとつは Responder オブジェクトで、
            これはコールが成功したかどうかなどのサーバからの返り値を処理します。
        </para>

        <programlisting language="as"><![CDATA[
import flash.net.NetConnection;
import flash.net.Responder;
]]></programlisting>

        <para>
            クラスの中で 3 つの変数を用意します。これらがそれぞれ NetConnection、Responder
            そして <classname>Zend_Amf_Server</classname> へのゲートウェイ
            <acronym>URL</acronym> をあらわします。
        </para>

        <programlisting language="as"><![CDATA[
private var gateway:String = "http://example.com/server.php";
private var connection:NetConnection;
private var responder:Responder;
]]></programlisting>

        <para>
            Main のコンストラクタでレスポンダを作成し、また
            <classname>Zend_Amf_Server</classname> エンドポイントへの新規接続も作成します。
            レスポンダでは、サーバからのレスポンスを処理するメソッドが 2 つ定義されています。
            わかりやすくするため、それぞれ onResult および onFault と名づけます。
        </para>

        <programlisting language="as"><![CDATA[
responder = new Responder(onResult, onFault);
connection = new NetConnection;
connection.connect(gateway);
]]></programlisting>

        <para>
            onComplete 関数は、コンストラクタの処理が終わった直後に実行されます。
            ここで、データをサーバに送信します。
            <classname>Zend_Amf_Server</classname> World->hello 関数をコールするコードを 1 行追加しています。
        </para>

        <programlisting language="as"><![CDATA[
connection.call("World.hello", responder, params);
]]></programlisting>

        <para>
            responder を作成した際に、サーバからのレスポンスを処理する関数として
            onResult と onFault を定義しました。サーバから正しい結果が返ってきたとき用の関数を追加します。
            成功時のイベントハンドラは、サーバへの接続が正しく処理されるたびに毎回実行されます。
        </para>

        <programlisting language="as"><![CDATA[
private function onResult(result:Object):void {
    // Display the returned data
    trace(String(result));
}
]]></programlisting>

        <para>
            onFault 関数は、サーバから無効な結果が返ってきたときにコールされます。
            たとえば、サーバからエラーが返された場合、サーバへの <acronym>URL</acronym> が無効な場合、
            リモート側にサービスやメソッドが存在しない場合など、
            接続時に問題が発生した場合にコールされることになります。
        </para>

        <programlisting language="as"><![CDATA[
private function onFault(fault:Object):void {
    trace(String(fault.description));
}
]]></programlisting>

        <para>
            これで、ActionScript 内でのリモート接続処理は完成しました。
            ZendExample を実行すると、 <classname>Zend_Amf</classname> へ接続されるようになります。
            ここまでを振り返ってみましょう。まず最初にリモートサーバへの接続に必要な変数を追加し、
            サーバからのレスポンスを受け取ったときに使用するメソッドを定義し、
            そして最後に返された結果を <methodname>trace()</methodname> で出力しました。
        </para>

    </sect2>

    <sect2 id="zend.amf.server.auth">
        <title>認証</title>

        <para>
            <classname>Zend_Amf_Server</classname> では、認証と認可のフックを指定して
            サービスへのアクセスを制御できます。この仕組みは、
            <link linkend="zend.auth"><classname>Zend_Auth</classname></link> および
            <link linkend="zend.acl"><classname>Zend_Acl</classname></link>
            コンポーネントが提供するものを使用しています。
        </para>

        <para>
            認証を定義するには、抽象クラス
            <classname>Zend_Amf_Auth_Abstract</classname> を継承した認証アダプタを作成します。
            このアダプタは、通常の
            <link linkend="zend.auth.introduction.adapters">認証アダプタ</link>
            と同様に <methodname>authenticate()</methodname> メソッドを実装しなければなりません。
        </para>

        <para>
            アダプタでの認証の際には、親クラス
            <classname>Zend_Amf_Auth_Abstract</classname> のプロパティ
            <emphasis>_username</emphasis> および
            <emphasis>_password</emphasis> を使用しなければなりません。
            <acronym>AMF</acronym> リクエストヘッダに認証情報が含まれていれば、
            <methodname>authenticate()</methodname> がコールされる前にサーバが
            <methodname>setCredentials()</methodname> メソッドを用いてその情報を設定します。
        </para>

        <para>
            アダプタが返す識別情報は、<emphasis>role</emphasis>
            プロパティを含むオブジェクトでなければなりません。
            これを用いて <acronym>ACL</acronym> アクセス制御が動作します。
        </para>

        <para>
            認証に失敗した場合はそれ以降のリクエストの処理は行われず、
            失敗したというメッセージとその理由を結果として返します。
        </para>

        <para>
            アダプタとサーバを関連づけるには <methodname>setAuth()</methodname> メソッドを使用します。
        </para>

        <programlisting language="php"><![CDATA[
$server->setAuth(new My_Amf_Auth());
]]></programlisting>

        <para>
            アクセス制御を行うには
            <methodname>setAcl()</methodname> メソッドで設定した
            <classname>Zend_Acl</classname> オブジェクトを使用します。
        </para>

        <programlisting language="php"><![CDATA[
$acl = new Zend_Acl();
createPermissions($acl); // パーミッション情報を作成します
$server->setAcl($acl);
]]></programlisting>

        <para>
            <acronym>ACL</acronym> オブジェクトが設定され、コールされるクラスで
            <methodname>initAcl()</methodname> メソッドが定義されていれば、
            <acronym>ACL</acronym> オブジェクトを引数としてこのメソッドがコールされます。
            このクラスは追加の <acronym>ACL</acronym> ルールを作成して
            <constant>TRUE</constant> を返すこともできますし、
            このクラスでのアクセス制御が不要な場合は
            <constant>FALSE</constant> を返すこともできます。
        </para>

        <para>
            <acronym>ACL</acronym> の準備が終わると、
            サーバ側で「指定されたロールで、指定されたクラス (関数コールの際は null)
            のリソース、指定された関数の実行権限があるかどうか」を調べます。
            認証情報が提供されていない場合は
            <emphasis>anonymous</emphasis> ロールが定義されているかどうかを調べ、
            定義されている場合はそれを使用します。定義されていない場合はアクセスを拒否します。
        </para>

        <programlisting language="php"><![CDATA[
if($this->_acl->isAllowed($role, $class, $function)) {
    return true;
} else {
    require_once 'Zend/Amf/Server/Exception.php';
    throw new Zend_Amf_Server_Exception("Access not allowed");
}
]]></programlisting>

    </sect2>

</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
