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

    <para>
        <classname>Zend_Amf_Server</classname> fornece um servidor no estilo <acronym>RPC</acronym>
        para manipular requisições feitas com Adobe Flash Player usando o protocolo
        <acronym>AMF</acronym>. Como todas as classes de servidor do Zend Framework, ela segue a
        <acronym>API</acronym> SoapServer, fornecendo uma interface fácil de lembrar para criar
        servidores.
    </para>

    <example id="zend.amf.server.basic">
        <title>Servidor AMF Básico</title>
        <para>
            Vamos assumir que você tenha criado uma classe <classname>Foo</classname> com uma
            variedade de métodos públicos. Você pode criar um servidor <acronym>AMF</acronym> usando
            o código a seguir:
        </para>

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

        <para>
            Alternativamente, você pode optar por atribuir uma simples função como chamada de
            retorno:
        </para>

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

        <para>
            Você também pode misturar e combinar várias classes e funções. Quando fizer isso,
            sugerimos que utilize namespaces para que nenhuma colisão de nomes de métodos ocorra;
            isso pode ser feito simplesmente passando uma string como segundo argumento, tanto para
            <methodname>addFunction()</methodname> ou <methodname>setClass()</methodname>.
        </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>
            O <classname>Zend_Amf_Server</classname> também permite que serviços sejam
            dinamicamente carregados baseado em um caminho de diretório fornecido. Você pode
            adicionar tantos quantos diretórios desejar ao servidor. A ordem em que você adiciona os
            diretórios ao servidor será a ordem em que a pesquisa <acronym>LIFO</acronym> será
            realizada nos diretórios para encontrar a classe. Adição de diretórios é feita com
            o método <methodname>addDirectory()</methodname>.
        </para>

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

        <para>
            Ao chamar serviços remotos, os nomes de seus fontes podem conter sublinhados ("_") e
            pontos (".") como delimitadores de diretórios. Quando um sublinhado é usado, as
            conveções <acronym>PEAR</acronym> e Zend Framework para nomenclaturas serão respeitadas.
            Isso significa que se você chamar um serviço <filename>com_Foo_Bar</filename> o servidor
            procurará pelo arquivo <filename>Bar.php</filename> em cada caminho incluído em
            <filename>com/Foo/Bar.php</filename>. Se a notação de ponto é usada para seu serviço
            remoto como em <filename>com.Foo.Bar</filename>, <filename>com/Foo/Bar.php</filename>
            será adicionado ao final de cada caminho incluído para autocarregar
            <filename>Bar.php</filename>
        </para>

        <para>
            Todas as requisições <acronym>AMF</acronym> enviadas ao script serão manipuladas
            posteriormente pelo servidor, e uma resposta <acronym>AMF</acronym> será retornada.
        </para>
    </example>

    <note>
        <title>
            Todas as Funções e Métodos atribuídos precisam de Blocos de Documentação (Docblocks)
        </title>

        <para>
            Como todos os componentes de servidor no Zend Framework, você precisa documentar seus
            métodos de classe usando docblocks <acronym>PHP</acronym>. Você precisa fornecer,
            no mínimo, anotações para cada argumento obrigatório assim como o valor de retorno.
            Exemplo:
        </para>

        <programlisting language="php"><![CDATA[
// Função para atribuição:

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

        <programlisting language="php"><![CDATA[
// Classe atribuída

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

        <para>
            Outras anotações podem ser usadas, mas serão ignoradas.
        </para>
    </note>

    <sect2 id="zend.amf.server.flex">
        <title>Conectando ao servidor com Flex</title>

        <para>
            Conectar a seu <classname>Zend_Amf_Server</classname> a partir de seu projeto Flex é
            bem simples; você simplesmente precisa apontar sua <acronym>URI</acronym> de ponto de
            extremidade (endpoint) para seu script <classname>Zend_Amf_Server</classname>
        </para>

        <para>
            Digamos, por exemplo, que você tenha criado seu servidor e o colocado no arquivo
            <filename>server.php</filename> na raiz de sua aplicação, e seu <acronym>URI</acronym> é
            <filename>http://example.com/server.php</filename>. Neste caso, você modificaria seu
            arquivo <filename>services-config.xml</filename> para definir o atributo uri de ponto de
            extremidade, <property>channel</property>, para este valor.
        </para>

        <para>
            Se você nunca criou um arquivo <filename>services-config.xml</filename> você poderá
            fazê-lo abrindo seu projeto na janela 'Navigator' do Flex Builder. Clique com o botão
            direito sobre nome do projeto e selecione 'properties'. Na janela de diálogo de
            propriedades do projeto vá para o menu 'Flex Build Path', aba 'Library path' e tenha
            certeza de que o arquivo '<filename>rpc.swc</filename>' foi adicionado aos caminhos de
            seus projetos e pressione 'Ok' para fechar a janela.
        </para>

        <para>
            Você também precisará informar ao compilador para usar o arquivo
            <filename>services-config.xml</filename> para encontrar o ponto de extremidade do
            <classname>RemoteObject</classname>. Para isso, abra novamente o painel de propriedades
            de seu projeto clicando com o botão direito do mouse no diretório do projeto a partir
            da janela 'Navigator' e selecionando 'properties'. Na popup de propriedades selecione
            'Flex COmpiler' e adicione a seqüência de caracteres:
            <command>-services "services-config.xml"</command>. Pressione 'Apply' e depois 'OK' para
            voltar e atualizar a opção. O que você acabou de fazer foi dizer ao compilador Flex para
            procurar por variáveis de tempo de execução no arquivo
            <filename>services-config.xml</filename> que serão usadas pela classe
            <classname>RemoteObject</classname>
        </para>

        <para>
            Agora precisamos dizer ao Flex qual arquivo de configuração de serviços usar para
            conectar a nossos métodos remotos. Por essa razão crie um novo arquivo
            '<filename>services-config.xml</filename>' em seu diretório <filename>src</filename> do
            seu projeto Flex. Pra fazer isso clique com o botão direito no diretório do projeto e
            selecione 'new'; 'File' que uma nova janela se abrirá. Selecione o diretório do projeto
            e nomeie o arquivo '<filename>services-config.xml</filename>' e pressione 'finish'.
        </para>

        <para>
            O Flex criou um novo <filename>servies-config.xml</filename> e o abriu. Use o texto de
            exemplo a seguir para seu arquivo <filename>services-config.xml</filename>. Tenha
            certeza de atualizar seu ponto de extremidade (endpoint) para coincidir com seu servidor
            de testes e que você salve o arquivo.
        </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>
            Há dois pontos chave no exemplo. Primeiro, mas por último na listagem, criamos um canal
            <acronym>AMF</acronym> e especificados o poonto de extremidade (endpoint) como
            <acronym>URL</acronym> para nosso <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>
            Note que demos a este canal um identificador, "zend-endpoint". O exemplo cria um destino
            de serviço que se refere a este canal, atribuindo a ele um ID também - neste caso
            "zend".
        </para>

        <para>
            Em nossos arquivos <acronym>MXML</acronym> do Flex, precisamos ligar um
            <classname>RemoteObject</classname> ao serviço. Em <acronym>MXML</acronym>, isto é feito
            como a seguir:
        </para>

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

        <para>
            Aqui, definimos um novo objeto remoto identificado por "myservice" ligado ao destino de
            serviço "zend" que definimos no arquivo <filename>services-config.xml</filename>. Nós
            depois chamamos métodos em nosso ActionScript simplesmente
            chamando "myservice.&lt;método&gt;". Como no exemplo:
        </para>

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

        <para>
            Quando usando espaços de nomes (namespaces), usamos:
            "myservice.&lt;espaço de nome&gt;.&lt;método&gt;":
        </para>

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

        <para>
            Para mais informações sobre como utilizar o <classname>RemoteObject</classname> do Flex,
            <ulink url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">
            visite o site da Ajuda do Adobre Flex 3</ulink>.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.errors">
        <title>Manipulação de Erros</title>

        <para>
            Por padrão, todas as exceções lançadas em suas classes ou funções anexadas serão obtidas
            e retornadas como <classname>ErrorMessage</classname>s do <acronym>AMF</acronym>.
            No entando, o conteúdos destes objetos <classname>ErrorMessage</classname> variam se
            o servidor está ou não em modo de "produção" (o estado padrão).
        </para>

        <para>
            Quando em modo de produção, somente o código da exceção será retornado. Se você
            desabilitar o modo de produção - algo que você deve fazer apenas para testes - a maioria
            dos detalhes de exceção serão retornados: a mensagem de exceção, linha, e
            pilha de execução (backtrace) serão todos anexados.
        </para>

        <para>
            Para desabilitar o modo de produção, faça o seguinte:
        </para>

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

        <para>
            Para habilitá-lo novamnete, passe um valor booleano <constant>TRUE</constant>:
        </para>

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

        <note>
            <title>Desabilite o modo de produção com moderação!</title>

            <para>
                Recomendamos desabilitar o modo de produção somente durante o desenvolvimento.
                Mensagens de exceção e pilhas de execução podem conter informações sensíveis que
                você provavelmente não deseje que terceiros tenham acesso. Mesmo
                <acronym>AMF</acronym> sendo um formato binário, a especificação é aberta, o que
                quer dizer que qualquer um pode, potencialmente, desserializar os dados carregados.
            </para>
        </note>

        <para>
            Uma área para ser especialmente cuidadoso são os próprios erros <acronym>PHP</acronym>.
            Quando a diretiva <property>display_errors</property> do <acronym>INI</acronym> está
            habilitada, qualquer erro <acronym>PHP</acronym> para o nível atual de reltório de erros
            são mostrados diretamente na saída - potencialmente interrompendo a carga de dados
            <acronym>AMF</acronym>. Sugerimos desabilitar a diretiva
            <property>display_errors</property> em modo de produção para evitar tais problemas
        </para>
    </sect2>

    <sect2 id="zend.amf.server.response">
        <title>Respostas AMF</title>

        <para>
            Ocasionalmente você pode desejar manipular levemente o objeto de resposta, tipicamente
            para retornar cabeçalhos de mensagem extra. O método <methodname>handle()</methodname>
            do servidor retorna o objeto da resposta, possibilitando a você fazer isto.
        </para>

        <example id="zend.amf.server.response.messageHeaderExample">
            <title>Adicionando Cabeçalhos de Mensagem à Resposta AMF</title>

            <para>
                Neste exemplo, adicionamos um <classname>MessageHeader</classname> 'foo' com o
                valor 'bar' à resposta antes de retorná-la.
            </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>Objetos Tipados</title>

        <para>
            De modo similar ao <acronym>SOAP</acronym>, <acronym>AMF</acronym> permite que sejam
            passados objetos entre o cliente e o servidor. Isso permite uma grande quantidade de
            flexibilidade e coerência entre os dois ambientes.
        </para>

        <para>
            <classname>Zend_Amf</classname> fornece três métodos para mapeamento entre objetos
            ActionScript e <acronym>PHP</acronym>.
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    Primeiro, você deve criar explicitamente ligações no nível do servidor, usando o
                    método <methodname>setClassMap()</methodname>. O primeiro argumento é o nome da
                    classe ActionScript, o segundo é a classe <acronym>PHP</acronym> que a mapeia:
                </para>

                <programlisting language="php"><![CDATA[
// Mapeia a classe ActionScript 'ContactVO' para a classe PHP 'Contact':
$server->setClassMap('ContactVO', 'Contact');
]]></programlisting>
            </listitem>

            <listitem>
                <para>
                    Em segundo lugar, você definir a propriedade pública
                    <varname>$_explicitType</varname> em sua classe <acronym>PHP</acronym>, com o
                    valor representando a classe ActionScript para mapear:
                </para>

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

            <listitem>
                <para>
                    Terceiro, de maneira similar, você pode definir o método público
                    <methodname>getASClassName()</methodname> em sua classe <acronym>PHP</acronym>;
                    este método deve retornar a classe ActionScript apropriada:
                </para>

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

        <para>
            Embora tenhamos criado o ContactVO no servidor precisamos agora fazer a classe
            correspondente em <acronym>AS3</acronym> para que o objeto de servidor seja mapeado.
        </para>

        <para>
            Clique com o botão direito na pasta <filename>src</filename> de seu projeto Flex e
            selecione 'New' -> 'ActionScript File'. Nomeie o arquivo como 'ContactVO' e pressione
            'finish' para ver o novo arquivo. Copie o seguinte código para finalizar a criação da
            classe.
        </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 ContactVO():void {
        }
    }
}
]]></programlisting>

        <para>
            A classe é sintaticamente equivalente à classe <acronym>PHP</acronym> com o mesmo nome.
            Os nomes de variáveis são exatamente os mesmos e precisam estar sob o mesmo caso para
            que funcione apropriadamente. Existem duas marcações meta (meta tags)
            <acronym>AS3</acronym> únicas nesta classe. A primeira é Bindable, que faz com
            que um evento de alteração (change) seja disparado quando ela é atualizada. A segunda
            marcação é RemoteClass, que define que esta classe pode ter um objeto remoto mapeado a
            ela com um apelido, neste caso <emphasis>ContactVO</emphasis>. É obrigatório que o valor
            desta marcação seja definido seja estritamente equivalente ao da classe
            <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>
            O evento de resultado gerado pela chamada ao serviço é instantaneamente convertido para
            o ContactVO do Flex. Qualquer coisa que seja direcionada a <varname>myContact</varname>
            será atualizado e os dados de ContactVO serão retornados.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.resources">
        <title>Recursos</title>

        <para>
            <classname>Zend_Amf</classname> fornece ferramentas para mapear tipos de recursos
            retornados por classes de serviços em informações consumíveis pelo ActionScript.
        </para>

        <para>
            A fim de lidar com tipo de recurso específico, o usuário precisa criar uma classe plugin
            chamado após o nome do recurso, com palavras em maiúsculas e espaços removidos (assim
            recurso do tipo "resultado mysql" torna-se ResultadoMysql), com algum prefixo, ex.:
            <classname>Meu_ResultadoMysql</classname>. Esta classe precisa implementar um método,
            <methodname>parse()</methodname>, recebendo um argumento - o recurso - e retornando o
            valor a ser enviado para o ActionScript. A classe deve estar localizada no arquivo
            chamado após o nome do componente, ex.: <filename>ResultadoMysql.php</filename>.
        </para>

        <para>
            O diretório contendo os plugins para manipulação de recursos devem ser registrados com o
            carregador de tipo <classname>Zend_Amf</classname>:
        </para>

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

        <para>
            Para uma discussão detalhada sobre o plugins carregadores, por favor veja a seção
            <link linkend="zend.loader.pluginloader">plugin carregador</link>.
        </para>

        <para>
            O diretório padrão para recursos <classname>Zend_Amf</classname> é registrado
            automaticamente e atualmente contém manipuladores para recursos "resultado mysql" e
            "stream".
        </para>

        <programlisting language="php"><![CDATA[
// Classe de exemplo implementando a manipulação de recursos do tipo "resultado mysql"
class Zend_Amf_Parse_Recurso_ResultadoMysql
{
    /**
     * Decodifica o recurso em uma matriz
     *
     * @param resource $resource
     * @return array
     */
    public function parse($resource) {
        $result = array();
        while($row = mysql_fetch_assoc($resource)) {
            $result[] = $row;
        }
        return $result;
    }
}
]]></programlisting>

        <para>
            Ao tentar retornar um tipo desconhecido de recirso (ex., um para o qual não haja plugin
            manipulador existente) resultará em uma exceção.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.flash">
        <title>Conectando ao Servidor a partir do Flash</title>

        <para>
            Conectando ao seu <classname>Zend_Amf_Server</classname> a partir de seu projeto Flash é
            ligeiramente diferente do que com Flex. Contudo, depois da conexão, Flash funciona com
            <classname>Zend_Amf_Server</classname> da mesma forma que com Flex. O exemplo a seguir
            também pode ser usado com um arquivo <acronym>AS3</acronym> do Flex. Reutilizaremos a
            mesma configuração <classname>Zend_Amf_Server</classname> com a classe Mundo para nossa
            conexão.
        </para>

        <para>
            Abra o Flash CS e crie um novo arquivo Flash (ActionScript 3). Nomeie o documento
            <filename>ExemploZend.fla</filename> e salve o documento em uma pasta que você usará
            para este exemplo. Crie uma nova classe <acronym>AS3</acronym> no mesmo diretório e
            nomeie o arquivo como <filename>Principal.as</filename>. Tenha ambos os arquivos abertos
            em seu editor. Vamos conectar os dois arquivos através da classe de documento. Selecione
            ExemploZend e clique no palco. No painel de propriedade dos palco, altere a classe de
            documento (Document class) para Principal. Isso ligará o arquivo ActionScript
            <filename>Principal.as</filename> com a interface do usuário do arquivo
            <filename>ExemploZend.fla</filename>. Quando você executa o arquivo Flash ExemploZend, a
            classe <filename>Principal.as</filename> será executada agora. Agora, vamos adicionar o
            código ActionScript para fazer a chamada <acronym>AMF</acronym>.
        </para>

        <para>
            Agora nós faremos a classe Principal de modo que possamos enviar dados ao servidor e
            exibir o resultado. Copie o código a seguir para seu arquivo
            <filename>Principal.as</filename> e depois vamos descrever, passo a passo, o papel de
            cada elemento nele.
        </para>

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

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

    public function Principal() {
      responder = new Responder(onResult, onFault);
      connection = new NetConnection;
      connection.addEventListener(NetStatusEvent.NET_STATUS, onComplete);
      connection.connect(gateway);
    }

    public function onComplete( e:NetStatusEvent ):void {
      if(e.info.code == "NetGroup.Connect.Succcess") {
        var params = "Sent to Server";
        connection.call("Mundo.alo", 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>
            Primeiro precisamos importar duas bibliotecas ActionScriot que executam a maior parte do
            trabalho. A primeira é NetConnection que atua como um tubo bi-direcional entre o cliente
            e o servidor. A segunda é o objeto Responder, que manipula os valores de retorno do
            servidor relacionados ao sucesso ou falha da chamada.
        </para>

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

        <para>
            Na classe, precisamos de três variáveis para representar a NetConnection, Responder e a
            <acronym>URL</acronym> da porta de entrada (gateway) para nossa instalação
            <classname>Zend_Amf_Server</classname>.
        </para>

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

        <para>
            No contrutor de Principal criamos um respondedor e uma nova conexão ao
            ponto de extremidade (gateway) <classname>Zend_Amf_Server</classname>. O respondedor
            define dois métodos diferentes para manipular as respostas do servidor. Por simplicidade
            eles foram chamados de onResult e onFault.
        </para>

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

        <para>
            Na função onComplete, que é executada assim que o construtor tenha sido terminado, nós
            enviamos dados ao servidor. Precisamos adicionar mais uma linha que realiza a chamada a
            função Mundo->alo do <classname>Zend_Amf_Server</classname>
        </para>

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

        <para>
            Quando instanciamos a variável responder, definimos uma função onResult e onFault para
            manipular a resposta do servidor. Adicionamos esta função para um resultado de sucesso
            vindo do servidor. Um manipulador de eventos de sucesso é executado sempre que uma
            conexão  é manipulada apropriadamente no servidor.
        </para>

        <programlisting language="as"><![CDATA[
private function onResult(result:Object):void {
    // Mostra os dados retornados
    trace(String(result));
}
]]></programlisting>

        <para>
            A função onFault é chamada se há uma resposta inválida vinda do servidor. Isso acontece
            quando há um erro no servidor, a <acronym>URL</acronym> para o servidor é inválida, o
            serviço remoto ou método não existe ou se há qualquer outro problema relacionado à
            conexão.
        </para>

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

        <para>
            Completamos então a inclusão do ActionScript para realizar a conexão remota. Executando
            o arquivo ExemploZend agora faz a conexão ao <classname>Zend_Amf</classname>. Numa
            revisão, você adicionou as variáveis necessárias para abrir uma conexão ao servidor
            remoto, definiu quais métodos devem ser usados em sua aplicação para receber respostas
            do servidor e finalmente exibido os dados retornados através da função
            <methodname>trace()</methodname>.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.auth">
        <title>Autenticação</title>

        <para>
            <classname>Zend_Amf_Server</classname> permite que você especifique ganchos de
            autentcação e autorização para controlar acesso aos serviços. Isso é feito usando a
            infraestrutura fornecida pelos componentes
            <link linkend="zend.auth"><classname>Zend_Auth</classname></link> e
            <link linkend="zend.acl"><classname>Zend_Acl</classname></link>.
        </para>

        <para>
            Para definir autenticação, o usuário fornece um adaptador de autenticação extendendo a
            classe abstrata <classname>Zend_Amf_Auth_Abstract</classname>. O adaptador deve
            implementar o método <methodname>authenticate()</methodname> como qualquer outro
            <link linkend="zend.auth.introduction.adapters">adaptador de autenticação</link>.
        </para>

        <para>
            O adaptador deve utilizar as propriedades <emphasis>_username</emphasis> e
            <emphasis>_password</emphasis> da classe pai,
            <classname>Zend_Amf_Auth_Adapter</classname>, para autenticar. Estes valores são
            definidos pelo servidor usando o método <methodname>setCredentials()</methodname> antes
            da chamada à <methodname>authenticate()</methodname> se as credenciais forem recebidas
            nos cabeçalhos da requisição <acronym>AMF</acronym>.
        </para>

        <para>
            A identidade retornada pelo adaptador deve ser um objeto contendo a propriedade
            <property>role</property> para que o controle de acesso da <acronym>ACL</acronym>
            funcione.
        </para>

        <para>
            Se o resultado da autenticação não for bem sucedido, a requisição não é mais procesada e
            uma mensagem de falha é retornada contendo as razões da falha obtida do resultado.
        </para>

        <para>
            O adaptador é conectado ao servidor usando o método <methodname>setAuth()</methodname>:
        </para>

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

        <para>
            O controle de acesso é realizado usando um objeto <classname>Zend_Acl</classname>
            definido pelo método <methodname>setAcl()</methodname>:
        </para>

        <programlisting language="php"><![CDATA[
$acl = new Zend_Acl();
criarPermissoes($acl); // Cria a estrutura de permissões
$server->setAcl($acl);
]]></programlisting>

        <para>
            Se o objeto <acronym>ACL</acronym> é definido e a classe sendo chamada define o método
            <methodname>initAcl()</methodname>, este método será chamado com o objeto
            <acronym>ACL</acronym> como um argumento. A classe depois cria regras
            <acronym>ACL</acronym> adicionais e retorna <constant>TRUE</constant>, ou retorna
            <constant>FALSE</constant> se nenhum controle de acesso for necessário para esta classe.
        </para>

        <para>
            Depois de a <acronym>ACL</acronym> ser definida, o servidor verificará se o acesso é
            permitido com o papel definido pela autenticação, sendo o recurso o nome da classe (ou
            <constant>NULL</constant> para chamadas de funções) e o privileǵio sendo o nome da
            função. Se nenhuma autenticação for fornecida, e se o papel
            <emphasis>anonymous</emphasis> foi definido, ele será usado, em outro caso o acesso será
            negado.
        </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("Accesso não permitido");
}
]]></programlisting>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
