| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 15103 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.amf.server">
- <title>Zend_Amf_Server</title>
- <para>
- <classname>Zend_Amf_Server</classname> proporciona un servidor al estilo RPC para
- tramitar solicitudes hechas desde Adobe Flash Player utilizando el protocolo AMF.
- Al igual que todas las clases de servidor, Zend Framework sigue la API de
- SoapServer, proporcionando una interfaz para crear servidores fácil de recordar.
- </para>
- <example id="zend.amf.server.basic">
- <title>Servidor AMF básico</title>
- <para>
- Asumamos que ha creado la clase <code>Foo</code> con una
- variedad de métodos públicos. Usando el siguiente código, puede
- crear un servidor AMF:
- </para>
- <programlisting role="php"><![CDATA[
- $servidor = new Zend_Amf_Server();
- $servidor->setClass('Foo');
- $respuesta = $servidor->handle();
- echo $respuesta;
- ]]></programlisting>
- <para>
- Alternativamente, en su lugar puede elegir agregar una función simple como
- llamada de retorno:
- </para>
- <programlisting role="php"><![CDATA[
- $servidor = new Zend_Amf_Server();
- $servidor->addFunction('myUberCoolFunction');
- $respuesta = $servidor->handle();
- echo $respuesta;
- ]]></programlisting>
- <para>
- También puede combinar y examinar la identidad de varias clases y funciones.
- Al hacerlo, sugerimos darle un espacio de nombres a cada una para
- garantizar que no ocurran colisiones entre nombres de métodos;
- puede hacerse simplemente pasando una segunda cadena de argumentos para cualquier <code>addFunction()</code> o
- <code>setClass()</code>:
- </para>
- <programlisting role="php"><![CDATA[
- $servidor = new Zend_Amf_Server();
- $servidor->addFunction('myUberCoolFunction', 'my')
- ->setClass('Foo', 'foo')
- ->setClass('Bar', 'bar');
- $respuesta = $servidor->handle();
- echo $respuesta;
- ]]></programlisting>
- <para>
- El <classname>Zend_Amf_Server</classname> también permite cargar servicios
- dinámicamente, en función de una ruta de directorio ya suministrada.
- Puede añadir al servidor tantos directorios como desee.
- El orden en que se añadan los directorios al servidor será el orden en que
- se realizarán las búsquedas LIFO en los directorios para coincidir
- con la clase.
- El método <code>addDirectory()</code> realiza la acción de añadir directorios.
- </para>
- <programlisting role="php"><![CDATA[
- $servidor->addDirectory(dirname(__FILE__) .'/../services/');
- $servidor->addDirectory(dirname(__FILE__) .'/../package/');
- ]]></programlisting>
- <para>
- Cuando se llama a servicios remotos, los nombres de los directorios que
- contengan las fuentes pueden tener los delimitadores guión bajo (_) y el punto (.).
- Cuando se utilize un guión bajo (_) tanto en PEAR como en Zend Framework,
- se respetarán los nombres de clases de acuerdo a las convenciones de nomenclatura.
- Esto significa que si usted llama al servicio com_Foo_Bar el servidor
- buscará el archivo Bar.php en cada una de las rutas incluidas en <code>com/Foo/Bar.php</code>.
- Si se usa la notación punto para su servicio remoto como <code>com.Foo.Bar</code>
- cada ruta incluida deberá tener <code>com/Foo/Bar.php</code> agregado al final
- para autocargar Bar.php.
- </para>
- <para>
- Todos las solicitudes AMF enviadas al script serán manejadas
- por el servidor, y este devolverá una respuesta AMF.
- </para>
- </example>
- <note>
- <title>Todos los métodos y las funciones agregadas requieren bloques de documentación (docblocks)</title>
- <para>
- Como todos los demás componentes del servidor en Zend Framework,
- debe documentar los métodos de su clase usando PHP docblocks.
- Como mínimo, necesita proporcionar anotaciones para cada argumento
- así como para el valor de retorno. Como ejemplos:
- </para>
- <programlisting role="php"><![CDATA[
- // Función que agregar:
- /**
- * @param string $nombre
- * @param string $saludo
- * @return string
- */
- function holaMundo($ombre, $saludo = 'Hola')
- {
- return $saludo . ', ' . $nombre;
- }
- ]]></programlisting>
- <programlisting role="php"><![CDATA[
- // Clase agregada
- class Mundo
- {
- /**
- * @param string $nombre
- * @param string $saludo
- * @return string
- */
- public function hola($nombre, $saludo = 'Hola')
- {
- return $saludo . ', ' . $nombre;
- }
- }
- ]]></programlisting>
- <para>
- Pueden usarse otras anotaciones, pero serán ignoradas.
- </para>
- </note>
- <sect2 id="zend.amf.server.flex">
- <title>Conectándose al Servidor desde Flex</title>
- <para>
- Conectarse a <classname>Zend_Amf_Server</classname> desde su proyecto Flex
- es bastante simple; solo necesita apuntar el final del URI
- a su script <classname>Zend_Amf_Server</classname>.
- </para>
- <para>
- Por ejemplo, digamos que usted ya ha creado su servidor y lo ha
- puesto en el fichero <code>server.php</code> en el directorio raíz (root)
- de su aplicación, por lo tanto la URI es <code>http://example.com/server.php</code>.
- En este caso, usted debería modificar su fichero services-config.xml
- poniendo este valor como atributo al punto final del canal uri.
- </para>
- <para>
- Si nunca ha creado un fichero services-config.xml puede hacerlo
- abriendo su proyecto en la ventana del navegador.
- Haga clic derecho sobre el nombre del proyecto y seleccione 'properties' (propiedades).
- En el cuadro de diálogo 'properties' del proyecto ir al menú ‘Flex Build Path' (Crear ruta Flex),
- luego en la pestaña ‘Library path’ (ruta de biblioteca) asegúrese
- de que el fichero 'rpc.swc' sea añadido a su ruta de proyectos
- y pulse Ok (Aceptar) para cerrar la ventana.
- </para>
- <para>
- También necesitará indicarle al compilador que debe usar
- services-config.xml para encontrar el punto final de RemoteObject.
- Para hacerlo, abra de nuevo el panel de propiedades de su proyecto
- haciendo clic en el botón derecho sobre el proyecto en la carpeta del
- navegador y seleccione 'properties' (propiedades).
- Ahora seleccione ‘Flex Compiler' (Compilador Flex) y añada la cadena:
- -services “services-config.xml".
- Presione 'Apply' (Aplicar) y luego en OK para volver a actualizar la opción.
- Lo que acaba de hacer es decirle al compilador Flex que busque en el fichero
- services-config.xml aquellas variables que se usarán en tiempo de
- ejecución por la clase RemotingObject.
- </para>
- <para>
- Ahora, para conectarnos a nuestros métodos remotos debemos indicarle a Flex
- qué fichero de configuración de servicios utilizar.
- Por esta razón creamos un nuevo fichero 'services-config.xml'
- en la carpeta src del proyecto Flex.
- Con click derecho sobre el proyecto y seleccionando 'new'(nuevo)
- 'File' (fichero), se abrirá una nueva ventana.
- Seleccione la carpeta del proyecto y luego nombre el archivo
- 'services-config.xml' y presione 'finish' (finalizar).
- </para>
- <para>
- Flex ha creado y abierto el nuevo fichero services-config.xml.
- Utilice el siguiente texto de ejemplo para su fichero services-config.xml.
- Asegúrese de actualizar su punto final para que concuerde con el servidor.
- Asegúrese también de guardar el fichero.
- </para>
- <programlisting role="xml"><![CDATA[
- <?xml version="1.0" encoding="UTF-8"?>
- <services-config>
- <services>
- <service id="zend-service"
- class="flex.messaging.services.RemotingService"
- messageTypes="flex.messaging.messages.RemotingMessage">
- <destination id="zend">
- <channels>
- <channel ref="zend-endpoint"/>
- </channels>
- <properties>
- <source>*</source>
- </properties>
- </destination>
- </service>
- </services>
- <channels>
- <channel-definition id="zend-endpoint"
- class="mx.messaging.channels.AMFChannel">
- <endpoint uri="http://example.com/server.php"
- class="flex.messaging.endpoints.AMFEndpoint"/>
- </channel-definition>
- </channels>
- </services-config>
- ]]></programlisting>
- <para>
- Hay dos puntos clave en el ejemplo.
- En primer lugar, pero último en el listado, creamos un canal AMF,
- y especificamos el punto final como la URL a nuestro <classname>Zend_Amf_Server</classname>:
- </para>
- <programlisting role="xml"><![CDATA[
- <channel-definition id="zend-endpoint"
- <endpoint uri="http://example.com/server.php"
- class="flex.messaging.endpoints.AMFEndpoint"/>
- </channel-definition>
- ]]></programlisting>
- <para>
- Advierta que a este canal le hemos dado un identificador, "zend-endpoint".
- El ejemplo crea un servicio cuyo destino hace referencia a este canal,
- asignándole también un ID, en este caso es "zend".
- </para>
- <para>
- Dentro de nuestros ficheros Flex MXML, necesitamos vincular un RemoteObject al servicio.
- En MXML, esto podría hacerse así:
- </para>
- <programlisting role="xml"><![CDATA[
- <mx:RemoteObject id="myservice"
- fault="faultHandler(event)"
- showBusyCursor="true"
- destination="zend">
- ]]></programlisting>
- <para>
- Aquí, hemos definido un nuevo objeto remoto identificado por "myservice"
- vinculado destino de servicio "zend" que hemos definido en el fichero
- <code>services-config.xml</code>. Entonces invocamos sus métodos en
- nuestro ActionScript simplemente llamando a "myservice.<method>".
- . A modo de ejemplo:
- </para>
- <programlisting role="ActionScript"><![CDATA[
- myservice.hello("Wade");
- ]]></programlisting>
- <para>
- Cuando se usan nombres-de-espacio, puede usarse
- "myservice.<namespace>.<method>":
- </para>
- <programlisting role="ActionScript"><![CDATA[
- myservice.world.hello("Wade");
- ]]></programlisting>
- <para>
- Para más información sobre como invocar a Flex RemoteObject visite el
- sitio de ayuda de Adobe Flex 3 en:<ulink
- url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html"></ulink>.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.errors">
- <title>Manejo de errores</title>
- <para>
- Por defecto, todas las excepciones producidas en sus
- clases o funciones adjuntas serán capturados y devueltas como
- mensajes de error de AMF (AMF ErrorMessages).
- Sin embargo, el contenido de estos objetos de mensajes de error
- variará dependiendo de si el servidor está o no en modo "producción"
- (el estado por defecto).
- </para>
- <para>
- Cuando se está en modo de producción, únicamente el código de excepción será devuelto.
- Si desactiva el modo de producción, algo que debe hacerse sólo
- para probar -- serán devueltos más detalles de la excepción:
- el mensaje de excepción (error), línea y backtrace serán adjuntados.
- </para>
- <para>
- Para desactivar el modo de producción, haga lo siguiente:
- </para>
- <programlisting role="php"><![CDATA[
- $server->setProduction(false);
- ]]></programlisting>
- <para>
- Para habilitarlo nuevamente, pase el valor true en su lugar.
- </para>
- <programlisting role="php"><![CDATA[
- $server->setProduction(true);
- ]]></programlisting>
- <note>
- <title>¡Deshabilite el modo de producción racionalmente!</title>
- <para>
- Sugerimos deshabilitar el modo de producción solo cuando se está
- en modo de desarrollo.
- Los mensajes de excepción y los backtraces puede contener información
- sensible del sistema, y no desea que se pueda acceder a ellas
- desde el exterior.
- Aunque AMF es un formato binario, ahora al ser abierta la especificación,
- cualquiera puede potencialmente deserializar los datos.
- </para>
- </note>
- <para>
- Un área en la que se debe tener especialmente mucho cuidado son los
- errores propios de PHP.
- Cuando la directiva INI <code>display_errors</code> está habilitada,
- los errores de PHP de cualquier nivel del reporte actual serán
- pasados directamente a la salida, y potencialmente se podrían hacer
- estragos con las respuestas de AMF.
- Para prevenir estos problemas, sugerimos deshabilitar la directiva
- <code>display_errors</code> cuando se está en modo de producción.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.response">
- <title>Respuestas de AMF</title>
- <para>
- En ocasiones es posible que quiera manipular ligeramente el objeto
- respuesta, es bastante usual querer devolver algunas cebeceras
- de mensajes adicionales. Puede hacerlo mediante el método del servidor
- <code>handle()</code> que devuelve el objeto respuesta.
- </para>
- <example id="zend.amf.server.response.messageHeaderExample">
- <title>Agregar cabeceras de mensaje a la respuesta de AMF</title>
- <para>
- En este ejemplo, añadiremos la cabecera de mensaje (MessageHeader)
- "foo" con el valor 'bar' a la respuesta antes de devolverla.
- </para>
- <programlisting role="php"><![CDATA[
- $respuesta = $servidor->handle();
- $respuesta->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
- echo $respuesta;
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.amf.server.typedobjects">
- <title>Objetos tipados</title>
- <para>
- Similarmente a SOAP, AMF permite pasar objetos entre cliente y servidor.
- Esto le da una gran flexibilidad y coherencia a ambos entornos.
- </para>
- <para>
- <code>Zend_Amf</code> ofrece tres métodos para mapear ActionScript
- y objetos PHP.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Primero, usted puede crear uniones explícitas a nivel del servidor,
- utilizando el método <code>setClassMap()</code>.
- El primer argumento es el nombre de la clase de ActionScript,
- el segundo es el nombre de la clase PHP que lo mapea:
- </para>
- <programlisting role="php"><![CDATA[
- // Mapea la clase ActionScript 'ContactVO' a la clase PHP 'Contact':
- $servidor->setClassMap('ContactVO', 'Contact');
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- Segundo, en su clase PHP puede ajustar la propiedad como pública
- mediante <code>$_explicitType</code>, con el valor
- representativo de la clase ActionScript que mapear:
- </para>
- <programlisting role="php"><![CDATA[
- class Contact
- {
- public $_explicitType = 'ContactVO';
- }
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- Tercero, en un sentido similar, puede definir como público el método
- <code>getASClassName()</code> dentro de su clase.
- Este método debe devolver la clase ActionScript apropiada:
- </para>
- <programlisting role="php"><![CDATA[
- class Contact
- {
- public function getASClassName()
- {
- return 'ContactVO';
- }
- }
- ]]></programlisting>
- </listitem>
- </itemizedlist>
- <para>
- Aunque hemos creado ContactVO en el servidor,
- ahora tenemos que hacer su clase correspondiente en AS3
- para que el servidor pueda mapear el objeto.
- </para>
- <para>
- Haga clic derecho sobre la carpeta src del proyecto Flex y seleccione New -> ActionScript File.
- Nombre el fichero como ContactVO y pulse 'finish' (finalizar) para verlo.
- Copie el siguiente código en el fichero para terminar de crear la clase.
- </para>
- <programlisting role="as"><![CDATA[
- package
- {
- [Bindable]
- [RemoteClass(alias="ContactVO")]
- public class ContactVO
- {
- public var id:int;
- public var firstname:String;
- public var lastname:String;
- public var email:String;
- public var mobile:String;
- public function ProductVO():void {
- }
- }
- }
- ]]></programlisting>
- <para>
- La clase es sintácticamente equivalente a la de PHP del mismo nombre.
- Los nombres de variables son exactamente los mismos y necesitan estar
- en el mismo contenedor para trabajar correctamente. Hay
- dos meta tags AS3 únicos en esta clase.
- El primero es vinculable y dispara un evento cuando es actualizada.
- El segundo es el tag RemoteClass y define que esta clase puede tener
- mapeado un objeto remoto con un nombre de alias, en este caso <code>ContactVO</code>
- Es obligatorio que en esta etiqueta(tag), el valor que se estableció es la clase PHP
- sea estrictamente equivalente.
- </para>
- <programlisting role="as"><![CDATA[
- [Bindable]
- private var myContact:ContactVO;
- private function getContactHandler(event:ResultEvent):void {
- myContact = ContactVO(event.result);
- }
- ]]></programlisting>
- <para>
- El siguiente resultado del evento debido a la llamada de servicio,
- se incorporó instantáneamente a ContactVO de Flex.
- Cualquier cosa que esté ligada a myContact será actualizada con los
- datos retornados por ContactVO.
- </para>
- </sect2>
- <sect2 id="zend.amf.server.flash">
- <title>Conectándose al Servidor desde Flash</title>
- <para>
- La conexión a <classname>Zend_Amf_Server</classname> desde su proyecto Flash
- es ligeramente distinta a la de Flex. Sin embargo una vez que la conexión
- con Flash funcione con <classname>Zend_Amf_Server</classname> lo hará igual
- modo que con Flex. El siguiente ejemplo también puede ser utilizado
- desde un fichero Flex AS3. Para nuestra conexión vamos a reutilizar
- la misma configuracion <classname>Zend_Amf_Server</classname> junto a la clase Mundo.
- </para>
- <para>
- Abra Flash CS y cree un nuevo fichero Flash (ActionScript 3).
- Nombre al documento como ZendExample.fla y guárdelo en una carpeta
- que utilizará para este ejemplo. Cree una nuevo fichero AS3 en el mismo
- directorio y llámelo Main.as. Abra ambos ficheros con su editor.
- Ahora vamos a conectar las dos ficheros a través de la clase documento.
- Seleccione ZendExample y haga clic en el escenario.
- Desde el panel del escenario cambie la propiedad de la clase Document a Main.
- Esto vincula al fichero Main.as con la interfaz de usuario en ZendExample.fla.
- Cuando ejecute el fichero ZendExample de Flash se ejecutará ahora
- la clase Main.as.
- El paso siguiente será añadir ActionScript para hacer una lamada AMF.
- </para>
- <para>
- Ahora vamos a hacer una clase Main(principal) para que podamos enviar
- los datos al servidor y mostrar el resultado.
- Copie el código siguiente en su fichero Main.as y luego vamos a recorrer
- el código para describir cuál es el papel de cada elemento.
- </para>
- <programlisting role="as"><![CDATA[
- package {
- import flash.display.MovieClip;
- import flash.events.*;
- import flash.net.NetConnection;
- import flash.net.Responder;
- public class Main extends MovieClip {
- private var gateway:String = "http://example.com/server.php";
- private var connection:NetConnection;
- private var responder:Responder;
- public function Main() {
- responder = new Responder(onResult, onFault);
- connection = new NetConnection;
- connection.connect(gateway);
- }
- public function onComplete( e:Event ):void{
- var params = "Sent to Server";
- connection.call("World.hello", responder, params);
- }
- private function onResult(result:Object):void {
- // Display the returned data
- trace(String(result));
- }
- private function onFault(fault:Object):void {
- trace(String(fault.description));
- }
- }
- }
- ]]></programlisting>
- <para>
- Primero tenemos que importar dos bibliotecas de ActionScript que realizan
- la mayor parte del trabajo. La primera es NetConnection que actúa como un
- tubo bidireccional entre el cliente y el servidor.
- La segunda es un objeto Responder que maneja los valores de retorno desde
- el servidor, y que están relacionados con el éxito o el fracaso de la llamada.
- </para>
- <programlisting role="as"><![CDATA[
- import flash.net.NetConnection;
- import flash.net.Responder;
- ]]></programlisting>
- <para>
- En la clase necesitaremos tres variables para representar a NetConnection,
- Responder, y la URL del gateway a nuestra instalación <classname>Zend_Amf_Server</classname>.
- </para>
- <programlisting role="as"><![CDATA[
- private var gateway:String = "http://example.com/server.php";
- private var connection:NetConnection;
- private var responder:Responder;
- ]]></programlisting>
- <para>
- En el constructor Main creamos un Responder(respondedor) y una nueva conexión al
- punto final de <classname>Zend_Amf_Server</classname>. El respondedor define dos
- diferentes métodos para manejar la respuesta desde el servidor.
- Por simplicidad los hemos llamado onResult y onFault.
- </para>
- <programlisting role="as"><![CDATA[
- responder = new Responder(onResult, onFault);
- connection = new NetConnection;
- connection.connect(gateway);
- ]]></programlisting>
- <para>
- La función onComplete se ejecuta tan pronto como la construcción
- ha concluido, enviando los datos al servidor.
- Necesitamos añadir una línea más que hace una llamada a la función
- <classname>Zend_Amf_Server</classname> Mundo->hola.
- </para>
- <programlisting role="as"><![CDATA[
- connection.call("Mundo.hola", responder, params);
- ]]></programlisting>
- <para>
- Cuando creamos la variable responder hemos definido las funciones onResult y onFault
- para manejar la respuesta proveniente del servidor.
- Hemos añadido la función OnResult para el resultado exitoso desde el servidor.
- Cada vez que se ejecuta apropiadamente el manejo de conexión con el
- servidor, el manejador de eventos llama esta función.
- </para>
- <programlisting role="as"><![CDATA[
- private function onResult(result:Object):void {
- // Muestra los datos devueltos
- trace(String(result));
- }
- ]]></programlisting>
- <para>
- La función onFault, se llama si hubo una respuesta nula desde el servidor.
- Esto ocurre cuando hay un error en el servidor, la URL al servidor es inválida,
- el servicio remoto o método no existe o cualquier otra cuestión
- relacionada con la conexión.
- </para>
- <programlisting role="as"><![CDATA[
- private function onFault(fault:Object):void {
- trace(String(fault.description));
- }
- ]]></programlisting>
- <para>
- La inclusión de ActionScript para realizar la conexión remota ha finalizado.
- Al ejecutar el fichero ZendExample, se establece una conexión con Zend_Amf.
- En resumen, se han añadido las variables requeridas para abrir una conexión
- con el servidor remoto, se han definido qué métodos se deben utilizar cuando su aplicación
- recibe una respuesta desde el servidor, y finalmente se han mostrado los datos de salida
- devueltos a través de trace().
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|