<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 17062 -->
<sect1 id="zend.xmlrpc.client">
    <title>Zend_XmlRpc_Client</title>

    <sect2 id="zend.xmlrpc.client.introduction">
        <title>導入</title>

        <para>
            Zend Framework では、クライアントとしてリモートの
            <acronym>XML-RPC</acronym> サービスを使用することもサポートしています。そのためには
            <classname>Zend_XmlRpc_Client</classname> パッケージを使用します。
            主な機能には、<acronym>PHP</acronym> と <acronym>XML-RPC</acronym> の間の型変換やサーバのプロキシオブジェクト、
            そしてサーバが提供する機能を調べることなどがあります。
        </para>

    </sect2>

    <sect2 id="zend.xmlrpc.client.method-calls">
        <title>メソッドのコール</title>

        <para>
            <classname>Zend_XmlRpc_Client</classname> のコンストラクタは、
            リモート <acronym>XML-RPC</acronym> サーバの <acronym>URL</acronym> を最初の引数として受け取ります。
            返されたインスタンスを使用して、
            その場所からさまざまなリモートメソッドを実行します。
        </para>

        <para>
            リモートメソッドを <acronym>XML-RPC</acronym> クライアントからコールするには、
            インスタンスを作成した後で <code>call()</code> メソッドをコールします。
            以下の例では Zend Framework のウェブサイト上にあるデモ用の
            <acronym>XML-RPC</acronym> サーバを使用します。<classname>Zend_XmlRpc</classname>
            のテストや調査のために、このサーバを使用することができます。
        </para>

        <example id="zend.xmlrpc.client.method-calls.example-1">
            <title>XML-RPC メソッドのコール</title>
            <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

echo $client->call('test.sayHello');

// hello
]]></programlisting>
        </example>

        <para>
            リモートメソッドのコールによって返される <acronym>XML-RPC</acronym> の値は、
            自動的に <acronym>PHP</acronym> のネイティブ型に変換されます。
            上の例では <acronym>PHP</acronym> の <type>String</type> が返されるので、
            それをそのまま使用することができます。
        </para>

        <para>
            <code>call()</code> メソッドの最初のパラメータは、
            コールするリモートメソッドの名前です。
            そのリモートメソッドが何らかのパラメータを要求する場合は、それを
            <code>call()</code> の二番目のオプションのパラメータで指定します。
            このパラメータには、リモートメソッドに渡す値を配列で指定します。
        </para>

        <example id="zend.xmlrpc.client.method-calls.example-2">
            <title>パラメータを指定した XML-RPC メソッドのコール</title>
            <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$arg1 = 1.1;
$arg2 = 'foo';

$result = $client->call('test.sayHello', array($arg1, $arg2));

// $result はネイティブな PHP の型になります
]]></programlisting>
        </example>

        <para>
            リモートメソッドがパラメータを要求していない場合は、
            このパラメータには何も指定しません。あるいは空の <code>array()</code>
            を渡します。リモートメソッドに渡すパラメータの配列には、
            ネイティブの <acronym>PHP</acronym> 型と <classname>Zend_XmlRpc_Value</classname>
            オブジェクトの両方を使用できます。それらを混用することも可能です。
        </para>

        <para>
            <code>call()</code> メソッドは自動的に <acronym>XML-RPC</acronym> のレスポンスを変換し、
            同等な <acronym>PHP</acronym> ネイティブ型にして返します。返り値を
            <classname>Zend_XmlRpc_Response</classname> オブジェクトとして取得するには、
            このメソッドの後で <code>getLastResponse()</code> をコールします。
        </para>
    </sect2>

    <sect2 id="zend.xmlrpc.value.parameters">
        <title>型およびその変換</title>
        <para>
            リモートメソッドの中にはパラメータが必要なものがあります。
            必要なパラメータは、<classname>Zend_XmlRpc_Client</classname> の
            <code>call()</code> メソッドの二番目のパラメータとして配列で指定します。
            パラメータを渡す方法は 2 通りあります。<acronym>PHP</acronym> のネイティブ型
            (これは自動的に変換されます) で渡すか、
            対応する <acronym>XML-RPC</acronym> 型 (<classname>Zend_XmlRpc_Value</classname>
            オブジェクトのひとつ) で渡すかのいずれかです。
        </para>

        <sect3 id="zend.xmlrpc.value.parameters.php-native">
            <title>PHP ネイティブ変数をパラメータとして渡す</title>
            <para>
                <code>call()</code> のパラメータをネイティブの <acronym>PHP</acronym>
                型で渡します。つまり <type>String</type>、
                <code>integer</code>、<code>float</code>、
                <type>Boolean</type>、<type>Array</type> あるいは
                <code>object</code> で渡すということです。
                このとき、<acronym>PHP</acronym> のネイティブ型は自動的に検出され、
                以下の表にしたがって <acronym>XML-RPC</acronym> 型に変換されます。
            </para>

            <table id="zend.xmlrpc.value.parameters.php-native.table-1">
                <title>PHP と XML-RPC の間の型変換</title>
                <tgroup cols="2">
                    <thead>
                        <row>
                            <entry><acronym>PHP</acronym> ネイティブ型</entry>
                            <entry><acronym>XML-RPC</acronym> 型</entry>
                        </row>
                    </thead>
                    <tbody>
                        <row>
                            <entry>integer</entry>
                            <entry>int</entry>
                        </row>
                        <row>
                            <entry>double</entry>
                            <entry>double</entry>
                        </row>
                        <row>
                            <entry>boolean</entry>
                            <entry>boolean</entry>
                        </row>
                        <row>
                            <entry>string</entry>
                            <entry>string</entry>
                        </row>
                        <row>
                            <entry>array</entry>
                            <entry>array</entry>
                        </row>
                        <row>
                            <entry>associative array</entry>
                            <entry>struct</entry>
                        </row>
                        <row>
                            <entry>object</entry>
                            <entry>array</entry>
                        </row>
                    </tbody>
                </tgroup>
            </table>

            <note>
                <title>空の配列はどの型に変換されるの?</title>

                <para>
                    空の配列を <acronym>XML-RPC</acronym> メソッドに渡すことには問題があります。
                    それが array と struct のどちらにでもとれるからです。
                    <classname>Zend_XmlRpc_Client</classname>
                    は、このような状況を検出した場合にはサーバの
                    <code>system.methodSignature</code>
                    メソッドにリクエストを送り、どの <acronym>XML-RPC</acronym>
                    型に変換すべきかを判断します。
                </para>

                <para>
                    しかし、このやりかた自体にも別の問題があります。
                    まず、サーバが <code>system.methodSignature</code>
                    をサポートしていない場合には「リクエストに失敗した」
                    記録がサーバに残ってしまいます。この場合、
                    <classname>Zend_XmlRpc_Client</classname> は値を
                    <acronym>XML-RPC</acronym> の array 型に変換します。
                    さらに、このやりかたを使用すると
                    「配列形式の引数を指定してコールすると、
                    毎回リモートサーバへの余計な呼び出しが発生する」
                    ということになります。
                </para>

                <para>
                    この仕組みを無効にするには、<acronym>XML-RPC</acronym> コールの前に
                    <code>setSkipSystemLookup()</code> メソッドをコールします。
                </para>

                <programlisting language="php"><![CDATA[
$client->setSkipSystemLookup(true);
$result = $client->call('foo.bar', array(array()));
]]></programlisting>
            </note>
        </sect3>

        <sect3 id="zend.xmlrpc.value.parameters.xmlrpc-value">
            <title><classname>Zend_XmlRpc_Value</classname> オブジェクトをパラメータとして渡す</title>
            <para>
                パラメータを表す <classname>Zend_XmlRpc_Value</classname>
                のインスタンスを作成し、<acronym>XML-RPC</acronym> の型を指定することもできます。
                このようにする理由には次のようなものがあります。

                <itemizedlist>
                    <listitem>
                        <para>
                            プロシージャに正しい型で渡されることを確実にしたいことがある
                            (例えば、integer を要求しているプロシージャに対して
                            データベースから取得した文字列を渡したい場合など)。
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            プロシージャが <code>base64</code> 型や
                            <code>dateTime.iso8601</code> 型を要求していることがある
                            (これらは <acronym>PHP</acronym> のネイティブ型には存在しません)。
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            自動変換が失敗する場合 (例えば、空の <acronym>XML-RPC</acronym>
                            構造体をパラメータとして渡すことを考えましょう。
                            これは、<acronym>PHP</acronym> では空の配列に対応します。しかし、
                            空の配列をパラメータとして渡すと、それが自動変換されたときに
                            <acronym>XML-RPC</acronym> の array になってしまいます。なぜなら、
                            空の配列は連想配列ではないからです)。
                        </para>
                    </listitem>
                </itemizedlist>
            </para>

            <para>
                <classname>Zend_XmlRpc_Value</classname> オブジェクトを作成する方法は
                二通りあります。<classname>Zend_XmlRpc_Value</classname>
                のサブクラスのインスタンスを直接作成するか、
                あるいは静的ファクトリメソッド <classname>Zend_XmlRpc_Value::getXmlRpcValue()</classname>
                を使用します。
            </para>

            <table id="zend.xmlrpc.value.parameters.xmlrpc-value.table-1">
                <title><classname>Zend_XmlRpc_Value</classname> オブジェクトと対応する XML-RPC 型</title>
                <tgroup cols="3">
                    <thead>
                        <row>
                            <entry><acronym>XML-RPC</acronym> 型</entry>
                            <entry>対応する <classname>Zend_XmlRpc_Value</classname> 定数</entry>
                            <entry><classname>Zend_XmlRpc_Value</classname> オブジェクト</entry>
                        </row>
                    </thead>
                    <tbody>
                        <row>
                            <entry>int</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_Integer</classname></entry>
                        </row>
                        <row>
                            <entry>double</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_Double</classname></entry>
                        </row>
                        <row>
                            <entry>boolean</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_Boolean</classname></entry>
                        </row>
                        <row>
                            <entry>string</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_STRING</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_String</classname></entry>
                        </row>
                        <row>
                            <entry>base64</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_Base64</classname></entry>
                        </row>
                        <row>
                            <entry>dateTime.iso8601</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_DateTime</classname></entry>
                        </row>
                        <row>
                            <entry>array</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_Array</classname></entry>
                        </row>
                        <row>
                            <entry>struct</entry>
                            <entry><classname>Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT</classname></entry>
                            <entry><classname>Zend_XmlRpc_Value_Struct</classname></entry>
                        </row>
                    </tbody>
                </tgroup>
            </table>

            <para>
                <note>
                    <title>自動変換</title>
                    <para>
                        新しい <classname>Zend_XmlRpc_Value</classname> オブジェクトを作成する際には、
                        その値は <acronym>PHP</acronym> の型として設定されます。この <acronym>PHP</acronym> の型は、
                        <acronym>PHP</acronym> のキャスト機能によって変換されます。
                        たとえば、<classname>Zend_XmlRpc_Value_Integer</classname>
                        に文字列を渡すと、<code>(int)$value</code>
                        のように変換されます。
                    </para>
                </note>
            </para>
        </sect3>
    </sect2>

    <sect2 id="zend.xmlrpc.client.requests-and-responses">
        <title>サーバプロキシオブジェクト</title>
        <para>
            リモートメソッドを <acronym>XML-RPC</acronym> クライアントからコールするもうひとつの方法は、
            サーバプロキシを使用することです。
            サーバプロキシとはリモートの <acronym>XML-RPC</acronym> 名前空間のプロキシとなる
            <acronym>PHP</acronym> オブジェクトで、ネイティブな <acronym>PHP</acronym>
            オブジェクトと可能な限り同じように扱えるようにしたものです。
        </para>

        <para>
            サーバプロキシのインスタンスを作成するには、
            <classname>Zend_XmlRpc_Client</classname> のインスタンスメソッド
            <code>getProxy()</code> をコールします。これは
            <classname>Zend_XmlRpc_Client_ServerProxy</classname> のインスタンスを返します。
            サーバプロキシに対するあらゆるメソッドコールはリモートに転送され、
            パラメータも通常の <acronym>PHP</acronym> メソッドと同じように渡すことができます。
        </para>

        <example id="zend.xmlrpc.client.requests-and-responses.example-1">
            <title>デフォルト名前空間のプロキシ</title>
            <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$server = $client->getProxy();           // デフォルトの名前空間のプロキシを作成します

$hello = $server->test->sayHello(1, 2);  // test.Hello(1, 2) は "hello" を返します
]]></programlisting>
        </example>

        <para>
            <code>getProxy()</code> のオプションの引数で、
            リモートサーバのどの名前空間をプロキシするかを指定することができます。
            名前空間を指定しなかった場合は、デフォルトの名前空間をプロキシします。
            次の例では、<code>test</code> 名前空間がプロキシの対象となります。
        </para>

        <example id="zend.xmlrpc.client.requests-and-responses.example-2">
            <title>任意の名前空間のプロキシ</title>
            <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$test  = $client->getProxy('test');     // "test" 名前空間のプロキシを作成します

$hello = $test->sayHello(1, 2);         // test.Hello(1,2) は "hello" を返します
]]></programlisting>
        </example>

        <para>
            リモートサーバが入れ子状の名前空間をサポートしている場合は、
            サーバプロキシでもそれを使用することができます。たとえば、
            上の例のサーバがメソッド <code>test.foo.bar()</code>
            を保持している場合は、<code>$test->foo->bar()</code>
            のようにコールします。
        </para>
    </sect2>

    <sect2 id="zend.xmlrpc.client.error-handling">
        <title>エラー処理</title>
        <para>
            <acronym>XML-RPC</acronym> のメソッドコールで発生する可能性のあるエラーには、二種類あります。
            <acronym>HTTP</acronym> のエラーと <acronym>XML-RPC</acronym> の fault です。<classname>Zend_XmlRpc_Client</classname>
            はこれらの両方を理解するので、それぞれ独立して検出と処理が可能です。
        </para>

        <sect3 id="zend.xmlrpc.client.error-handling.http">
            <title>HTTP エラー</title>

            <para>
                <acronym>HTTP</acronym> エラーが発生した場合、
                つまり、たとえばリモート <acronym>HTTP</acronym> サーバが
                <code>404 Not Found</code> を返したような場合に
                <classname>Zend_XmlRpc_Client_HttpException</classname> がスローされます。
            </para>

            <example id="zend.xmlrpc.client.error-handling.http.example-1">
                <title>HTTP エラーの処理</title>

                <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://foo/404');

try {

    $client->call('bar', array($arg1, $arg2));

} catch (Zend_XmlRpc_Client_HttpException $e) {

    // $e->getCode() は 404 を返します
    // $e->getMessage() は "Not Found" を返します

}
]]></programlisting>
            </example>

            <para>
                <acronym>XML-RPC</acronym> クライアントの使用法にかかわらず、<acronym>HTTP</acronym> エラーが発生すると必ず
                <classname>Zend_XmlRpc_Client_HttpException</classname> がスローされます。
            </para>
        </sect3>

        <sect3 id="zend.xmlrpc.client.error-handling.faults">
            <title>XML-RPC Fault</title>

            <para>
                <acronym>XML-RPC</acronym> の fault は、<acronym>PHP</acronym> の例外と似たものです。これは
                <acronym>XML-RPC</acronym> メソッドのコールから返される特別な型で、
                エラーコードとエラーメッセージを含みます。<acronym>XML-RPC</acronym> の fault
                は、<classname>Zend_XmlRpc_Client</classname> の使用場面によって処理方法が異なります。
            </para>

            <para>
                <code>call()</code> メソッドや
                サーバプロキシオブジェクトを使用している場合には、
                <acronym>XML-RPC</acronym> の fault が発生すると
                <classname>Zend_XmlRpc_Client_FaultException</classname> がスローされます。
                この例外のコードとメッセージは、もとの <acronym>XML-RPC</acronym> の fault
                レスポンスの値に対応するものとなります。
            </para>

            <example id="zend.xmlrpc.client.error-handling.faults.example-1">
                <title>XML-RPC Fault の処理</title>

                <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

try {

    $client->call('badMethod');

} catch (Zend_XmlRpc_Client_FaultException $e) {

    // $e->getCode() は 1 を返します
    // $e->getMessage() は "Unknown method" を返します

}
]]></programlisting>
            </example>

            <para>
                <code>call()</code> メソッドを使用してリクエストを作成した場合は、
                fault の際に <classname>Zend_XmlRpc_Client_FaultException</classname>
                がスローされます。fault を含む <classname>Zend_XmlRpc_Response</classname>
                オブジェクトを取得するには
                <code>getLastResponse()</code> をコールします。
            </para>

            <para>
                <code>doRequest()</code> メソッドでリクエストを作成した場合は、
                例外はスローされません。そのかわりに、falut を含む
                <classname>Zend_XmlRpc_Response</classname> オブジェクトを返します。
                これを調べるには、
                <classname>Zend_XmlRpc_Response</classname> のインスタンスメソッド
                <code>isFault()</code> を使用します。
            </para>
        </sect3>

    </sect2>

    <sect2 id="zend.xmlrpc.client.introspection">
        <title>サーバのイントロスペクション</title>
        <para>
            <acronym>XML-RPC</acronym> サーバの中には、<acronym>XML-RPC</acronym> の <code>system.</code> 名前空間で
            デファクトのイントロスペクションメソッドをサポートしているものもあります。
            <classname>Zend_XmlRpc_Client</classname> は、この機能を持つサーバもサポートしています。
        </para>

        <para>
            <classname>Zend_XmlRpcClient</classname> の <code>getIntrospector()</code> メソッドをコールすると、
            <classname>Zend_XmlRpc_Client_ServerIntrospection</classname> のインスタンスを取得できます。
            これを使用してサーバのイントロスペクションを行います。
        </para>
    </sect2>

    <sect2 id="zend.xmlrpc.client.request-to-response">
        <title>リクエストからレスポンスへ</title>
        <para>
            <classname>Zend_XmlRpc_Client</classname> のインスタンスメソッド <code>call()</code> 中で行われていることは、
            まずリクエストオブジェクト (<classname>Zend_XmlRpc_Request</classname>) を作成し、
            それを別のメソッド <code>doRequest()</code> で送信し、
            その結果返されるレスポンスオブジェクト (<classname>Zend_XmlRpc_Response</classname>)
            を取得するということです。
        </para>

        <para>
            <code>doRequest()</code> メソッドは、それ単体で直接使用することもできます。
        </para>

        <example id="zend.xmlrpc.client.request-to-response.example-1">
            <title>リクエストからレスポンスへの処理</title>

            <programlisting language="php"><![CDATA[
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$request = new Zend_XmlRpc_Request();
$request->setMethod('test.sayHello');
$request->setParams(array('foo', 'bar'));

$client->doRequest($request);

// $server->getLastRequest() は Zend_XmlRpc_Request のインスタンスを返します
// $server->getLastResponse() は Zend_XmlRpc_Response のインスタンスを返します
]]></programlisting>
        </example>

        <para>
            クライアントから <acronym>XML-RPC</acronym> メソッドのコールが
            (<code>call()</code> メソッド、
            <code>doRequest()</code> メソッドあるいはサーバプロキシによって)
            行われた場合は、最後のリクエストオブジェクトおよびその応答が常に
            <code>getLastRequest()</code> および
            <code>getLastResponse()</code> で取得できます。
        </para>
    </sect2>

    <sect2 id="zend.xmlrpc.client.http-client">
        <title>HTTP クライアントのテスト</title>

        <para>
            これまでのすべての例では、<acronym>HTTP</acronym> クライアントの設定を行いませんでした。
            このような場合、<classname>Zend_Http_Client</classname>
            の新しいインスタンスがデフォルトのオプションで作成され、それを自動的に
            <classname>Zend_XmlRpc_Client</classname> で使用します。
        </para>

        <para>
            <acronym>HTTP</acronym> クライアントは、いつでも
            <code>getHttpClient()</code> メソッドで取得できます。
            たいていの場合はデフォルトの <acronym>HTTP</acronym> クライアントで用が足りるでしょう。
            しかし、<code>setHttpClient()</code> を使用することで、
            別の <acronym>HTTP</acronym> クライアントのインスタンスを使うこともできます。
        </para>

        <para>
            <code>setHttpClient()</code> は、特に単体テストの際に有用です。
            <classname>Zend_Http_Client_Adapter_Test</classname> と組み合わせることで、
            テスト用のリモートサービスのモックを作成することができます。
            この方法を調べるには、<classname>Zend_XmlRpc_Client</classname>
            自体の単体テストを参照ください。
        </para>
    </sect2>

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