Zend_Amf-Server.xml 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  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>
  8. proporciona un servidor al estilo
  9. <acronym>RPC</acronym>
  10. para tramitar solicitudes hechas desde Adobe
  11. Flash Player utilizando el protocolo
  12. <acronym>AMF</acronym>
  13. . Al igual
  14. que todas las clases de servidor, Zend Framework sigue la
  15. <acronym>API</acronym>
  16. de SoapServer, proporcionando una interfaz
  17. para crear servidores fácil de recordar.
  18. </para>
  19. <example id="zend.amf.server.basic">
  20. <title>Servidor AMF básico</title>
  21. <para>
  22. Asumamos que ha creado la clase
  23. <classname>Foo</classname>
  24. con
  25. una variedad de métodos públicos. Usando el siguiente código, puede
  26. crear un servidor
  27. <acronym>AMF</acronym>
  28. :
  29. </para>
  30. <programlisting language="php"><![CDATA[
  31. $servidor = new Zend_Amf_Server();
  32. $servidor->setClass('Foo');
  33. $respuesta = $servidor->handle();
  34. echo $respuesta;
  35. ]]></programlisting>
  36. <para>Alternativamente, en su lugar puede elegir agregar una función
  37. simple como llamada de
  38. retorno:</para>
  39. <programlisting language="php"><![CDATA[
  40. $servidor = new Zend_Amf_Server();
  41. $servidor->addFunction('myUberCoolFunction');
  42. $respuesta = $servidor->handle();
  43. echo $respuesta;
  44. ]]></programlisting>
  45. <para>
  46. También puede combinar y examinar la identidad de varias clases y
  47. funciones. Al hacerlo,
  48. sugerimos darle un espacio de nombres a cada
  49. una para garantizar que no ocurran
  50. colisiones entre nombres de
  51. métodos; puede hacerse simplemente pasando una segunda cadena
  52. de
  53. argumentos para cualquier
  54. <methodname>addFunction()</methodname>
  55. o
  56. <methodname>setClass()</methodname>
  57. :
  58. </para>
  59. <programlisting language="php"><![CDATA[
  60. $servidor = new Zend_Amf_Server();
  61. $servidor->addFunction('myUberCoolFunction', 'my')
  62. ->setClass('Foo', 'foo')
  63. ->setClass('Bar', 'bar');
  64. $respuesta = $servidor->handle();
  65. echo $respuesta;
  66. ]]></programlisting>
  67. <para>
  68. El
  69. <classname>Zend_Amf_Server</classname>
  70. también permite cargar
  71. servicios dinámicamente, en función de una ruta de directorio ya
  72. suministrada. Puede añadir al servidor tantos directorios como
  73. desee. El orden en que se
  74. añadan los directorios al servidor será el
  75. orden en que se realizarán las búsquedas
  76. <acronym>LIFO</acronym>
  77. en
  78. los directorios para coincidir con la clase. El método
  79. <methodname>addDirectory()</methodname>
  80. realiza la acción de
  81. añadir directorios.
  82. </para>
  83. <programlisting language="php"><![CDATA[
  84. $servidor->addDirectory(dirname(__FILE__) .'/../services/');
  85. $servidor->addDirectory(dirname(__FILE__) .'/../package/');
  86. ]]></programlisting>
  87. <para>
  88. Cuando se llama a servicios remotos, los nombres de los
  89. directorios que contengan las
  90. fuentes pueden tener los delimitadores
  91. guión bajo ("_") y el punto ("."). Cuando se
  92. utilize un guión bajo
  93. ("_") tanto en
  94. <acronym>PEAR</acronym>
  95. como en Zend Framework, se
  96. respetarán los nombres de clases de acuerdo a las convenciones
  97. de
  98. nomenclatura. Esto significa que si usted llama al servicio
  99. com_Foo_Bar el servidor
  100. buscará el archivo
  101. <filename>Bar.php</filename>
  102. en cada una de las rutas incluidas
  103. en
  104. <filename>com/Foo/Bar.php</filename>
  105. . Si se usa la notación punto
  106. para su servicio remoto como
  107. <filename>com.Foo.Bar</filename>
  108. cada
  109. ruta incluida deberá tener
  110. <filename>com/Foo/Bar.php</filename>
  111. agregado al final para autocargar
  112. <filename>Bar.php</filename>
  113. </para>
  114. <para>
  115. Todos las solicitudes
  116. <acronym>AMF</acronym>
  117. enviadas al script
  118. serán manejadas por el servidor, y este devolverá una respuesta
  119. <acronym>AMF</acronym>
  120. .
  121. </para>
  122. </example>
  123. <note>
  124. <title>Todos los métodos y las funciones agregadas requieren bloques de
  125. documentación
  126. (docblocks)</title>
  127. <para>
  128. Como todos los demás componentes del servidor en Zend Framework,
  129. debe documentar los
  130. métodos de su clase usando
  131. <acronym>PHP</acronym>
  132. docblocks. Como mínimo, necesita
  133. proporcionar anotaciones para cada argumento así como
  134. para el valor
  135. de retorno. Como ejemplos:
  136. </para>
  137. <programlisting language="php"><![CDATA[
  138. // Función que agregar:
  139. /**
  140. * @param string $nombre
  141. * @param string $saludo
  142. * @return string
  143. */
  144. function holaMundo($ombre, $saludo = 'Hola')
  145. {
  146. return $saludo . ', ' . $nombre;
  147. }
  148. ]]></programlisting>
  149. <programlisting language="php"><![CDATA[
  150. // Clase agregada
  151. class Mundo
  152. {
  153. /**
  154. * @param string $nombre
  155. * @param string $saludo
  156. * @return string
  157. */
  158. public function hola($nombre, $saludo = 'Hola')
  159. {
  160. return $saludo . ', ' . $nombre;
  161. }
  162. }
  163. ]]></programlisting>
  164. <para>Pueden usarse otras anotaciones, pero serán ignoradas.</para>
  165. </note>
  166. <sect2 id="zend.amf.server.flex">
  167. <title>Conectándose al Servidor desde Flex</title>
  168. <para>
  169. Conectarse a
  170. <classname>Zend_Amf_Server</classname>
  171. desde su
  172. proyecto Flex es bastante simple; solo necesita apuntar el final del
  173. <acronym>URI</acronym>
  174. a su script
  175. <classname>Zend_Amf_Server</classname>
  176. .
  177. </para>
  178. <para>
  179. Por ejemplo, digamos que ya ha creado su servidor y lo ha puesto
  180. en el fichero
  181. <filename>server.php</filename>
  182. en el directorio raíz
  183. (root) de su aplicación, por lo tanto la
  184. <acronym>URI</acronym>
  185. es
  186. <filename>http://example.com/server.php</filename>
  187. . En este
  188. caso, usted debería modificar su fichero
  189. <filename>service-config.xml</filename>
  190. poniendo este valor como
  191. atributo al punto final del canal
  192. <acronym>URI</acronym>
  193. .
  194. </para>
  195. <para>
  196. Si nunca ha creado un fichero
  197. <filename>service-config.xml</filename>
  198. puede hacerlo abriendo
  199. su proyecto en la ventana del navegador. Haga clic derecho sobre
  200. el
  201. nombre del proyecto y seleccione 'properties' (propiedades). En el
  202. cuadro de diálogo
  203. 'properties' del proyecto ir al menú ‘Flex Build
  204. Path' (Crear ruta Flex), luego en la
  205. pestaña ‘Library path’ (ruta de
  206. biblioteca) asegúrese de que el fichero
  207. '
  208. <filename>rpc.swc</filename>
  209. ' sea añadido a su ruta de
  210. proyectos y pulse Ok (Aceptar) para cerrar la ventana.
  211. </para>
  212. <para>
  213. También necesitará indicarle al compilador que debe usar
  214. <filename>service-config.xml</filename>
  215. para encontrar el punto
  216. final de RemoteObject. Para hacerlo, abra de nuevo el panel de
  217. propiedades de su proyecto haciendo clic en el botón derecho sobre
  218. el proyecto en la
  219. carpeta del navegador y seleccione 'properties'
  220. (propiedades). Ahora seleccione ‘Flex
  221. Compiler' (Compilador Flex) y
  222. añada la cadena:
  223. <command>-services "services-config.xml"</command>
  224. .
  225. Presione 'Apply' (Aplicar) y luego en OK para volver a actualizar la
  226. opción. Lo que
  227. acaba de hacer es decirle al compilador Flex que
  228. busque en el fichero
  229. <filename>services-config.xml</filename>
  230. aquellas variables que se usarán en tiempo de ejecución por la clase
  231. RemotingObject.
  232. </para>
  233. <para>
  234. Ahora, para conectarnos a nuestros métodos remotos debemos
  235. indicarle a Flex qué fichero
  236. de configuración de servicios utilizar.
  237. Por esta razón creamos un nuevo fichero
  238. '
  239. <filename>services-config.xml</filename>
  240. ' en la carpeta src del
  241. proyecto Flex. Con click derecho sobre el proyecto y
  242. seleccionando
  243. 'new'(nuevo) 'File' (fichero), se abrirá una nueva ventana.
  244. Seleccione la
  245. carpeta del proyecto y luego nombre el archivo
  246. '
  247. <filename>services-config.xml</filename>
  248. ' y presione 'finish'
  249. (finalizar).
  250. </para>
  251. <para>
  252. Flex ha creado y abierto el nuevo fichero
  253. <filename>services-config.xml</filename>
  254. . Utilice el siguiente
  255. texto de ejemplo para su fichero
  256. <filename>services-config.xml</filename>
  257. . Asegúrese de
  258. actualizar su punto final para que concuerde con el servidor.
  259. Asegúrese
  260. también de guardar el fichero.
  261. </para>
  262. <programlisting language="xml"><![CDATA[
  263. <?xml version="1.0" encoding="UTF-8"?>
  264. <services-config>
  265. <services>
  266. <service id="zend-service"
  267. class="flex.messaging.services.RemotingService"
  268. messageTypes="flex.messaging.messages.RemotingMessage">
  269. <destination id="zend">
  270. <channels>
  271. <channel ref="zend-endpoint"/>
  272. </channels>
  273. <properties>
  274. <source>*</source>
  275. </properties>
  276. </destination>
  277. </service>
  278. </services>
  279. <channels>
  280. <channel-definition id="zend-endpoint"
  281. class="mx.messaging.channels.AMFChannel">
  282. <endpoint uri="http://example.com/server.php"
  283. class="flex.messaging.endpoints.AMFEndpoint"/>
  284. </channel-definition>
  285. </channels>
  286. </services-config>
  287. ]]></programlisting>
  288. <para>
  289. Hay dos puntos clave en el ejemplo. En primer lugar, pero último
  290. en el listado, creamos
  291. un canal
  292. <acronym>AMF</acronym>
  293. , y
  294. especificamos el punto final como la
  295. <acronym>URL</acronym>
  296. a
  297. nuestro
  298. <classname>Zend_Amf_Server</classname>
  299. :
  300. </para>
  301. <programlisting language="xml"><![CDATA[
  302. <channel-definition id="zend-endpoint"
  303. <endpoint uri="http://example.com/server.php"
  304. class="flex.messaging.endpoints.AMFEndpoint"/>
  305. </channel-definition>
  306. ]]></programlisting>
  307. <para>Advierta que a este canal le hemos dado un identificador,
  308. "zend-endpoint". El ejemplo
  309. crea un servicio cuyo destino hace
  310. referencia a este canal, asignándole también un ID, en
  311. este caso es
  312. "zend".</para>
  313. <para>
  314. Dentro de nuestros ficheros Flex
  315. <acronym>MXML</acronym>
  316. ,
  317. necesitamos vincular un RemoteObject al servicio. En
  318. <acronym>MXML</acronym>
  319. , esto podría hacerse así:
  320. </para>
  321. <programlisting language="xml"><![CDATA[
  322. <mx:RemoteObject id="myservice"
  323. fault="faultHandler(event)"
  324. showBusyCursor="true"
  325. destination="zend">
  326. ]]></programlisting>
  327. <para>
  328. Aquí, hemos definido un nuevo objeto remoto identificado por
  329. "myservice" vinculado
  330. destino de servicio "zend" que hemos definido
  331. en el fichero
  332. <filename>services-config.xml</filename>.
  333. Entonces
  334. invocamos sus métodos en nuestro ActionScript simplemente llamando a
  335. "myservice.&lt;method&gt;". . A modo de ejemplo:
  336. </para>
  337. <programlisting language="ActionScript"><![CDATA[
  338. myservice.hello("Wade");
  339. ]]></programlisting>
  340. <para>Cuando se usan nombres-de-espacio, puede usarse
  341. "myservice.&lt;namespace&gt;.&lt;method&gt;":</para>
  342. <programlisting language="ActionScript"><![CDATA[
  343. myservice.world.hello("Wade");
  344. ]]></programlisting>
  345. <para>
  346. Para más información sobre como invocar a Flex RemoteObject
  347. visite el sitio de ayuda de
  348. Adobe Flex 3 en:
  349. <ulink url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html"/>
  350. .
  351. </para>
  352. </sect2>
  353. <sect2 id="zend.amf.server.errors">
  354. <title>Manejo de errores</title>
  355. <para>
  356. Por defecto, todas las excepciones producidas en sus clases o
  357. funciones adjuntas serán
  358. capturados y devueltas como mensajes de
  359. error de
  360. <acronym>AMF</acronym>
  361. (<acronym>AMF</acronym> ErrorMessages). Sin embargo, el
  362. contenido de estos objetos de mensajes de error
  363. variará dependiendo
  364. de si el servidor está o no en modo "producción" (el estado por
  365. defecto).
  366. </para>
  367. <para>Cuando se está en modo de producción, únicamente el código de
  368. excepción será devuelto.
  369. Si desactiva el modo de producción, algo
  370. que debe hacerse sólo para probar -- serán
  371. devueltos más detalles de
  372. la excepción: el mensaje de excepción (error), línea y
  373. backtrace
  374. serán adjuntados.</para>
  375. <para>Para desactivar el modo de producción, haga lo siguiente:</para>
  376. <programlisting language="php"><![CDATA[
  377. $server->setProduction(false);
  378. ]]></programlisting>
  379. <para>
  380. Para habilitarlo nuevamente, pase el valor
  381. <constant>TRUE</constant>
  382. en su lugar.
  383. </para>
  384. <programlisting language="php"><![CDATA[
  385. $server->setProduction(true);
  386. ]]></programlisting>
  387. <note>
  388. <title>¡Deshabilite el modo de producción racionalmente!</title>
  389. <para>
  390. Sugerimos deshabilitar el modo de producción solo cuando se
  391. está en modo de
  392. desarrollo. Los mensajes de excepción y los
  393. backtraces puede contener información
  394. sensible del sistema, y no
  395. desea que se pueda acceder a ellas desde el exterior.
  396. Aunque
  397. <acronym>AMF</acronym>
  398. es un formato binario, ahora al ser
  399. abierta la especificación, cualquiera puede
  400. potencialmente
  401. deserializar los datos.
  402. </para>
  403. </note>
  404. <para>
  405. Un área en la que se debe tener especialmente mucho cuidado son
  406. los errores propios de
  407. <acronym>PHP</acronym>
  408. . Cuando la directiva
  409. <acronym>INI</acronym>
  410. <property>display_errors</property>
  411. está habilitada, los errores de
  412. <acronym>PHP</acronym>
  413. de cualquier nivel del reporte actual
  414. serán pasados directamente a la salida, y
  415. potencialmente se podrían
  416. hacer estragos con las respuestas de
  417. <acronym>AMF</acronym>
  418. . Para
  419. prevenir estos problemas, sugerimos deshabilitar la directiva
  420. <property>display_errors</property>
  421. cuando se está en modo de
  422. producción.
  423. </para>
  424. </sect2>
  425. <sect2 id="zend.amf.server.response">
  426. <title>Respuestas de AMF</title>
  427. <para>
  428. En ocasiones es posible que quiera manipular ligeramente el
  429. objeto respuesta, es bastante
  430. usual querer devolver algunas
  431. cebeceras de mensajes adicionales. Puede hacerlo mediante
  432. el método
  433. del servidor
  434. <methodname>handle()</methodname>
  435. que devuelve el
  436. objeto respuesta.
  437. </para>
  438. <example id="zend.amf.server.response.messageHeaderExample">
  439. <title>Agregar cabeceras de mensaje a la respuesta de AMF</title>
  440. <para>En este ejemplo, añadiremos la cabecera de mensaje
  441. (MessageHeader) "foo" con el
  442. valor 'bar' a la respuesta antes de
  443. devolverla.</para>
  444. <programlisting language="php"><![CDATA[
  445. $respuesta = $servidor->handle();
  446. $respuesta->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
  447. echo $respuesta;
  448. ]]></programlisting>
  449. </example>
  450. </sect2>
  451. <sect2 id="zend.amf.server.typedobjects">
  452. <title>Objetos tipados</title>
  453. <para>
  454. Similarmente a
  455. <acronym>SOAP</acronym>
  456. ,
  457. <acronym>AMF</acronym>
  458. permite pasar objetos entre cliente y servidor. Esto le da una gran
  459. flexibilidad y
  460. coherencia a ambos entornos.
  461. </para>
  462. <para>
  463. <classname>Zend_Amf</classname>
  464. ofrece tres métodos para mapear
  465. ActionScript y objetos
  466. <acronym>PHP</acronym>
  467. .
  468. </para>
  469. <itemizedlist>
  470. <listitem>
  471. <para>
  472. Primero, usted puede crear uniones explícitas a nivel del
  473. servidor, utilizando el
  474. método
  475. <methodname>setClassMap()</methodname>
  476. . El primer
  477. argumento es el nombre de la clase de ActionScript, el
  478. segundo es el
  479. nombre de la clase
  480. <acronym>PHP</acronym>
  481. que
  482. lo mapea:
  483. </para>
  484. <programlisting language="php"><![CDATA[
  485. // Mapea la clase ActionScript 'ContactVO' a la clase PHP 'Contact':
  486. $servidor->setClassMap('ContactVO', 'Contact');
  487. ]]></programlisting>
  488. </listitem>
  489. <listitem>
  490. <para>
  491. Segundo, en su clase
  492. <acronym>PHP</acronym>
  493. puede ajustar
  494. la propiedad como pública mediante
  495. <varname>$_explicitType</varname>
  496. , con el valor
  497. representativo de la clase ActionScript que mapear:
  498. </para>
  499. <programlisting language="php"><![CDATA[
  500. class Contact
  501. {
  502. public $_explicitType = 'ContactVO';
  503. }
  504. ]]></programlisting>
  505. </listitem>
  506. <listitem>
  507. <para>
  508. Tercero, en un sentido similar, puede definir como
  509. público el método
  510. <methodname>getASClassName()</methodname>
  511. dentro de su clase. Este método debe devolver la clase
  512. ActionScript apropiada:
  513. </para>
  514. <programlisting language="php"><![CDATA[
  515. class Contact
  516. {
  517. public function getASClassName()
  518. {
  519. return 'ContactVO';
  520. }
  521. }
  522. ]]></programlisting>
  523. </listitem>
  524. </itemizedlist>
  525. <para>
  526. Aunque hemos creado
  527. <emphasis>ContactVO</emphasis>
  528. en el
  529. servidor, ahora tenemos que hacer su clase correspondiente en
  530. <acronym>AS3</acronym>
  531. para que el servidor pueda mapear el
  532. objeto.
  533. </para>
  534. <para>Haga clic derecho sobre la carpeta src del proyecto Flex y
  535. seleccione New ->
  536. ActionScript File. Nombre el fichero como
  537. ContactVO y pulse 'finish' (finalizar) para
  538. verlo. Copie el
  539. siguiente código en el fichero para terminar de crear la clase.</para>
  540. <programlisting language="as"><![CDATA[
  541. package
  542. {
  543. [Bindable]
  544. [RemoteClass(alias="ContactVO")]
  545. public class ContactVO
  546. {
  547. public var id:int;
  548. public var firstname:String;
  549. public var lastname:String;
  550. public var email:String;
  551. public var mobile:String;
  552. public function ProductVO():void {
  553. }
  554. }
  555. }
  556. ]]></programlisting>
  557. <para>
  558. La clase es sintácticamente equivalente a la de
  559. <acronym>PHP</acronym>
  560. del mismo nombre. Los nombres de
  561. variables son exactamente los mismos y necesitan estar
  562. en el mismo
  563. contenedor para trabajar correctamente. Hay dos meta tags
  564. <acronym>AS3</acronym>
  565. únicos en esta clase. El primero es
  566. vinculable y dispara un evento cuando es actualizada.
  567. El segundo es
  568. el tag RemoteClass y define que esta clase puede tener mapeado un
  569. objeto
  570. remoto con un nombre de alias, en este caso
  571. <emphasis>ContactVO</emphasis>
  572. Es obligatorio que en esta
  573. etiqueta(tag), el valor que se estableció es la clase
  574. <acronym>PHP</acronym>
  575. sea estrictamente equivalente.
  576. </para>
  577. <programlisting language="as"><![CDATA[
  578. [Bindable]
  579. private var myContact:ContactVO;
  580. private function getContactHandler(event:ResultEvent):void {
  581. myContact = ContactVO(event.result);
  582. }
  583. ]]></programlisting>
  584. <para>
  585. El siguiente resultado del evento debido a la llamada de
  586. servicio, se incorporó
  587. instantáneamente a
  588. <emphasis>ContactVO</emphasis>
  589. de Flex. Cualquier cosa que esté
  590. ligada a myContact será actualizada con los datos
  591. retornados por
  592. <emphasis>ContactVO</emphasis>
  593. .
  594. </para>
  595. </sect2>
  596. <sect2 id="zend.amf.server.resources">
  597. <title>Recursos</title>
  598. <para>
  599. <classname>Zend_Amf</classname>
  600. provides tools for mapping resource
  601. types returned by service classes into data
  602. consumable by
  603. ActionScript.
  604. </para>
  605. <para>
  606. In order to handle specific resource type, the user needs to
  607. create a plugin class named
  608. after the resource name, with words
  609. capitalized and spaces removed (so, resource type
  610. "mysql result"
  611. becomes MysqlResult), with some prefix, e.g.
  612. <classname>My_MysqlResult</classname>
  613. . This class should
  614. implement one method,
  615. <methodname>parse()</methodname>
  616. , receiving
  617. one argument - the resource - and returning the value that should be
  618. sent to
  619. ActionScript. The class should be located in the file named
  620. after the last component of
  621. the name, e.g.
  622. <filename>MysqlResult.php</filename>
  623. .
  624. </para>
  625. <para>
  626. The directory containing the resource handling plugins should be
  627. registered with
  628. <classname>Zend_Amf</classname>
  629. type loader:
  630. </para>
  631. <programlisting language="php"><![CDATA[
  632. Zend_Amf_Parse_TypeLoader::addResourceDirectory(
  633. "My",
  634. "application/library/resources/My"
  635. ));
  636. ]]></programlisting>
  637. <para>
  638. For detailed discussion of loading plugins, please see the
  639. <link linkend="zend.loader.pluginloader">plugin loader</link>
  640. section.
  641. </para>
  642. <para>
  643. Default directory for
  644. <classname>Zend_Amf</classname>
  645. resources
  646. is registered automatically and currently contains handlers for
  647. "mysql result"
  648. and "stream" resources.
  649. </para>
  650. <programlisting language="php"><![CDATA[
  651. // Example class implementing handling resources of type mysql result
  652. class Zend_Amf_Parse_Resource_MysqlResult
  653. {
  654. /**
  655. * Parse resource into array
  656. *
  657. * @param resource $resource
  658. * @return array
  659. */
  660. public function parse($resource) {
  661. $result = array();
  662. while($row = mysql_fetch_assoc($resource)) {
  663. $result[] = $row;
  664. }
  665. return $result;
  666. }
  667. }
  668. ]]></programlisting>
  669. <para>Trying to return unknown resource type (i.e., one for which no
  670. handler plugin exists)
  671. will result in an exception.</para>
  672. </sect2>
  673. <sect2 id="zend.amf.server.flash">
  674. <title>Conectándose al Servidor desde Flash</title>
  675. <para>
  676. La conexión a
  677. <classname>Zend_Amf_Server</classname>
  678. desde su
  679. proyecto Flash es ligeramente distinta a la de Flex. Sin embargo una
  680. vez que la
  681. conexión con Flash funcione con
  682. <classname>Zend_Amf_Server</classname>
  683. lo hará igual modo que
  684. con Flex. El siguiente ejemplo también puede ser utilizado desde
  685. un
  686. fichero Flex
  687. <acronym>AS3</acronym>
  688. . Para nuestra conexión vamos a
  689. reutilizar la misma configuracion
  690. <classname>Zend_Amf_Server</classname>
  691. junto a la clase Mundo.
  692. </para>
  693. <para>
  694. Abra Flash CS y cree un nuevo fichero Flash (ActionScript 3).
  695. Nombre al documento como
  696. <filename>ZendExample.fla</filename>
  697. y
  698. guárdelo en una carpeta que utilizará para este ejemplo. Cree una
  699. nuevo fichero
  700. <acronym>AS3</acronym>
  701. en el mismo directorio y
  702. llámelo
  703. <filename>Main.as</filename>
  704. . Abra ambos ficheros con su
  705. editor. Ahora vamos a conectar las dos ficheros a través de
  706. la clase
  707. documento. Seleccione ZendExample y haga clic en el escenario. Desde
  708. el panel del
  709. escenario cambie la propiedad de la clase Document a
  710. Main. Esto vincula al fichero
  711. Main.as con la interfaz de usuario
  712. en
  713. <filename>ZendExample.fla</filename>
  714. Cuando ejecute el fichero
  715. ZendExample de Flash se ejecutará ahora la clase
  716. <filename>Main.as</filename>
  717. El paso siguiente será añadir
  718. ActionScript para hacer una lamada
  719. <acronym>AMF</acronym>
  720. .
  721. </para>
  722. <para>
  723. Ahora vamos a hacer una clase Main(principal) para que podamos
  724. enviar los datos al
  725. servidor y mostrar el resultado. Copie el código
  726. siguiente en su fichero
  727. <filename>Main.as</filename>
  728. y luego vamos a
  729. recorrer el código para describir cuál es el papel de cada elemento.
  730. </para>
  731. <programlisting language="as"><![CDATA[
  732. package {
  733. import flash.display.MovieClip;
  734. import flash.events.*;
  735. import flash.net.NetConnection;
  736. import flash.net.Responder;
  737. public class Main extends MovieClip {
  738. private var gateway:String = "http://example.com/server.php";
  739. private var connection:NetConnection;
  740. private var responder:Responder;
  741. public function Main() {
  742. responder = new Responder(onResult, onFault);
  743. connection = new NetConnection;
  744. connection.connect(gateway);
  745. }
  746. public function onComplete( e:Event ):void{
  747. var params = "Sent to Server";
  748. connection.call("World.hello", responder, params);
  749. }
  750. private function onResult(result:Object):void {
  751. // Display the returned data
  752. trace(String(result));
  753. }
  754. private function onFault(fault:Object):void {
  755. trace(String(fault.description));
  756. }
  757. }
  758. }
  759. ]]></programlisting>
  760. <para>Primero tenemos que importar dos bibliotecas de ActionScript que
  761. realizan la mayor
  762. parte del trabajo. La primera es NetConnection que
  763. actúa como un tubo bidireccional entre
  764. el cliente y el servidor. La
  765. segunda es un objeto Responder que maneja los valores de
  766. retorno
  767. desde el servidor, y que están relacionados con el éxito o el
  768. fracaso de la
  769. llamada.</para>
  770. <programlisting language="as"><![CDATA[
  771. import flash.net.NetConnection;
  772. import flash.net.Responder;
  773. ]]></programlisting>
  774. <para>
  775. En la clase necesitaremos tres variables para representar a
  776. NetConnection, Responder, y
  777. la
  778. <acronym>URL</acronym>
  779. del gateway a
  780. nuestra instalación
  781. <classname>Zend_Amf_Server</classname>
  782. .
  783. </para>
  784. <programlisting language="as"><![CDATA[
  785. private var gateway:String = "http://example.com/server.php";
  786. private var connection:NetConnection;
  787. private var responder:Responder;
  788. ]]></programlisting>
  789. <para>
  790. En el constructor Main creamos un Responder(respondedor) y una
  791. nueva conexión al punto
  792. final de
  793. <classname>Zend_Amf_Server</classname>
  794. . El respondedor define
  795. dos diferentes métodos para manejar la respuesta desde el
  796. servidor.
  797. Por simplicidad los hemos llamado onResult y onFault.
  798. </para>
  799. <programlisting language="as"><![CDATA[
  800. responder = new Responder(onResult, onFault);
  801. connection = new NetConnection;
  802. connection.connect(gateway);
  803. ]]></programlisting>
  804. <para>
  805. La función onComplete se ejecuta tan pronto como la construcción
  806. ha concluido, enviando
  807. los datos al servidor. Necesitamos añadir una
  808. línea más que hace una llamada a la función
  809. <classname>Zend_Amf_Server</classname>
  810. Mundo->hola.
  811. </para>
  812. <programlisting language="as"><![CDATA[
  813. connection.call("Mundo.hola", responder, params);
  814. ]]></programlisting>
  815. <para>Cuando creamos la variable responder hemos definido las funciones
  816. onResult y onFault
  817. para manejar la respuesta proveniente del
  818. servidor. Hemos añadido la función OnResult
  819. para el resultado
  820. exitoso desde el servidor. Cada vez que se ejecuta apropiadamente el
  821. manejo de conexión con el servidor, el manejador de eventos llama
  822. esta función.</para>
  823. <programlisting language="as"><![CDATA[
  824. private function onResult(result:Object):void {
  825. // Muestra los datos devueltos
  826. trace(String(result));
  827. }
  828. ]]></programlisting>
  829. <para>
  830. La función onFault, se llama si hubo una respuesta nula desde el
  831. servidor. Esto ocurre
  832. cuando hay un error en el servidor, la
  833. <acronym>URL</acronym>
  834. al servidor es inválida, el servicio
  835. remoto o método no existe o cualquier otra cuestión
  836. relacionada con
  837. la conexión.
  838. </para>
  839. <programlisting language="as"><![CDATA[
  840. private function onFault(fault:Object):void {
  841. trace(String(fault.description));
  842. }
  843. ]]></programlisting>
  844. <para>
  845. La inclusión de ActionScript para realizar la conexión remota ha
  846. finalizado. Al ejecutar
  847. el fichero ZendExample, se establece una
  848. conexión con
  849. <classname>Zend_Amf</classname>
  850. . En resumen, se han añadido las variables
  851. requeridas para abrir una conexión con el
  852. servidor remoto, se han
  853. definido qué métodos se deben utilizar cuando su aplicación
  854. recibe
  855. una respuesta desde el servidor, y finalmente se han mostrado los
  856. datos de salida
  857. devueltos a través de
  858. <methodname>trace()</methodname>
  859. .
  860. </para>
  861. </sect2>
  862. <sect2 id="zend.amf.server.auth">
  863. <title>Authentication</title>
  864. <para>
  865. <classname>Zend_Amf_Server</classname>
  866. allows you to specify
  867. authentication and authorization hooks to control access to the
  868. services. It is using the infrastructure provided by
  869. <link linkend="zend.auth">
  870. <classname>Zend_Auth</classname>
  871. </link>
  872. and
  873. <link linkend="zend.acl">
  874. <classname>Zend_Acl</classname>
  875. </link>
  876. components.
  877. </para>
  878. <para>
  879. In order to define authentication, the user provides
  880. authentication adapter extening
  881. <classname>Zend_Amf_Auth_Abstract</classname>
  882. abstract class.
  883. The adapter should implement the
  884. <methodname>authenticate()</methodname>
  885. method just like regular
  886. <link linkend="zend.auth.introduction.adapters">authentication
  887. adapter</link>
  888. .
  889. </para>
  890. <para>
  891. The adapter should use properties
  892. <emphasis>_username</emphasis>
  893. and
  894. <emphasis>_password</emphasis>
  895. from the parent
  896. <classname>Zend_Amf_Auth_Abstract</classname>
  897. class in order to
  898. authenticate. These values are set by the server using
  899. <methodname>setCredentials()</methodname>
  900. method before call to
  901. <methodname>authenticate()</methodname>
  902. if the credentials are
  903. received in the
  904. <acronym>AMF</acronym>
  905. request headers.
  906. </para>
  907. <para>
  908. The identity returned by the adapter should be an object
  909. containing property
  910. <property>role</property>
  911. for the
  912. <acronym>ACL</acronym>
  913. access control to work.
  914. </para>
  915. <para>If the authentication result is not successful, the request is
  916. not proceseed further
  917. and failure message is returned with the
  918. reasons for failure taken from the result.</para>
  919. <para>
  920. The adapter is connected to the server using
  921. <methodname>setAuth()</methodname>
  922. method:
  923. </para>
  924. <programlisting language="php"><![CDATA[
  925. $server->setAuth(new My_Amf_Auth());
  926. ]]></programlisting>
  927. <para>
  928. Access control is performed by using
  929. <classname>Zend_Acl</classname>
  930. object set by
  931. <methodname>setAcl()</methodname>
  932. method:
  933. </para>
  934. <programlisting language="php"><![CDATA[
  935. $acl = new Zend_Acl();
  936. createPermissions($acl); // create permission structure
  937. $server->setAcl($acl);
  938. ]]></programlisting>
  939. <para>
  940. If the
  941. <acronym>ACL</acronym>
  942. object is set, and the class being
  943. called defines
  944. <methodname>initAcl()</methodname>
  945. method, this
  946. method will be called with the
  947. <acronym>ACL</acronym>
  948. object as an
  949. argument. The class then can create additional
  950. <acronym>ACL</acronym>
  951. rules and return
  952. <constant>TRUE</constant>
  953. , or return
  954. <constant>FALSE</constant>
  955. if no access control is required for this class.
  956. </para>
  957. <para>
  958. After
  959. <acronym>ACL</acronym>
  960. have been set up, the server will
  961. check if access is allowed with role set by the
  962. authentication,
  963. resource being the class name (or
  964. <constant>NULL</constant>
  965. for
  966. function calls) and privilege being the function name. If no
  967. authentication was
  968. provided, then if the
  969. <emphasis>anonymous</emphasis>
  970. role was defined, it will be
  971. used, otherwise the access will be denied.
  972. </para>
  973. <programlisting language="php"><![CDATA[
  974. if($this->_acl->isAllowed($role, $class, $function)) {
  975. return true;
  976. } else {
  977. require_once 'Zend/Amf/Server/Exception.php';
  978. throw new Zend_Amf_Server_Exception("Access not allowed");
  979. }
  980. ]]></programlisting>
  981. </sect2>
  982. </sect1>