Zend_Amf-Server.xml 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 17136 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.amf.server">
  5. <title>Zend_Amf_Server</title>
  6. <para>
  7. <classname>Zend_Amf_Server</classname> proporciona un servidor al estilo
  8. <acronym>RPC</acronym> para tramitar solicitudes hechas desde Adobe Flash Player
  9. utilizando el protocolo <acronym>AMF</acronym>. Al igual que todas las clases de servidor,
  10. Zend Framework sigue la <acronym>API</acronym> de SoapServer, proporcionando una interfaz
  11. para crear servidores fácil de recordar. </para>
  12. <example id="zend.amf.server.basic">
  13. <title>Servidor AMF básico</title>
  14. <para> Asumamos que ha creado la clase <classname>Foo</classname> con una variedad de
  15. métodos públicos. Usando el siguiente código, puede crear un servidor
  16. <acronym>AMF</acronym>: </para>
  17. <programlisting language="php"><![CDATA[
  18. $servidor = new Zend_Amf_Server();
  19. $servidor->setClass('Foo');
  20. $respuesta = $servidor->handle();
  21. echo $respuesta;
  22. ]]></programlisting>
  23. <para> Alternativamente, en su lugar puede elegir agregar una función simple como llamada de
  24. retorno: </para>
  25. <programlisting language="php"><![CDATA[
  26. $servidor = new Zend_Amf_Server();
  27. $servidor->addFunction('myUberCoolFunction');
  28. $respuesta = $servidor->handle();
  29. echo $respuesta;
  30. ]]></programlisting>
  31. <para> También puede combinar y examinar la identidad de varias clases y funciones. Al
  32. hacerlo, sugerimos darle un espacio de nombres a cada una para garantizar que no ocurran
  33. colisiones entre nombres de métodos; puede hacerse simplemente pasando una segunda
  34. cadena de argumentos para cualquier <methodname>addFunction()</methodname> o
  35. <methodname>setClass()</methodname>: </para>
  36. <programlisting language="php"><![CDATA[
  37. $servidor = new Zend_Amf_Server();
  38. $servidor->addFunction('myUberCoolFunction', 'my')
  39. ->setClass('Foo', 'foo')
  40. ->setClass('Bar', 'bar');
  41. $respuesta = $servidor->handle();
  42. echo $respuesta;
  43. ]]></programlisting>
  44. <para> El <classname>Zend_Amf_Server</classname> también permite cargar servicios
  45. dinámicamente, en función de una ruta de directorio ya suministrada. Puede añadir al
  46. servidor tantos directorios como desee. El orden en que se añadan los directorios al
  47. servidor será el orden en que se realizarán las búsquedas <acronym>LIFO</acronym> en los
  48. directorios para coincidir con la clase. El método
  49. <methodname>addDirectory()</methodname> realiza la acción de añadir directorios. </para>
  50. <programlisting language="php"><![CDATA[
  51. $servidor->addDirectory(dirname(__FILE__) .'/../services/');
  52. $servidor->addDirectory(dirname(__FILE__) .'/../package/');
  53. ]]></programlisting>
  54. <para> Cuando se llama a servicios remotos, los nombres de los directorios que contengan las
  55. fuentes pueden tener los delimitadores guión bajo ("_") y el punto ("."). Cuando se
  56. utilize un guión bajo ("_") tanto en <acronym>PEAR</acronym> como en Zend Framework, se
  57. respetarán los nombres de clases de acuerdo a las convenciones de nomenclatura. Esto
  58. significa que si usted llama al servicio com_Foo_Bar el servidor
  59. buscará el archivo <filename>Bar.php</filename> en cada una de las rutas incluidas en
  60. <filename>com/Foo/Bar.php</filename>. Si se usa la notación punto para su servicio
  61. remoto como <filename>com.Foo.Bar</filename> cada ruta incluida deberá tener
  62. <filename>com/Foo/Bar.php</filename> agregado al final para autocargar
  63. <filename>Bar.php</filename>
  64. </para>
  65. <para> Todos las solicitudes <acronym>AMF</acronym> enviadas al script serán manejadas por
  66. el servidor, y este devolverá una respuesta <acronym>AMF</acronym>. </para>
  67. </example>
  68. <note>
  69. <title>Todos los métodos y las funciones agregadas requieren bloques de documentación
  70. (docblocks)</title>
  71. <para> Como todos los demás componentes del servidor en Zend Framework, debe documentar los
  72. métodos de su clase usando <acronym>PHP</acronym> docblocks. Como mínimo, necesita
  73. proporcionar anotaciones para cada argumento así como para el valor de retorno. Como
  74. ejemplos: </para>
  75. <programlisting language="php"><![CDATA[
  76. // Función que agregar:
  77. /**
  78. * @param string $nombre
  79. * @param string $saludo
  80. * @return string
  81. */
  82. function holaMundo($ombre, $saludo = 'Hola')
  83. {
  84. return $saludo . ', ' . $nombre;
  85. }
  86. ]]></programlisting>
  87. <programlisting language="php"><![CDATA[
  88. // Clase agregada
  89. class Mundo
  90. {
  91. /**
  92. * @param string $nombre
  93. * @param string $saludo
  94. * @return string
  95. */
  96. public function hola($nombre, $saludo = 'Hola')
  97. {
  98. return $saludo . ', ' . $nombre;
  99. }
  100. }
  101. ]]></programlisting>
  102. <para> Pueden usarse otras anotaciones, pero serán ignoradas. </para>
  103. </note>
  104. <sect2 id="zend.amf.server.flex">
  105. <title>Conectándose al Servidor desde Flex</title>
  106. <para> Conectarse a <classname>Zend_Amf_Server</classname> desde su proyecto Flex es
  107. bastante simple; solo necesita apuntar el final del <acronym>URI</acronym> a su script
  108. <classname>Zend_Amf_Server</classname>. </para>
  109. <para> Por ejemplo, digamos que ya ha creado su servidor y lo ha puesto en el fichero
  110. <filename>server.php</filename> en el directorio raíz (root) de su aplicación, por
  111. lo tanto la <acronym>URI</acronym> es
  112. <filename>http://example.com/server.php</filename>. En este caso, usted debería
  113. modificar su fichero <filename>service-config.xml</filename> poniendo este valor como
  114. atributo al punto final del canal uri. </para>
  115. <para> Si nunca ha creado un fichero <filename>service-config.xml</filename> puede hacerlo
  116. abriendo su proyecto en la ventana del navegador. Haga clic derecho sobre el nombre del
  117. proyecto y seleccione 'properties' (propiedades). En el cuadro de diálogo 'properties'
  118. del proyecto ir al menú ‘Flex Build Path' (Crear ruta Flex), luego en la pestaña
  119. ‘Library path’ (ruta de biblioteca) asegúrese de que el fichero
  120. '<filename>rpc.swc</filename>' sea añadido a su ruta de proyectos y pulse Ok
  121. (Aceptar) para cerrar la ventana. </para>
  122. <para> También necesitará indicarle al compilador que debe usar
  123. <filename>service-config.xml</filename> para encontrar el punto final de
  124. RemoteObject. Para hacerlo, abra de nuevo el panel de propiedades de su proyecto
  125. haciendo clic en el botón derecho sobre el proyecto en la carpeta del navegador y
  126. seleccione 'properties' (propiedades). Ahora seleccione ‘Flex Compiler' (Compilador
  127. Flex) y añada la cadena: <command>-services "services-config.xml"</command>. Presione
  128. 'Apply' (Aplicar) y luego en OK para volver a actualizar la opción. Lo que acaba de
  129. hacer es decirle al compilador Flex que busque en el fichero
  130. <filename>services-config.xml</filename> aquellas variables que se usarán en tiempo
  131. de ejecución por la clase RemotingObject. </para>
  132. <para> Ahora, para conectarnos a nuestros métodos remotos debemos indicarle a Flex qué
  133. fichero de configuración de servicios utilizar. Por esta razón creamos un nuevo fichero
  134. '<filename>services-config.xml</filename>' en la carpeta src del proyecto Flex. Con
  135. click derecho sobre el proyecto y seleccionando 'new'(nuevo) 'File' (fichero), se abrirá
  136. una nueva ventana. Seleccione la carpeta del proyecto y luego nombre el archivo
  137. '<filename>services-config.xml</filename>' y presione 'finish' (finalizar). </para>
  138. <para> Flex ha creado y abierto el nuevo fichero <filename>services-config.xml</filename>.
  139. Utilice el siguiente texto de ejemplo para su fichero
  140. <filename>services-config.xml</filename>. Asegúrese de actualizar su punto final
  141. para que concuerde con el servidor. Asegúrese también de guardar el fichero. </para>
  142. <programlisting language="xml"><![CDATA[
  143. <?xml version="1.0" encoding="UTF-8"?>
  144. <services-config>
  145. <services>
  146. <service id="zend-service"
  147. class="flex.messaging.services.RemotingService"
  148. messageTypes="flex.messaging.messages.RemotingMessage">
  149. <destination id="zend">
  150. <channels>
  151. <channel ref="zend-endpoint"/>
  152. </channels>
  153. <properties>
  154. <source>*</source>
  155. </properties>
  156. </destination>
  157. </service>
  158. </services>
  159. <channels>
  160. <channel-definition id="zend-endpoint"
  161. class="mx.messaging.channels.AMFChannel">
  162. <endpoint uri="http://example.com/server.php"
  163. class="flex.messaging.endpoints.AMFEndpoint"/>
  164. </channel-definition>
  165. </channels>
  166. </services-config>
  167. ]]></programlisting>
  168. <para> Hay dos puntos clave en el ejemplo. En primer lugar, pero último en el listado,
  169. creamos un canal <acronym>AMF</acronym>, y especificamos el punto final como la URL a
  170. nuestro <classname>Zend_Amf_Server</classname>: </para>
  171. <programlisting language="xml"><![CDATA[
  172. <channel-definition id="zend-endpoint"
  173. <endpoint uri="http://example.com/server.php"
  174. class="flex.messaging.endpoints.AMFEndpoint"/>
  175. </channel-definition>
  176. ]]></programlisting>
  177. <para> Advierta que a este canal le hemos dado un identificador, "zend-endpoint". El ejemplo
  178. crea un servicio cuyo destino hace referencia a este canal, asignándole también un ID,
  179. en este caso es "zend". </para>
  180. <para> Dentro de nuestros ficheros Flex <acronym>MXML</acronym>, necesitamos vincular un
  181. RemoteObject al servicio. En <acronym>MXML</acronym>, esto podría hacerse así: </para>
  182. <programlisting language="xml"><![CDATA[
  183. <mx:RemoteObject id="myservice"
  184. fault="faultHandler(event)"
  185. showBusyCursor="true"
  186. destination="zend">
  187. ]]></programlisting>
  188. <para> Aquí, hemos definido un nuevo objeto remoto identificado por "myservice" vinculado
  189. destino de servicio "zend" que hemos definido en el fichero
  190. <filename>services-config.xml</filename>. Entonces invocamos sus métodos en nuestro
  191. ActionScript simplemente llamando a "myservice.&lt;method&gt;". . A modo de
  192. ejemplo: </para>
  193. <programlisting language="ActionScript"><![CDATA[
  194. myservice.hello("Wade");
  195. ]]></programlisting>
  196. <para> Cuando se usan nombres-de-espacio, puede usarse
  197. "myservice.&lt;namespace&gt;.&lt;method&gt;": </para>
  198. <programlisting language="ActionScript"><![CDATA[
  199. myservice.world.hello("Wade");
  200. ]]></programlisting>
  201. <para> Para más información sobre como invocar a Flex RemoteObject visite el sitio de ayuda
  202. de Adobe Flex 3 en:<ulink
  203. url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html"/>.
  204. </para>
  205. </sect2>
  206. <sect2 id="zend.amf.server.errors">
  207. <title>Manejo de errores</title>
  208. <para> Por defecto, todas las excepciones producidas en sus clases o funciones adjuntas
  209. serán capturados y devueltas como mensajes de error de <acronym>AMF</acronym> (AMF
  210. ErrorMessages). Sin embargo, el contenido de estos objetos de mensajes de error variará
  211. dependiendo de si el servidor está o no en modo "producción" (el estado por defecto). </para>
  212. <para> Cuando se está en modo de producción, únicamente el código de excepción será
  213. devuelto. Si desactiva el modo de producción, algo que debe hacerse sólo para probar --
  214. serán devueltos más detalles de la excepción: el mensaje de excepción (error), línea y
  215. backtrace serán adjuntados. </para>
  216. <para> Para desactivar el modo de producción, haga lo siguiente: </para>
  217. <programlisting language="php"><![CDATA[
  218. $server->setProduction(false);
  219. ]]></programlisting>
  220. <para> Para habilitarlo nuevamente, pase el valor <constant>TRUE</constant> en su lugar. </para>
  221. <programlisting language="php"><![CDATA[
  222. $server->setProduction(true);
  223. ]]></programlisting>
  224. <note>
  225. <title>¡Deshabilite el modo de producción racionalmente!</title>
  226. <para> Sugerimos deshabilitar el modo de producción solo cuando se está en modo de
  227. desarrollo. Los mensajes de excepción y los backtraces puede contener información
  228. sensible del sistema, y no desea que se pueda acceder a ellas desde el exterior.
  229. Aunque <acronym>AMF</acronym> es un formato binario, ahora al ser abierta la
  230. especificación, cualquiera puede potencialmente deserializar los datos. </para>
  231. </note>
  232. <para> Un área en la que se debe tener especialmente mucho cuidado son los errores propios
  233. de <acronym>PHP</acronym>. Cuando la directiva <acronym>INI</acronym>
  234. <property>display_errors</property> está habilitada, los errores de
  235. <acronym>PHP</acronym> de cualquier nivel del reporte actual serán pasados
  236. directamente a la salida, y potencialmente se podrían hacer estragos con las respuestas
  237. de <acronym>AMF</acronym>. Para prevenir estos problemas, sugerimos deshabilitar la
  238. directiva <property>display_errors</property> cuando se está en modo de producción.
  239. </para>
  240. </sect2>
  241. <sect2 id="zend.amf.server.response">
  242. <title>Respuestas de AMF</title>
  243. <para> En ocasiones es posible que quiera manipular ligeramente el objeto respuesta, es
  244. bastante usual querer devolver algunas cebeceras de mensajes adicionales. Puede hacerlo
  245. mediante el método del servidor <methodname>handle()</methodname> que devuelve el objeto
  246. respuesta. </para>
  247. <example id="zend.amf.server.response.messageHeaderExample">
  248. <title>Agregar cabeceras de mensaje a la respuesta de AMF</title>
  249. <para> En este ejemplo, añadiremos la cabecera de mensaje (MessageHeader) "foo" con el
  250. valor 'bar' a la respuesta antes de devolverla. </para>
  251. <programlisting language="php"><![CDATA[
  252. $respuesta = $servidor->handle();
  253. $respuesta->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
  254. echo $respuesta;
  255. ]]></programlisting>
  256. </example>
  257. </sect2>
  258. <sect2 id="zend.amf.server.typedobjects">
  259. <title>Objetos tipados</title>
  260. <para> Similarmente a <acronym>SOAP</acronym>, <acronym>AMF</acronym> permite pasar objetos
  261. entre cliente y servidor. Esto le da una gran flexibilidad y coherencia a ambos
  262. entornos. </para>
  263. <para>
  264. <methodname>Zend_Amf</methodname> ofrece tres métodos para mapear ActionScript y objetos
  265. PHP. </para>
  266. <itemizedlist>
  267. <listitem>
  268. <para> Primero, usted puede crear uniones explícitas a nivel del servidor,
  269. utilizando el método <methodname>setClassMap()</methodname>. El primer argumento
  270. es el nombre de la clase de ActionScript, el segundo es el nombre de la clase
  271. <acronym>PHP</acronym> que lo mapea: </para>
  272. <programlisting language="php"><![CDATA[
  273. // Mapea la clase ActionScript 'ContactVO' a la clase PHP 'Contact':
  274. $servidor->setClassMap('ContactVO', 'Contact');
  275. ]]></programlisting>
  276. </listitem>
  277. <listitem>
  278. <para> Segundo, en su clase <acronym>PHP</acronym> puede ajustar la propiedad como
  279. pública mediante <varname>$_explicitType</varname>, con el valor
  280. representativo de la clase ActionScript que mapear: </para>
  281. <programlisting language="php"><![CDATA[
  282. class Contact
  283. {
  284. public $_explicitType = 'ContactVO';
  285. }
  286. ]]></programlisting>
  287. </listitem>
  288. <listitem>
  289. <para> Tercero, en un sentido similar, puede definir como público el método
  290. <methodname>getASClassName()</methodname> dentro de su clase. Este método
  291. debe devolver la clase ActionScript apropiada: </para>
  292. <programlisting language="php"><![CDATA[
  293. class Contact
  294. {
  295. public function getASClassName()
  296. {
  297. return 'ContactVO';
  298. }
  299. }
  300. ]]></programlisting>
  301. </listitem>
  302. </itemizedlist>
  303. <para> Aunque hemos creado <emphasis>ContactVO</emphasis> en el servidor, ahora tenemos que
  304. hacer su clase correspondiente en <acronym>AS3</acronym> para que el servidor pueda
  305. mapear el objeto. </para>
  306. <para> Haga clic derecho sobre la carpeta src del proyecto Flex y seleccione New ->
  307. ActionScript File. Nombre el fichero como ContactVO y pulse 'finish' (finalizar) para
  308. verlo. Copie el siguiente código en el fichero para terminar de crear la clase. </para>
  309. <programlisting language="as"><![CDATA[
  310. package
  311. {
  312. [Bindable]
  313. [RemoteClass(alias="ContactVO")]
  314. public class ContactVO
  315. {
  316. public var id:int;
  317. public var firstname:String;
  318. public var lastname:String;
  319. public var email:String;
  320. public var mobile:String;
  321. public function ProductVO():void {
  322. }
  323. }
  324. }
  325. ]]></programlisting>
  326. <para> La clase es sintácticamente equivalente a la de <acronym>PHP</acronym> del mismo
  327. nombre. Los nombres de variables son exactamente los mismos y necesitan estar en el
  328. mismo contenedor para trabajar correctamente. Hay dos meta tags <acronym>AS3</acronym>
  329. únicos en esta clase. El primero es vinculable y dispara un evento cuando es
  330. actualizada. El segundo es el tag RemoteClass y define que esta clase puede tener
  331. mapeado un objeto remoto con un nombre de alias, en este caso
  332. <emphasis>ContactVO</emphasis> Es obligatorio que en esta etiqueta(tag), el valor
  333. que se estableció es la clase PHP sea estrictamente equivalente. </para>
  334. <programlisting language="as"><![CDATA[
  335. [Bindable]
  336. private var myContact:ContactVO;
  337. private function getContactHandler(event:ResultEvent):void {
  338. myContact = ContactVO(event.result);
  339. }
  340. ]]></programlisting>
  341. <para> El siguiente resultado del evento debido a la llamada de servicio, se incorporó
  342. instantáneamente a <emphasis>ContactVO</emphasis> de Flex. Cualquier cosa que esté
  343. ligada a myContact será actualizada con los datos retornados por
  344. <emphasis>ContactVO</emphasis>. </para>
  345. </sect2>
  346. <sect2 id="zend.amf.server.resources">
  347. <title>Recursos</title>
  348. <para>
  349. <classname>Zend_Amf</classname> provides tools for mapping resource types returned by
  350. service classes into data consumable by ActionScript. </para>
  351. <para> In order to handle specific resource type, the user needs to create a plugin class
  352. named after the resource name, with words capitalized and spaces removed (so, resource
  353. type "mysql result" becomes MysqlResult), with some prefix, e.g.
  354. <classname>My_MysqlResult</classname>. This class should implement one method,
  355. <methodname>parse()</methodname>, receiving one argument - the resource - and
  356. returning the value that should be sent to ActionScript. The class should be located in
  357. the file named after the last component of the name, e.g.
  358. <filename>MysqlResult.php</filename>. </para>
  359. <para> The directory containing the resource handling plugins should be registered with
  360. <classname>Zend_Amf</classname> type loader: </para>
  361. <programlisting language="php"><![CDATA[
  362. Zend_Amf_Parse_TypeLoader::addResourceDirectory(
  363. "My",
  364. "application/library/resources/My"
  365. ));
  366. ]]></programlisting>
  367. <para> For detailed discussion of loading plugins, please see the <link
  368. linkend="zend.loader.pluginloader">plugin loader</link> section. </para>
  369. <para> Default directory for <classname>Zend_Amf</classname> resources is registered
  370. automatically and currently contains handlers for "mysql result" and "stream" resources. </para>
  371. <programlisting language="php"><![CDATA[
  372. // Example class implementing handling resources of type mysql result
  373. class Zend_Amf_Parse_Resource_MysqlResult
  374. {
  375. /**
  376. * Parse resource into array
  377. *
  378. * @param resource $resource
  379. * @return array
  380. */
  381. public function parse($resource) {
  382. $result = array();
  383. while($row = mysql_fetch_assoc($resource)) {
  384. $result[] = $row;
  385. }
  386. return $result;
  387. }
  388. }
  389. ]]></programlisting>
  390. <para> Trying to return unknown resource type (i.e., one for which no handler plugin exists)
  391. will result in an exception. </para>
  392. </sect2>
  393. <sect2 id="zend.amf.server.flash">
  394. <title>Conectándose al Servidor desde Flash</title>
  395. <para> La conexión a <classname>Zend_Amf_Server</classname> desde su proyecto Flash es
  396. ligeramente distinta a la de Flex. Sin embargo una vez que la conexión con Flash
  397. funcione con <classname>Zend_Amf_Server</classname> lo hará igual modo que con Flex. El
  398. siguiente ejemplo también puede ser utilizado desde un fichero Flex
  399. <acronym>AS3</acronym>. Para nuestra conexión vamos a reutilizar la misma
  400. configuracion <classname>Zend_Amf_Server</classname> junto a la clase Mundo. </para>
  401. <para> Abra Flash CS y cree un nuevo fichero Flash (ActionScript 3). Nombre al documento
  402. como <filename>ZendExample.fla</filename> y guárdelo en una carpeta que utilizará para
  403. este ejemplo. Cree una nuevo fichero <acronym>AS3</acronym> en el mismo directorio y
  404. llámelo <filename>Main.as</filename>. Abra ambos ficheros con su editor. Ahora vamos a
  405. conectar las dos ficheros a través de la clase documento. Seleccione ZendExample y haga
  406. clic en el escenario. Desde el panel del escenario cambie la propiedad de la clase
  407. Document a Main. Esto vincula al fichero Main.as con la interfaz de usuario
  408. en<filename>ZendExample.fla</filename> Cuando ejecute el fichero ZendExample de
  409. Flash se ejecutará ahora la clase <filename>Main.as</filename> El paso siguiente será
  410. añadir ActionScript para hacer una lamada <acronym>AMF</acronym>. </para>
  411. <para> Ahora vamos a hacer una clase Main(principal) para que podamos enviar los datos al
  412. servidor y mostrar el resultado. Copie el código siguiente en su fichero
  413. <filename>Main.as</filename> y luego vamos a recorrer el código para describir cuál
  414. es el papel de cada elemento. </para>
  415. <programlisting language="as"><![CDATA[
  416. package {
  417. import flash.display.MovieClip;
  418. import flash.events.*;
  419. import flash.net.NetConnection;
  420. import flash.net.Responder;
  421. public class Main extends MovieClip {
  422. private var gateway:String = "http://example.com/server.php";
  423. private var connection:NetConnection;
  424. private var responder:Responder;
  425. public function Main() {
  426. responder = new Responder(onResult, onFault);
  427. connection = new NetConnection;
  428. connection.connect(gateway);
  429. }
  430. public function onComplete( e:Event ):void{
  431. var params = "Sent to Server";
  432. connection.call("World.hello", responder, params);
  433. }
  434. private function onResult(result:Object):void {
  435. // Display the returned data
  436. trace(String(result));
  437. }
  438. private function onFault(fault:Object):void {
  439. trace(String(fault.description));
  440. }
  441. }
  442. }
  443. ]]></programlisting>
  444. <para> Primero tenemos que importar dos bibliotecas de ActionScript que realizan la mayor
  445. parte del trabajo. La primera es NetConnection que actúa como un tubo bidireccional
  446. entre el cliente y el servidor. La segunda es un objeto Responder que maneja los valores
  447. de retorno desde el servidor, y que están relacionados con el éxito o el fracaso de la
  448. llamada. </para>
  449. <programlisting language="as"><![CDATA[
  450. import flash.net.NetConnection;
  451. import flash.net.Responder;
  452. ]]></programlisting>
  453. <para> En la clase necesitaremos tres variables para representar a NetConnection, Responder,
  454. y la URL del gateway a nuestra instalación <classname>Zend_Amf_Server</classname>. </para>
  455. <programlisting language="as"><![CDATA[
  456. private var gateway:String = "http://example.com/server.php";
  457. private var connection:NetConnection;
  458. private var responder:Responder;
  459. ]]></programlisting>
  460. <para> En el constructor Main creamos un Responder(respondedor) y una nueva conexión al
  461. punto final de <classname>Zend_Amf_Server</classname>. El respondedor define dos
  462. diferentes métodos para manejar la respuesta desde el servidor. Por simplicidad los
  463. hemos llamado onResult y onFault. </para>
  464. <programlisting language="as"><![CDATA[
  465. responder = new Responder(onResult, onFault);
  466. connection = new NetConnection;
  467. connection.connect(gateway);
  468. ]]></programlisting>
  469. <para> La función onComplete se ejecuta tan pronto como la construcción ha concluido,
  470. enviando los datos al servidor. Necesitamos añadir una línea más que hace una llamada a
  471. la función <classname>Zend_Amf_Server</classname> Mundo->hola. </para>
  472. <programlisting language="as"><![CDATA[
  473. connection.call("Mundo.hola", responder, params);
  474. ]]></programlisting>
  475. <para> Cuando creamos la variable responder hemos definido las funciones onResult y onFault
  476. para manejar la respuesta proveniente del servidor. Hemos añadido la función OnResult
  477. para el resultado exitoso desde el servidor. Cada vez que se ejecuta apropiadamente el
  478. manejo de conexión con el servidor, el manejador de eventos llama esta función. </para>
  479. <programlisting language="as"><![CDATA[
  480. private function onResult(result:Object):void {
  481. // Muestra los datos devueltos
  482. trace(String(result));
  483. }
  484. ]]></programlisting>
  485. <para> La función onFault, se llama si hubo una respuesta nula desde el servidor. Esto
  486. ocurre cuando hay un error en el servidor, la <acronym>URL</acronym> al servidor es
  487. inválida, el servicio remoto o método no existe o cualquier otra cuestión relacionada
  488. con la conexión. </para>
  489. <programlisting language="as"><![CDATA[
  490. private function onFault(fault:Object):void {
  491. trace(String(fault.description));
  492. }
  493. ]]></programlisting>
  494. <para> La inclusión de ActionScript para realizar la conexión remota ha finalizado. Al
  495. ejecutar el fichero ZendExample, se establece una conexión con Zend_Amf. En resumen, se
  496. han añadido las variables requeridas para abrir una conexión con el servidor remoto, se
  497. han definido qué métodos se deben utilizar cuando su aplicación recibe una respuesta
  498. desde el servidor, y finalmente se han mostrado los datos de salida devueltos a través
  499. de <methodname>trace()</methodname>. </para>
  500. </sect2>
  501. <sect2 id="zend.amf.server.auth">
  502. <title>Authentication</title>
  503. <para>
  504. <classname>Zend_Amf_Server</classname> allows you to specify authentication and
  505. authorization hooks to control access to the services. It is using the infrastructure
  506. provided by <link linkend="zend.auth">
  507. <classname>Zend_Auth</classname>
  508. </link> and <link linkend="zend.acl">
  509. <classname>Zend_Acl</classname>
  510. </link> components. </para>
  511. <para> In order to define authentication, the user provides authentication adapter extening
  512. <classname>Zend_Amf_Auth_Abstract</classname> abstract class. The adapter should
  513. implement the <methodname>authenticate()</methodname> method just like regular <link
  514. linkend="zend.auth.introduction.adapters">authentication adapter</link>. </para>
  515. <para> The adapter should use properties <emphasis>_username</emphasis> and
  516. <emphasis>_password</emphasis> from the parent
  517. <classname>Zend_Amf_Auth_Abstract</classname> class in order to authenticate. These
  518. values are set by the server using <methodname>setCredentials()</methodname> method
  519. before call to <methodname>authenticate()</methodname> if the credentials are received
  520. in the <acronym>AMF</acronym> request headers. </para>
  521. <para> The identity returned by the adapter should be an object containing property
  522. <property>role</property> for the <acronym>ACL</acronym> access control to work. </para>
  523. <para> If the authentication result is not successful, the request is not proceseed further
  524. and failure message is returned with the reasons for failure taken from the result. </para>
  525. <para> The adapter is connected to the server using <methodname>setAuth()</methodname>
  526. method: </para>
  527. <programlisting language="php"><![CDATA[
  528. $server->setAuth(new My_Amf_Auth());
  529. ]]></programlisting>
  530. <para> Access control is performed by using <classname>Zend_Acl</classname> object set by
  531. <methodname>setAcl()</methodname> method: </para>
  532. <programlisting language="php"><![CDATA[
  533. $acl = new Zend_Acl();
  534. createPermissions($acl); // create permission structure
  535. $server->setAcl($acl);
  536. ]]></programlisting>
  537. <para> If the <acronym>ACL</acronym> object is set, and the class being called defines
  538. <methodname>initAcl()</methodname> method, this method will be called with the
  539. <acronym>ACL</acronym> object as an argument. The class then can create additional
  540. <acronym>ACL</acronym> rules and return <constant>TRUE</constant>, or return
  541. <constant>FALSE</constant> if no access control is required for this class. </para>
  542. <para> After <acronym>ACL</acronym> have been set up, the server will check if access is
  543. allowed with role set by the authentication, resource being the class name (or
  544. <constant>NULL</constant> for function calls) and privilege being the function name.
  545. If no authentication was provided, then if the <emphasis>anonymous</emphasis> role was
  546. defined, it will be used, otherwise the access will be denied. </para>
  547. <programlisting language="php"><![CDATA[
  548. if($this->_acl->isAllowed($role, $class, $function)) {
  549. return true;
  550. } else {
  551. require_once 'Zend/Amf/Server/Exception.php';
  552. throw new Zend_Amf_Server_Exception("Access not allowed");
  553. }
  554. ]]></programlisting>
  555. </sect2>
  556. </sect1>
  557. <!--
  558. vim:se ts=4 sw=4 et:
  559. -->