Zend_Amf-Server.xml 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  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 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, channel, 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 ao caminhos de
  139. seus projetos e pressione 'Ok' para fechar a janela.
  140. </para>
  141. <para>
  142. You will also need to tell the compiler to use the
  143. <filename>service-config.xml</filename> to find the RemoteObject endpoint. To do this
  144. open your project properties panel again by right clicking on the project folder from
  145. your Navigator and selecting properties. From the properties popup select 'Flex
  146. Compiler' and add the string: <command>-services "services-config.xml"</command>. Press
  147. Apply then OK to return to update the option. What you have just done is told the Flex
  148. compiler to look to the <filename>services-config.xml</filename> file for runtime
  149. variables that will be used by the RemotingObject class.
  150. </para>
  151. <para>
  152. We now need to tell Flex which services configuration file to use for connecting to
  153. our remote methods. For this reason create a new
  154. '<filename>services-config.xml</filename>' file into your Flex project src folder. To
  155. do this right click on the project folder and select 'new' 'File' which will popup a
  156. new window. Select the project folder and then name the file
  157. '<filename>services-config.xml</filename>' and press finish.
  158. </para>
  159. <para>
  160. Flex has created the new <filename>services-config.xml</filename> and has it open. Use
  161. the following example text for your <filename>services-config.xml</filename> file. Make
  162. sure that you update your endpoint to match that of your testing server. Make sure you
  163. save the file.
  164. </para>
  165. <programlisting language="xml"><![CDATA[
  166. <?xml version="1.0" encoding="UTF-8"?>
  167. <services-config>
  168. <services>
  169. <service id="zend-service"
  170. class="flex.messaging.services.RemotingService"
  171. messageTypes="flex.messaging.messages.RemotingMessage">
  172. <destination id="zend">
  173. <channels>
  174. <channel ref="zend-endpoint"/>
  175. </channels>
  176. <properties>
  177. <source>*</source>
  178. </properties>
  179. </destination>
  180. </service>
  181. </services>
  182. <channels>
  183. <channel-definition id="zend-endpoint"
  184. class="mx.messaging.channels.AMFChannel">
  185. <endpoint uri="http://example.com/server.php"
  186. class="flex.messaging.endpoints.AMFEndpoint"/>
  187. </channel-definition>
  188. </channels>
  189. </services-config>
  190. ]]></programlisting>
  191. <para>
  192. There are two key points in the example. First, but last in the
  193. listing, we create an <acronym>AMF</acronym> channel, and specify the endpoint as the
  194. <acronym>URL</acronym> to our <classname>Zend_Amf_Server</classname>:
  195. </para>
  196. <programlisting language="xml"><![CDATA[
  197. <channel-definition id="zend-endpoint"
  198. <endpoint uri="http://example.com/server.php"
  199. class="flex.messaging.endpoints.AMFEndpoint"/>
  200. </channel-definition>
  201. ]]></programlisting>
  202. <para>
  203. Notice that we've given this channel an identifier, "zend-endpoint".
  204. The example create a service destination that refers to this channel,
  205. assigning it an ID as well -- in this case "zend".
  206. </para>
  207. <para>
  208. Within our Flex <acronym>MXML</acronym> files, we need to bind a RemoteObject to the
  209. service. In <acronym>MXML</acronym>, this might be done as follows:
  210. </para>
  211. <programlisting language="xml"><![CDATA[
  212. <mx:RemoteObject id="myservice"
  213. fault="faultHandler(event)"
  214. showBusyCursor="true"
  215. destination="zend">
  216. ]]></programlisting>
  217. <para>
  218. Here, we've defined a new remote object identified by "myservice"
  219. bound to the service destination "zend" we defined in the
  220. <filename>services-config.xml</filename> file. We then call methods on it
  221. in our ActionScript by simply calling "myservice.&lt;method&gt;".
  222. As an example:
  223. </para>
  224. <programlisting language="ActionScript"><![CDATA[
  225. myservice.hello("Wade");
  226. ]]></programlisting>
  227. <para>
  228. When namespacing, you would use
  229. "myservice.&lt;namespace&gt;.&lt;method&gt;":
  230. </para>
  231. <programlisting language="ActionScript"><![CDATA[
  232. myservice.world.hello("Wade");
  233. ]]></programlisting>
  234. <para>
  235. For more information on Flex RemoteObject invocation, <ulink
  236. url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">
  237. visit the Adobe Flex 3 Help site</ulink>.
  238. </para>
  239. </sect2>
  240. <sect2 id="zend.amf.server.errors">
  241. <title>Error Handling</title>
  242. <para>
  243. By default, all exceptions thrown in your attached classes or
  244. functions will be caught and returned as <acronym>AMF</acronym> ErrorMessages. However,
  245. the content of these ErrorMessage objects will vary based on whether
  246. or not the server is in "production" mode (the default state).
  247. </para>
  248. <para>
  249. When in production mode, only the exception code will be returned.
  250. If you disable production mode -- something that should be done for
  251. testing only -- most exception details will be returned: the
  252. exception message, line, and backtrace will all be attached.
  253. </para>
  254. <para>
  255. To disable production mode, do the following:
  256. </para>
  257. <programlisting language="php"><![CDATA[
  258. $server->setProduction(false);
  259. ]]></programlisting>
  260. <para>
  261. To re-enable it, pass a <constant>TRUE</constant> boolean value instead:
  262. </para>
  263. <programlisting language="php"><![CDATA[
  264. $server->setProduction(true);
  265. ]]></programlisting>
  266. <note>
  267. <title>Disable production mode sparingly!</title>
  268. <para>
  269. We recommend disabling production mode only when in development.
  270. Exception messages and backtraces can contain sensitive system
  271. information that you may not wish for outside parties to access.
  272. Even though <acronym>AMF</acronym> is a binary format, the specification is now
  273. open, meaning anybody can potentially deserialize the payload.
  274. </para>
  275. </note>
  276. <para>
  277. One area to be especially careful with is <acronym>PHP</acronym> errors themselves.
  278. When the <property>display_errors</property> <acronym>INI</acronym> directive is
  279. enabled, any <acronym>PHP</acronym> errors for the current error reporting level are
  280. rendered directly in the output -- potentially disrupting the <acronym>AMF</acronym>
  281. response payload. We suggest turning off the <property>display_errors</property>
  282. directive in production to prevent such problems
  283. </para>
  284. </sect2>
  285. <sect2 id="zend.amf.server.response">
  286. <title>AMF Responses</title>
  287. <para>
  288. Occasionally you may desire to manipulate the response object
  289. slightly, typically to return extra message headers. The
  290. <methodname>handle()</methodname> method of the server returns the response
  291. object, allowing you to do so.
  292. </para>
  293. <example id="zend.amf.server.response.messageHeaderExample">
  294. <title>Adding Message Headers to the AMF Response</title>
  295. <para>
  296. In this example, we add a 'foo' MessageHeader with the value
  297. 'bar' to the response prior to returning it.
  298. </para>
  299. <programlisting language="php"><![CDATA[
  300. $response = $server->handle();
  301. $response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
  302. echo $response;
  303. ]]></programlisting>
  304. </example>
  305. </sect2>
  306. <sect2 id="zend.amf.server.typedobjects">
  307. <title>Typed Objects</title>
  308. <para>
  309. Similar to <acronym>SOAP</acronym>, <acronym>AMF</acronym> allows passing objects
  310. between the client and server. This allows a great amount of flexibility and
  311. coherence between the two environments.
  312. </para>
  313. <para>
  314. <classname>Zend_Amf</classname> provides three methods for mapping
  315. ActionScript and <acronym>PHP</acronym> objects.
  316. </para>
  317. <itemizedlist>
  318. <listitem>
  319. <para>
  320. First, you may create explicit bindings at the server level,
  321. using the <methodname>setClassMap()</methodname> method. The first
  322. argument is the ActionScript class name, the second the <acronym>PHP</acronym>
  323. class name it maps to:
  324. </para>
  325. <programlisting language="php"><![CDATA[
  326. // Map the ActionScript class 'ContactVO' to the PHP class 'Contact':
  327. $server->setClassMap('ContactVO', 'Contact');
  328. ]]></programlisting>
  329. </listitem>
  330. <listitem>
  331. <para>
  332. Second, you can set the public property <varname>$_explicitType</varname>
  333. in your <acronym>PHP</acronym> class, with the
  334. value representing the ActionScript class to map to:
  335. </para>
  336. <programlisting language="php"><![CDATA[
  337. class Contact
  338. {
  339. public $_explicitType = 'ContactVO';
  340. }
  341. ]]></programlisting>
  342. </listitem>
  343. <listitem>
  344. <para>
  345. Third, in a similar vein, you may define the public method
  346. <methodname>getASClassName()</methodname> in your <acronym>PHP</acronym> class;
  347. this method should return the appropriate ActionScript class:
  348. </para>
  349. <programlisting language="php"><![CDATA[
  350. class Contact
  351. {
  352. public function getASClassName()
  353. {
  354. return 'ContactVO';
  355. }
  356. }
  357. ]]></programlisting>
  358. </listitem>
  359. </itemizedlist>
  360. <para>
  361. Although we have created the ContactVO on the server we now need to make its
  362. corresponding class in <acronym>AS3</acronym> for the server object to be mapped to.
  363. </para>
  364. <para>
  365. Right click on the src folder of the Flex project and select New -> ActionScript
  366. File. Name the file ContactVO and press finish to see the new file. Copy the
  367. following code into the file to finish creating the class.
  368. </para>
  369. <programlisting language="as"><![CDATA[
  370. package
  371. {
  372. [Bindable]
  373. [RemoteClass(alias="ContactVO")]
  374. public class ContactVO
  375. {
  376. public var id:int;
  377. public var firstname:String;
  378. public var lastname:String;
  379. public var email:String;
  380. public var mobile:String;
  381. public function ProductVO():void {
  382. }
  383. }
  384. }
  385. ]]></programlisting>
  386. <para>
  387. The class is syntactically equivalent to the <acronym>PHP</acronym> of the same name.
  388. The variable names are exactly the same and need to be in the same case
  389. to work properly. There are two unique <acronym>AS3</acronym> meta tags in this class.
  390. The first is bindable which makes fire a change event when it is updated.
  391. The second tag is the RemoteClass tag which defines that this class can
  392. have a remote object mapped with the alias name in this case
  393. <emphasis>ContactVO</emphasis>. It is mandatory that this tag the value that was set
  394. is the <acronym>PHP</acronym> class are strictly equivalent.
  395. </para>
  396. <programlisting language="as"><![CDATA[
  397. [Bindable]
  398. private var myContact:ContactVO;
  399. private function getContactHandler(event:ResultEvent):void {
  400. myContact = ContactVO(event.result);
  401. }
  402. ]]></programlisting>
  403. <para>
  404. The following result event from the service call is cast instantly onto the Flex
  405. ContactVO. Anything that is bound to myContact will be updated with the returned
  406. ContactVO data.
  407. </para>
  408. </sect2>
  409. <sect2 id="zend.amf.server.resources">
  410. <title>Resources</title>
  411. <para>
  412. <classname>Zend_Amf</classname> provides tools for mapping resource types
  413. returned by service classes into data consumable by ActionScript.
  414. </para>
  415. <para>
  416. In order to handle specific resource type, the user needs to create a plugin class named
  417. after the resource name, with words capitalized and spaces removed (so, resource
  418. type "mysql result" becomes MysqlResult), with some prefix, e.g.
  419. <classname>My_MysqlResult</classname>. This class should implement one method,
  420. <methodname>parse()</methodname>, receiving one argument - the resource - and returning
  421. the value that should be sent to ActionScript. The class should be located in the file
  422. named after the last component of the name, e.g. <filename>MysqlResult.php</filename>.
  423. </para>
  424. <para>
  425. The directory containing the resource handling plugins should be registered with
  426. <classname>Zend_Amf</classname> type loader:
  427. </para>
  428. <programlisting language="php"><![CDATA[
  429. Zend_Amf_Parse_TypeLoader::addResourceDirectory(
  430. "My",
  431. "application/library/resources/My"
  432. );
  433. ]]></programlisting>
  434. <para>
  435. For detailed discussion of loading plugins, please see
  436. the <link linkend="zend.loader.pluginloader">plugin loader</link> section.
  437. </para>
  438. <para>
  439. Default directory for <classname>Zend_Amf</classname> resources is registered
  440. automatically and currently contains handlers for "mysql result" and "stream"
  441. resources.
  442. </para>
  443. <programlisting language="php"><![CDATA[
  444. // Example class implementing handling resources of type mysql result
  445. class Zend_Amf_Parse_Resource_MysqlResult
  446. {
  447. /**
  448. * Parse resource into array
  449. *
  450. * @param resource $resource
  451. * @return array
  452. */
  453. public function parse($resource) {
  454. $result = array();
  455. while($row = mysql_fetch_assoc($resource)) {
  456. $result[] = $row;
  457. }
  458. return $result;
  459. }
  460. }
  461. ]]></programlisting>
  462. <para>
  463. Trying to return unknown resource type (i.e., one for which no handler plugin exists)
  464. will result in an exception.
  465. </para>
  466. </sect2>
  467. <sect2 id="zend.amf.server.flash">
  468. <title>Connecting to the Server from Flash</title>
  469. <para>
  470. Connecting to your <classname>Zend_Amf_Server</classname> from your Flash project is
  471. slightly different than from Flex. However once the connection Flash functions with
  472. <classname>Zend_Amf_Server</classname> the same way is flex. The following example can
  473. also be used from a Flex <acronym>AS3</acronym> file. We will reuse the same
  474. <classname>Zend_Amf_Server</classname> configuration along with the World class for our
  475. connection.
  476. </para>
  477. <para>
  478. Open Flash CS and create and new Flash File (ActionScript 3). Name the document
  479. <filename>ZendExample.fla</filename> and save the document into a folder that you will
  480. use for this example. Create a new <acronym>AS3</acronym> file in the same directory
  481. and call the file <filename>Main.as</filename>. Have both files open in your editor. We
  482. are now going to connect the two files via the document class. Select ZendExample and
  483. click on the stage. From the stage properties panel change the Document class to Main.
  484. This links the <filename>Main.as</filename> ActionScript file with the user interface
  485. in <filename>ZendExample.fla</filename>. When you run the Flash file ZendExample the
  486. <filename>Main.as</filename> class will now be run. Next we will add ActionScript to
  487. make the <acronym>AMF</acronym> call.
  488. </para>
  489. <para>
  490. We now are going to make a Main class so that we can send the data to the server and
  491. display the result. Copy the following code into your <filename>Main.as</filename> file
  492. and then we will walk through the code to describe what each element's role is.
  493. </para>
  494. <programlisting language="as"><![CDATA[
  495. package {
  496. import flash.display.MovieClip;
  497. import flash.events.*;
  498. import flash.net.NetConnection;
  499. import flash.net.Responder;
  500. public class Main extends MovieClip {
  501. private var gateway:String = "http://example.com/server.php";
  502. private var connection:NetConnection;
  503. private var responder:Responder;
  504. public function Main() {
  505. responder = new Responder(onResult, onFault);
  506. connection = new NetConnection;
  507. connection.connect(gateway);
  508. }
  509. public function onComplete( e:Event ):void{
  510. var params = "Sent to Server";
  511. connection.call("World.hello", responder, params);
  512. }
  513. private function onResult(result:Object):void {
  514. // Display the returned data
  515. trace(String(result));
  516. }
  517. private function onFault(fault:Object):void {
  518. trace(String(fault.description));
  519. }
  520. }
  521. }
  522. ]]></programlisting>
  523. <para>
  524. We first need to import two ActionScript libraries that perform the bulk of the work.
  525. The first is NetConnection which acts like a by directional pipe between the client and
  526. the server. The second is a Responder object which handles the return values from the
  527. server related to the success or failure of the call.
  528. </para>
  529. <programlisting language="as"><![CDATA[
  530. import flash.net.NetConnection;
  531. import flash.net.Responder;
  532. ]]></programlisting>
  533. <para>
  534. In the class we need three variables to represent the NetConnection, Responder, and
  535. the gateway <acronym>URL</acronym> to our <classname>Zend_Amf_Server</classname>
  536. installation.
  537. </para>
  538. <programlisting language="as"><![CDATA[
  539. private var gateway:String = "http://example.com/server.php";
  540. private var connection:NetConnection;
  541. private var responder:Responder;
  542. ]]></programlisting>
  543. <para>
  544. In the Main constructor we create a responder and a new connection to the
  545. <classname>Zend_Amf_Server</classname> endpoint. The responder defines two different
  546. methods for handling the response from the server. For simplicity I have called these
  547. onResult and onFault.
  548. </para>
  549. <programlisting language="as"><![CDATA[
  550. responder = new Responder(onResult, onFault);
  551. connection = new NetConnection;
  552. connection.connect(gateway);
  553. ]]></programlisting>
  554. <para>
  555. In the onComplete function which is run as soon as the construct has completed we send
  556. the data to the server. We need to add one more line that makes a call to the
  557. <classname>Zend_Amf_Server</classname> World->hello function.
  558. </para>
  559. <programlisting language="as"><![CDATA[
  560. connection.call("World.hello", responder, params);
  561. ]]></programlisting>
  562. <para>
  563. When we created the responder variable we defined an onResult and onFault function to
  564. handle the response from the server. We added this function for the successful result
  565. from the server. A successful event handler is run every time the connection is handled
  566. properly to the server.
  567. </para>
  568. <programlisting language="as"><![CDATA[
  569. private function onResult(result:Object):void {
  570. // Display the returned data
  571. trace(String(result));
  572. }
  573. ]]></programlisting>
  574. <para>
  575. The onFault function, is called if there was an invalid response from the server. This
  576. happens when there is an error on the server, the <acronym>URL</acronym> to the server
  577. is invalid, the remote service or method does not exist, and any other connection
  578. related issues.
  579. </para>
  580. <programlisting language="as"><![CDATA[
  581. private function onFault(fault:Object):void {
  582. trace(String(fault.description));
  583. }
  584. ]]></programlisting>
  585. <para>
  586. Adding in the ActionScript to make the remoting connection is now complete. Running the
  587. ZendExample file now makes a connection to <classname>Zend_Amf</classname>. In review
  588. you have added the required variables to open a connection to the remote server, defined
  589. what methods should be used when your application receives a response from the server,
  590. and finally displayed the returned data to output via <methodname>trace()</methodname>.
  591. </para>
  592. </sect2>
  593. <sect2 id="zend.amf.server.auth">
  594. <title>Authentication</title>
  595. <para>
  596. <classname>Zend_Amf_Server</classname> allows you to specify authentication and
  597. authorization hooks to control access to the services. It is using the infrastructure
  598. provided by <link linkend="zend.auth"><classname>Zend_Auth</classname></link> and
  599. <link linkend="zend.acl"><classname>Zend_Acl</classname></link> components.
  600. </para>
  601. <para>
  602. In order to define authentication, the user provides authentication adapter extening
  603. <classname>Zend_Amf_Auth_Abstract</classname> abstract class. The adapter should
  604. implement the <methodname>authenticate()</methodname> method just like regular
  605. <link linkend="zend.auth.introduction.adapters">authentication adapter</link>.
  606. </para>
  607. <para>
  608. The adapter should use properties <emphasis>_username</emphasis> and
  609. <emphasis>_password</emphasis> from the parent
  610. <classname>Zend_Amf_Auth_Abstract</classname> class in order to authenticate. These
  611. values are set by the server using <methodname>setCredentials()</methodname> method
  612. before call to <methodname>authenticate()</methodname> if the credentials are received
  613. in the <acronym>AMF</acronym> request headers.
  614. </para>
  615. <para>
  616. The identity returned by the adapter should be an object containing property
  617. <property>role</property> for the <acronym>ACL</acronym> access control to work.
  618. </para>
  619. <para>
  620. If the authentication result is not successful, the request is not proceseed further
  621. and failure message is returned with the reasons for failure taken from the result.
  622. </para>
  623. <para>
  624. The adapter is connected to the server using <methodname>setAuth()</methodname> method:
  625. </para>
  626. <programlisting language="php"><![CDATA[
  627. $server->setAuth(new My_Amf_Auth());
  628. ]]></programlisting>
  629. <para>
  630. Access control is performed by using <classname>Zend_Acl</classname> object set by
  631. <methodname>setAcl()</methodname> method:
  632. </para>
  633. <programlisting language="php"><![CDATA[
  634. $acl = new Zend_Acl();
  635. createPermissions($acl); // create permission structure
  636. $server->setAcl($acl);
  637. ]]></programlisting>
  638. <para>
  639. If the <acronym>ACL</acronym> object is set, and the class being called defines
  640. <methodname>initAcl()</methodname> method, this method will be called with the
  641. <acronym>ACL</acronym> object as an argument. The class then can create additional
  642. <acronym>ACL</acronym> rules and return <constant>TRUE</constant>, or return
  643. <constant>FALSE</constant> if no access control is required for this class.
  644. </para>
  645. <para>
  646. After <acronym>ACL</acronym> have been set up, the server will check if access is
  647. allowed with role set by the authentication, resource being the class name (or
  648. <constant>NULL</constant> for
  649. function calls) and privilege being the function name. If no authentication was
  650. provided, then if the <emphasis>anonymous</emphasis> role was defined, it will be used,
  651. otherwise the access will be denied.
  652. </para>
  653. <programlisting language="php"><![CDATA[
  654. if($this->_acl->isAllowed($role, $class, $function)) {
  655. return true;
  656. } else {
  657. require_once 'Zend/Amf/Server/Exception.php';
  658. throw new Zend_Amf_Server_Exception("Access not allowed");
  659. }
  660. ]]></programlisting>
  661. </sect2>
  662. </sect1>
  663. <!--
  664. vim:se ts=4 sw=4 et:
  665. -->