Zend_Amf-Server.xml 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.amf.server">
  5. <title>Zend_Amf_Server</title>
  6. <para>
  7. <classname>Zend_Amf_Server</classname> fornece um servidor no estilo <acronym>RPC</acronym>
  8. para manipular requisições feitas com Adobe Flash Player usando o protocolo
  9. <acronym>AMF</acronym>. Como todas as classes de servidor do Zend Framework, ela segue a
  10. <acronym>API</acronym> SoapServer, fornecendo uma interface fácil de lembrar para criar
  11. servidores.
  12. </para>
  13. <example id="zend.amf.server.basic">
  14. <title>Servidor AMF Básico</title>
  15. <para>
  16. Vamos assumir que você tenha criado uma classe <classname>Foo</classname> com uma
  17. variedade de métodos públicos. Você pode criar um servidor <acronym>AMF</acronym> usando
  18. o código a seguir:
  19. </para>
  20. <programlisting language="php"><![CDATA[
  21. $server = new Zend_Amf_Server();
  22. $server->setClass('Foo');
  23. $response = $server->handle();
  24. echo $response;
  25. ]]></programlisting>
  26. <para>
  27. Alternativamente, você pode optar por atribuir uma simples função como chamada de
  28. retorno:
  29. </para>
  30. <programlisting language="php"><![CDATA[
  31. $server = new Zend_Amf_Server();
  32. $server->addFunction('myUberCoolFunction');
  33. $response = $server->handle();
  34. echo $response;
  35. ]]></programlisting>
  36. <para>
  37. Você também pode misturar e combinar várias classes e funções. Quando fizer isso,
  38. sugerimos que utilize namespaces para que nenhuma colisão de nomes de métodos ocorra;
  39. isso pode ser feito simplesmente passando uma string como segundo argumento, tanto para
  40. <methodname>addFunction()</methodname> ou <methodname>setClass()</methodname>.
  41. </para>
  42. <programlisting language="php"><![CDATA[
  43. $server = new Zend_Amf_Server();
  44. $server->addFunction('myUberCoolFunction', 'my')
  45. ->setClass('Foo', 'foo')
  46. ->setClass('Bar', 'bar');
  47. $response = $server->handle();
  48. echo $response;
  49. ]]></programlisting>
  50. <para>
  51. O <classname>Zend_Amf_Server</classname> também permite que serviços sejam
  52. dinamicamente carregados baseado em um caminho de diretório fornecido. Você pode
  53. adicionar tantos quantos diretórios desejar ao servidor. A ordem em que você adiciona os
  54. diretórios ao servidor será a ordem em que a pesquisa <acronym>LIFO</acronym> será
  55. realizada nos diretórios para encontrar a classe. Adição de diretórios é feita com
  56. o método <methodname>addDirectory()</methodname>.
  57. </para>
  58. <programlisting language="php"><![CDATA[
  59. $server->addDirectory(dirname(__FILE__) .'/../services/');
  60. $server->addDirectory(dirname(__FILE__) .'/../package/');
  61. ]]></programlisting>
  62. <para>
  63. Ao chamar serviços remotos, os nomes de seus fontes podem conter sublinhados ("_") e
  64. pontos (".") como delimitadores de diretórios. Quando um sublinhado é usado, as
  65. conveções <acronym>PEAR</acronym> e Zend Framework para nomenclaturas serão respeitadas.
  66. Isso significa que se você chamar um serviço <filename>com_Foo_Bar</filename> o servidor
  67. procurará pelo arquivo <filename>Bar.php</filename> em cada caminho incluído em
  68. <filename>com/Foo/Bar.php</filename>. Se a notação de ponto é usada para seu serviço
  69. remoto como em <filename>com.Foo.Bar</filename>, <filename>com/Foo/Bar.php</filename>
  70. será adicionado ao final de cada caminho incluído para autocarregar
  71. <filename>Bar.php</filename>
  72. </para>
  73. <para>
  74. Todas as requisições <acronym>AMF</acronym> enviadas ao script serão manipuladas
  75. posteriormente pelo servidor, e uma resposta <acronym>AMF</acronym> será retornada.
  76. </para>
  77. </example>
  78. <note>
  79. <title>
  80. Todas as Funções e Métodos atribuídos precisam de Blocos de Documentação (Docblocks)
  81. </title>
  82. <para>
  83. Como todos os componentes de servidor no Zend Framework, você precisa documentar seus
  84. métodos de classe usando docblocks <acronym>PHP</acronym>. Você precisa fornecer,
  85. no mínimo, anotações para cada argumento obrigatório assim como o valor de retorno.
  86. Exemplo:
  87. </para>
  88. <programlisting language="php"><![CDATA[
  89. // Função para atribuição:
  90. /**
  91. * @param string $name
  92. * @param string $greeting
  93. * @return string
  94. */
  95. function helloWorld($name, $greeting = 'Hello')
  96. {
  97. return $greeting . ', ' . $name;
  98. }
  99. ]]></programlisting>
  100. <programlisting language="php"><![CDATA[
  101. // Classe atribuída
  102. class World
  103. {
  104. /**
  105. * @param string $name
  106. * @param string $greeting
  107. * @return string
  108. */
  109. public function hello($name, $greeting = 'Hello')
  110. {
  111. return $greeting . ', ' . $name;
  112. }
  113. }
  114. ]]></programlisting>
  115. <para>
  116. Outras anotações podem ser usadas, mas serão ignoradas.
  117. </para>
  118. </note>
  119. <sect2 id="zend.amf.server.flex">
  120. <title>Conectando ao servidor com Flex</title>
  121. <para>
  122. Conectar a seu <classname>Zend_Amf_Server</classname> a partir de seu projeto Flex é
  123. bem simples; você simplesmente precisa apontar sua <acronym>URI</acronym> de ponto de
  124. extremidade (endpoint) para seu script <classname>Zend_Amf_Server</classname>
  125. </para>
  126. <para>
  127. Digamos, por exemplo, que você tenha criado seu servidor e o colocado no arquivo
  128. <filename>server.php</filename> na raiz de sua aplicação, e seu <acronym>URI</acronym> é
  129. <filename>http://example.com/server.php</filename>. Neste caso, você modificaria seu
  130. arquivo <filename>services-config.xml</filename> para definir o atributo uri de ponto de
  131. extremidade, <property>channel</property>, para este valor.
  132. </para>
  133. <para>
  134. Se você nunca criou um arquivo <filename>services-config.xml</filename> você poderá
  135. fazê-lo abrindo seu projeto na janela 'Navigator' do Flex Builder. Clique com o botão
  136. direito sobre nome do projeto e selecione 'properties'. Na janela de diálogo de
  137. propriedades do projeto vá para o menu 'Flex Build Path', aba 'Library path' e tenha
  138. certeza de que o arquivo '<filename>rpc.swc</filename>' foi adicionado aos caminhos de
  139. seus projetos e pressione 'Ok' para fechar a janela.
  140. </para>
  141. <para>
  142. Você também precisará informar ao compilador para usar o arquivo
  143. <filename>services-config.xml</filename> para encontrar o ponto de extremidade do
  144. <classname>RemoteObject</classname>. Para isso, abra novamente o painel de propriedades
  145. de seu projeto clicando com o botão direito do mouse no diretório do projeto a partir
  146. da janela 'Navigator' e selecionando 'properties'. Na popup de propriedades selecione
  147. 'Flex COmpiler' e adicione a seqüência de caracteres:
  148. <command>-services "services-config.xml"</command>. Pressione 'Apply' e depois 'OK' para
  149. voltar e atualizar a opção. O que você acabou de fazer foi dizer ao compilador Flex para
  150. procurar por variáveis de tempo de execução no arquivo
  151. <filename>services-config.xml</filename> que serão usadas pela classe
  152. <classname>RemoteObject</classname>
  153. </para>
  154. <para>
  155. Agora precisamos dizer ao Flex qual arquivo de configuração de serviços usar para
  156. conectar a nossos métodos remotos. Por essa razão crie um novo arquivo
  157. '<filename>services-config.xml</filename>' em seu diretório <filename>src</filename> do
  158. seu projeto Flex. Pra fazer isso clique com o botão direito no diretório do projeto e
  159. selecione 'new'; 'File' que uma nova janela se abrirá. Selecione o diretório do projeto
  160. e nomeie o arquivo '<filename>services-config.xml</filename>' e pressione 'finish'.
  161. </para>
  162. <para>
  163. O Flex criou um novo <filename>servies-config.xml</filename> e o abriu. Use o texto de
  164. exemplo a seguir para seu arquivo <filename>services-config.xml</filename>. Tenha
  165. certeza de atualizar seu ponto de extremidade (endpoint) para coincidir com seu servidor
  166. de testes e que você salve o arquivo.
  167. </para>
  168. <programlisting language="xml"><![CDATA[
  169. <?xml version="1.0" encoding="UTF-8"?>
  170. <services-config>
  171. <services>
  172. <service id="zend-service"
  173. class="flex.messaging.services.RemotingService"
  174. messageTypes="flex.messaging.messages.RemotingMessage">
  175. <destination id="zend">
  176. <channels>
  177. <channel ref="zend-endpoint"/>
  178. </channels>
  179. <properties>
  180. <source>*</source>
  181. </properties>
  182. </destination>
  183. </service>
  184. </services>
  185. <channels>
  186. <channel-definition id="zend-endpoint"
  187. class="mx.messaging.channels.AMFChannel">
  188. <endpoint uri="http://example.com/server.php"
  189. class="flex.messaging.endpoints.AMFEndpoint"/>
  190. </channel-definition>
  191. </channels>
  192. </services-config>
  193. ]]></programlisting>
  194. <para>
  195. Há dois pontos chave no exemplo. Primeiro, mas por último na listagem, criamos um canal
  196. <acronym>AMF</acronym> e especificados o poonto de extremidade (endpoint) como
  197. <acronym>URL</acronym> para nosso <classname>Zend_Amf_Server</classname>:
  198. </para>
  199. <programlisting language="xml"><![CDATA[
  200. <channel-definition id="zend-endpoint"
  201. <endpoint uri="http://example.com/server.php"
  202. class="flex.messaging.endpoints.AMFEndpoint"/>
  203. </channel-definition>
  204. ]]></programlisting>
  205. <para>
  206. Note que demos a este canal um identificador, "zend-endpoint". O exemplo cria um destino
  207. de serviço que se refere a este canal, atribuindo a ele um ID também - neste caso
  208. "zend".
  209. </para>
  210. <para>
  211. Em nossos arquivos <acronym>MXML</acronym> do Flex, precisamos ligar um
  212. <classname>RemoteObject</classname> ao serviço. Em <acronym>MXML</acronym>, isto é feito
  213. como a seguir:
  214. </para>
  215. <programlisting language="xml"><![CDATA[
  216. <mx:RemoteObject id="myservice"
  217. fault="faultHandler(event)"
  218. showBusyCursor="true"
  219. destination="zend">
  220. ]]></programlisting>
  221. <para>
  222. Aqui, definimos um novo objeto remoto identificado por "myservice" ligado ao destino de
  223. serviço "zend" que definimos no arquivo <filename>services-config.xml</filename>. Nós
  224. depois chamamos métodos em nosso ActionScript simplesmente
  225. chamando "myservice.&lt;método&gt;". Como no exemplo:
  226. </para>
  227. <programlisting language="ActionScript"><![CDATA[
  228. myservice.hello("Wade");
  229. ]]></programlisting>
  230. <para>
  231. Quando usando espaços de nomes (namespaces), usamos:
  232. "myservice.&lt;espaço de nome&gt;.&lt;método&gt;":
  233. </para>
  234. <programlisting language="ActionScript"><![CDATA[
  235. myservice.world.hello("Wade");
  236. ]]></programlisting>
  237. <para>
  238. Para mais informações sobre como utilizar o <classname>RemoteObject</classname> do Flex,
  239. <ulink url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">
  240. visite o site da Ajuda do Adobre Flex 3</ulink>.
  241. </para>
  242. </sect2>
  243. <sect2 id="zend.amf.server.errors">
  244. <title>Manipulação de Erros</title>
  245. <para>
  246. Por padrão, todas as exceções lançadas em suas classes ou funções anexadas serão obtidas
  247. e retornadas como <classname>ErrorMessage</classname>s do <acronym>AMF</acronym>.
  248. No entando, o conteúdos destes objetos <classname>ErrorMessage</classname> variam se
  249. o servidor está ou não em modo de "produção" (o estado padrão).
  250. </para>
  251. <para>
  252. Quando em modo de produção, somente o código da exceção será retornado. Se você
  253. desabilitar o modo de produção - algo que você deve fazer apenas para testes - a maioria
  254. dos detalhes de exceção serão retornados: a mensagem de exceção, linha, e
  255. pilha de execução (backtrace) serão todos anexados.
  256. </para>
  257. <para>
  258. Para desabilitar o modo de produção, faça o seguinte:
  259. </para>
  260. <programlisting language="php"><![CDATA[
  261. $server->setProduction(false);
  262. ]]></programlisting>
  263. <para>
  264. Para habilitá-lo novamnete, passe um valor booleano <constant>TRUE</constant>:
  265. </para>
  266. <programlisting language="php"><![CDATA[
  267. $server->setProduction(true);
  268. ]]></programlisting>
  269. <note>
  270. <title>Desabilite o modo de produção com moderação!</title>
  271. <para>
  272. Recomendamos desabilitar o modo de produção somente durante o desenvolvimento.
  273. Mensagens de exceção e pilhas de execução podem conter informações sensíveis que
  274. você provavelmente não deseje que terceiros tenham acesso. Mesmo
  275. <acronym>AMF</acronym> sendo um formato binário, a especificação é aberta, o que
  276. quer dizer que qualquer um pode, potencialmente, desserializar os dados carregados.
  277. </para>
  278. </note>
  279. <para>
  280. Uma área para ser especialmente cuidadoso são os próprios erros <acronym>PHP</acronym>.
  281. Quando a diretiva <property>display_errors</property> do <acronym>INI</acronym> está
  282. habilitada, qualquer erro <acronym>PHP</acronym> para o nível atual de reltório de erros
  283. são mostrados diretamente na saída - potencialmente interrompendo a carga de dados
  284. <acronym>AMF</acronym>. Sugerimos desabilitar a diretiva
  285. <property>display_errors</property> em modo de produção para evitar tais problemas
  286. </para>
  287. </sect2>
  288. <sect2 id="zend.amf.server.response">
  289. <title>Respostas AMF</title>
  290. <para>
  291. Ocasionalmente você pode desejar manipular levemente o objeto de resposta, tipicamente
  292. para retornar cabeçalhos de mensagem extra. O método <methodname>handle()</methodname>
  293. do servidor retorna o objeto da resposta, possibilitando a você fazer isto.
  294. </para>
  295. <example id="zend.amf.server.response.messageHeaderExample">
  296. <title>Adicionando Cabeçalhos de Mensagem à Resposta AMF</title>
  297. <para>
  298. Neste exemplo, adicionamos um <classname>MessageHeader</classname> 'foo' com o
  299. valor 'bar' à resposta antes de retorná-la.
  300. </para>
  301. <programlisting language="php"><![CDATA[
  302. $response = $server->handle();
  303. $response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
  304. echo $response;
  305. ]]></programlisting>
  306. </example>
  307. </sect2>
  308. <sect2 id="zend.amf.server.typedobjects">
  309. <title>Objetos Tipados</title>
  310. <para>
  311. De modo similar ao <acronym>SOAP</acronym>, <acronym>AMF</acronym> permite que sejam
  312. passados objetos entre o cliente e o servidor. Isso permite uma grande quantidade de
  313. flexibilidade e coerência entre os dois ambientes.
  314. </para>
  315. <para>
  316. <classname>Zend_Amf</classname> fornece três métodos para mapeamento entre objetos
  317. ActionScript e <acronym>PHP</acronym>.
  318. </para>
  319. <itemizedlist>
  320. <listitem>
  321. <para>
  322. Primeiro, você deve criar explicitamente ligações no nível do servidor, usando o
  323. método <methodname>setClassMap()</methodname>. O primeiro argumento é o nome da
  324. classe ActionScript, o segundo é a classe <acronym>PHP</acronym> que a mapeia:
  325. </para>
  326. <programlisting language="php"><![CDATA[
  327. // Mapeia a classe ActionScript 'ContactVO' para a classe PHP 'Contact':
  328. $server->setClassMap('ContactVO', 'Contact');
  329. ]]></programlisting>
  330. </listitem>
  331. <listitem>
  332. <para>
  333. Em segundo lugar, você definir a propriedade pública
  334. <varname>$_explicitType</varname> em sua classe <acronym>PHP</acronym>, com o
  335. valor representando a classe ActionScript para mapear:
  336. </para>
  337. <programlisting language="php"><![CDATA[
  338. class Contact
  339. {
  340. public $_explicitType = 'ContactVO';
  341. }
  342. ]]></programlisting>
  343. </listitem>
  344. <listitem>
  345. <para>
  346. Terceiro, de maneira similar, você pode definir o método público
  347. <methodname>getASClassName()</methodname> em sua classe <acronym>PHP</acronym>;
  348. este método deve retornar a classe ActionScript apropriada:
  349. </para>
  350. <programlisting language="php"><![CDATA[
  351. class Contact
  352. {
  353. public function getASClassName()
  354. {
  355. return 'ContactVO';
  356. }
  357. }
  358. ]]></programlisting>
  359. </listitem>
  360. </itemizedlist>
  361. <para>
  362. Embora tenhamos criado o ContactVO no servidor precisamos agora fazer a classe
  363. correspondente em <acronym>AS3</acronym> para que o objeto de servidor seja mapeado.
  364. </para>
  365. <para>
  366. Clique com o botão direito na pasta <filename>src</filename> de seu projeto Flex e
  367. selecione 'New' -> 'ActionScript File'. Nomeie o arquivo como 'ContactVO' e pressione
  368. 'finish' para ver o novo arquivo. Copie o seguinte código para finalizar a criação da
  369. classe.
  370. </para>
  371. <programlisting language="as"><![CDATA[
  372. package
  373. {
  374. [Bindable]
  375. [RemoteClass(alias="ContactVO")]
  376. public class ContactVO
  377. {
  378. public var id:int;
  379. public var firstname:String;
  380. public var lastname:String;
  381. public var email:String;
  382. public var mobile:String;
  383. public function ContactVO():void {
  384. }
  385. }
  386. }
  387. ]]></programlisting>
  388. <para>
  389. A classe é sintaticamente equivalente à classe <acronym>PHP</acronym> com o mesmo nome.
  390. Os nomes de variáveis são exatamente os mesmos e precisam estar sob o mesmo caso para
  391. que funcione apropriadamente. Existem duas marcações meta (meta tags)
  392. <acronym>AS3</acronym> únicas nesta classe. A primeira é Bindable, que faz com
  393. que um evento de alteração (change) seja disparado quando ela é atualizada. A segunda
  394. marcação é RemoteClass, que define que esta classe pode ter um objeto remoto mapeado a
  395. ela com um apelido, neste caso <emphasis>ContactVO</emphasis>. É obrigatório que o valor
  396. desta marcação seja definido seja estritamente equivalente ao da classe
  397. <acronym>PHP</acronym>.
  398. </para>
  399. <programlisting language="as"><![CDATA[
  400. [Bindable]
  401. private var myContact:ContactVO;
  402. private function getContactHandler(event:ResultEvent):void {
  403. myContact = ContactVO(event.result);
  404. }
  405. ]]></programlisting>
  406. <para>
  407. O evento de resultado gerado pela chamada ao serviço é instantaneamente convertido para
  408. o ContactVO do Flex. Qualquer coisa que seja direcionada a <varname>myContact</varname>
  409. será atualizado e os dados de ContactVO serão retornados.
  410. </para>
  411. </sect2>
  412. <sect2 id="zend.amf.server.resources">
  413. <title>Recursos</title>
  414. <para>
  415. <classname>Zend_Amf</classname> fornece ferramentas para mapear tipos de recursos
  416. retornados por classes de serviços em informações consumíveis pelo ActionScript.
  417. </para>
  418. <para>
  419. A fim de lidar com tipo de recurso específico, o usuário precisa criar uma classe plugin
  420. chamado após o nome do recurso, com palavras em maiúsculas e espaços removidos (assim
  421. recurso do tipo "resultado mysql" torna-se ResultadoMysql), com algum prefixo, ex.:
  422. <classname>Meu_ResultadoMysql</classname>. Esta classe precisa implementar um método,
  423. <methodname>parse()</methodname>, recebendo um argumento - o recurso - e retornando o
  424. valor a ser enviado para o ActionScript. A classe deve estar localizada no arquivo
  425. chamado após o nome do componente, ex.: <filename>ResultadoMysql.php</filename>.
  426. </para>
  427. <para>
  428. O diretório contendo os plugins para manipulação de recursos devem ser registrados com o
  429. carregador de tipo <classname>Zend_Amf</classname>:
  430. </para>
  431. <programlisting language="php"><![CDATA[
  432. Zend_Amf_Parse_TypeLoader::addResourceDirectory(
  433. "Meu",
  434. "application/library/recursos/Meu"
  435. );
  436. ]]></programlisting>
  437. <para>
  438. Para uma discussão detalhada sobre o plugins carregadores, por favor veja a seção
  439. <link linkend="zend.loader.pluginloader">plugin carregador</link>.
  440. </para>
  441. <para>
  442. O diretório padrão para recursos <classname>Zend_Amf</classname> é registrado
  443. automaticamente e atualmente contém manipuladores para recursos "resultado mysql" e
  444. "stream".
  445. </para>
  446. <programlisting language="php"><![CDATA[
  447. // Classe de exemplo implementando a manipulação de recursos do tipo "resultado mysql"
  448. class Zend_Amf_Parse_Recurso_ResultadoMysql
  449. {
  450. /**
  451. * Decodifica o recurso em uma matriz
  452. *
  453. * @param resource $resource
  454. * @return array
  455. */
  456. public function parse($resource) {
  457. $result = array();
  458. while($row = mysql_fetch_assoc($resource)) {
  459. $result[] = $row;
  460. }
  461. return $result;
  462. }
  463. }
  464. ]]></programlisting>
  465. <para>
  466. Ao tentar retornar um tipo desconhecido de recirso (ex., um para o qual não haja plugin
  467. manipulador existente) resultará em uma exceção.
  468. </para>
  469. </sect2>
  470. <sect2 id="zend.amf.server.flash">
  471. <title>Conectando ao Servidor a partir do Flash</title>
  472. <para>
  473. Conectando ao seu <classname>Zend_Amf_Server</classname> a partir de seu projeto Flash é
  474. ligeiramente diferente do que com Flex. Contudo, depois da conexão, Flash funciona com
  475. <classname>Zend_Amf_Server</classname> da mesma forma que com Flex. O exemplo a seguir
  476. também pode ser usado com um arquivo <acronym>AS3</acronym> do Flex. Reutilizaremos a
  477. mesma configuração <classname>Zend_Amf_Server</classname> com a classe Mundo para nossa
  478. conexão.
  479. </para>
  480. <para>
  481. Abra o Flash CS e crie um novo arquivo Flash (ActionScript 3). Nomeie o documento
  482. <filename>ExemploZend.fla</filename> e salve o documento em uma pasta que você usará
  483. para este exemplo. Crie uma nova classe <acronym>AS3</acronym> no mesmo diretório e
  484. nomeie o arquivo como <filename>Principal.as</filename>. Tenha ambos os arquivos abertos
  485. em seu editor. Vamos conectar os dois arquivos através da classe de documento. Selecione
  486. ExemploZend e clique no palco. No painel de propriedade dos palco, altere a classe de
  487. documento (Document class) para Principal. Isso ligará o arquivo ActionScript
  488. <filename>Principal.as</filename> com a interface do usuário do arquivo
  489. <filename>ExemploZend.fla</filename>. Quando você executa o arquivo Flash ExemploZend, a
  490. classe <filename>Principal.as</filename> será executada agora. Agora, vamos adicionar o
  491. código ActionScript para fazer a chamada <acronym>AMF</acronym>.
  492. </para>
  493. <para>
  494. Agora nós faremos a classe Principal de modo que possamos enviar dados ao servidor e
  495. exibir o resultado. Copie o código a seguir para seu arquivo
  496. <filename>Principal.as</filename> e depois vamos descrever, passo a passo, o papel de
  497. cada elemento nele.
  498. </para>
  499. <programlisting language="as"><![CDATA[
  500. package {
  501. import flash.display.MovieClip;
  502. import flash.events.*;
  503. import flash.net.NetConnection;
  504. import flash.net.Responder;
  505. public class Principal extends MovieClip {
  506. private var gateway:String = "http://exemplo.com/server.php";
  507. private var connection:NetConnection;
  508. private var responder:Responder;
  509. public function Principal() {
  510. responder = new Responder(onResult, onFault);
  511. connection = new NetConnection;
  512. connection.addEventListener(NetStatusEvent.NET_STATUS, onComplete);
  513. connection.connect(gateway);
  514. }
  515. public function onComplete( e:NetStatusEvent ):void {
  516. if(e.info.code == "NetGroup.Connect.Succcess") {
  517. var params = "Sent to Server";
  518. connection.call("Mundo.alo", responder, params);
  519. }
  520. }
  521. private function onResult(result:Object):void {
  522. // Display the returned data
  523. trace(String(result));
  524. }
  525. private function onFault(fault:Object):void {
  526. trace(String(fault.description));
  527. }
  528. }
  529. }
  530. ]]></programlisting>
  531. <para>
  532. Primeiro precisamos importar duas bibliotecas ActionScriot que executam a maior parte do
  533. trabalho. A primeira é NetConnection que atua como um tubo bi-direcional entre o cliente
  534. e o servidor. A segunda é o objeto Responder, que manipula os valores de retorno do
  535. servidor relacionados ao sucesso ou falha da chamada.
  536. </para>
  537. <programlisting language="as"><![CDATA[
  538. import flash.net.NetConnection;
  539. import flash.net.Responder;
  540. ]]></programlisting>
  541. <para>
  542. Na classe, precisamos de três variáveis para representar a NetConnection, Responder e a
  543. <acronym>URL</acronym> da porta de entrada (gateway) para nossa instalação
  544. <classname>Zend_Amf_Server</classname>.
  545. </para>
  546. <programlisting language="as"><![CDATA[
  547. private var gateway:String = "http://exemplo.com/server.php";
  548. private var connection:NetConnection;
  549. private var responder:Responder;
  550. ]]></programlisting>
  551. <para>
  552. No contrutor de Principal criamos um respondedor e uma nova conexão ao
  553. ponto de extremidade (gateway) <classname>Zend_Amf_Server</classname>. O respondedor
  554. define dois métodos diferentes para manipular as respostas do servidor. Por simplicidade
  555. eles foram chamados de onResult e onFault.
  556. </para>
  557. <programlisting language="as"><![CDATA[
  558. responder = new Responder(onResult, onFault);
  559. connection = new NetConnection;
  560. connection.addEventListener(NetStatusEvent.NET_STATUS, onComplete);
  561. connection.connect(gateway);
  562. ]]></programlisting>
  563. <para>
  564. Na função onComplete, que é executada assim que o construtor tenha sido terminado, nós
  565. enviamos dados ao servidor. Precisamos adicionar mais uma linha que realiza a chamada a
  566. função Mundo->alo do <classname>Zend_Amf_Server</classname>
  567. </para>
  568. <programlisting language="as"><![CDATA[
  569. connection.call("Mundo.alo", responder, params);
  570. ]]></programlisting>
  571. <para>
  572. Quando instanciamos a variável responder, definimos uma função onResult e onFault para
  573. manipular a resposta do servidor. Adicionamos esta função para um resultado de sucesso
  574. vindo do servidor. Um manipulador de eventos de sucesso é executado sempre que uma
  575. conexão é manipulada apropriadamente no servidor.
  576. </para>
  577. <programlisting language="as"><![CDATA[
  578. private function onResult(result:Object):void {
  579. // Mostra os dados retornados
  580. trace(String(result));
  581. }
  582. ]]></programlisting>
  583. <para>
  584. A função onFault é chamada se há uma resposta inválida vinda do servidor. Isso acontece
  585. quando há um erro no servidor, a <acronym>URL</acronym> para o servidor é inválida, o
  586. serviço remoto ou método não existe ou se há qualquer outro problema relacionado à
  587. conexão.
  588. </para>
  589. <programlisting language="as"><![CDATA[
  590. private function onFault(fault:Object):void {
  591. trace(String(fault.description));
  592. }
  593. ]]></programlisting>
  594. <para>
  595. Completamos então a inclusão do ActionScript para realizar a conexão remota. Executando
  596. o arquivo ExemploZend agora faz a conexão ao <classname>Zend_Amf</classname>. Numa
  597. revisão, você adicionou as variáveis necessárias para abrir uma conexão ao servidor
  598. remoto, definiu quais métodos devem ser usados em sua aplicação para receber respostas
  599. do servidor e finalmente exibido os dados retornados através da função
  600. <methodname>trace()</methodname>.
  601. </para>
  602. </sect2>
  603. <sect2 id="zend.amf.server.auth">
  604. <title>Autenticação</title>
  605. <para>
  606. <classname>Zend_Amf_Server</classname> permite que você especifique ganchos de
  607. autentcação e autorização para controlar acesso aos serviços. Isso é feito usando a
  608. infraestrutura fornecida pelos componentes
  609. <link linkend="zend.auth"><classname>Zend_Auth</classname></link> e
  610. <link linkend="zend.acl"><classname>Zend_Acl</classname></link>.
  611. </para>
  612. <para>
  613. Para definir autenticação, o usuário fornece um adaptador de autenticação extendendo a
  614. classe abstrata <classname>Zend_Amf_Auth_Abstract</classname>. O adaptador deve
  615. implementar o método <methodname>authenticate()</methodname> como qualquer outro
  616. <link linkend="zend.auth.introduction.adapters">adaptador de autenticação</link>.
  617. </para>
  618. <para>
  619. O adaptador deve utilizar as propriedades <emphasis>_username</emphasis> e
  620. <emphasis>_password</emphasis> da classe pai,
  621. <classname>Zend_Amf_Auth_Adapter</classname>, para autenticar. Estes valores são
  622. definidos pelo servidor usando o método <methodname>setCredentials()</methodname> antes
  623. da chamada à <methodname>authenticate()</methodname> se as credenciais forem recebidas
  624. nos cabeçalhos da requisição <acronym>AMF</acronym>.
  625. </para>
  626. <para>
  627. A identidade retornada pelo adaptador deve ser um objeto contendo a propriedade
  628. <property>role</property> para que o controle de acesso da <acronym>ACL</acronym>
  629. funcione.
  630. </para>
  631. <para>
  632. Se o resultado da autenticação não for bem sucedido, a requisição não é mais procesada e
  633. uma mensagem de falha é retornada contendo as razões da falha obtida do resultado.
  634. </para>
  635. <para>
  636. O adaptador é conectado ao servidor usando o método <methodname>setAuth()</methodname>:
  637. </para>
  638. <programlisting language="php"><![CDATA[
  639. $server->setAuth(new My_Amf_Auth());
  640. ]]></programlisting>
  641. <para>
  642. O controle de acesso é realizado usando um objeto <classname>Zend_Acl</classname>
  643. definido pelo método <methodname>setAcl()</methodname>:
  644. </para>
  645. <programlisting language="php"><![CDATA[
  646. $acl = new Zend_Acl();
  647. criarPermissoes($acl); // Cria a estrutura de permissões
  648. $server->setAcl($acl);
  649. ]]></programlisting>
  650. <para>
  651. Se o objeto <acronym>ACL</acronym> é definido e a classe sendo chamada define o método
  652. <methodname>initAcl()</methodname>, este método será chamado com o objeto
  653. <acronym>ACL</acronym> como um argumento. A classe depois cria regras
  654. <acronym>ACL</acronym> adicionais e retorna <constant>TRUE</constant>, ou retorna
  655. <constant>FALSE</constant> se nenhum controle de acesso for necessário para esta classe.
  656. </para>
  657. <para>
  658. Depois de a <acronym>ACL</acronym> ser definida, o servidor verificará se o acesso é
  659. permitido com o papel definido pela autenticação, sendo o recurso o nome da classe (ou
  660. <constant>NULL</constant> para chamadas de funções) e o privileǵio sendo o nome da
  661. função. Se nenhuma autenticação for fornecida, e se o papel
  662. <emphasis>anonymous</emphasis> foi definido, ele será usado, em outro caso o acesso será
  663. negado.
  664. </para>
  665. <programlisting language="php"><![CDATA[
  666. if($this->_acl->isAllowed($role, $class, $function)) {
  667. return true;
  668. } else {
  669. require_once 'Zend/Amf/Server/Exception.php';
  670. throw new Zend_Amf_Server_Exception("Accesso não permitido");
  671. }
  672. ]]></programlisting>
  673. </sect2>
  674. </sect1>
  675. <!--
  676. vim:se ts=4 sw=4 et:
  677. -->