sábado, 25 de abril de 2009

Tutorial HTTP Service con Flex y PHP

Existen dos grandes maneras de comunicarse remotamente a través de aplicaciones web, son dos enfoques que tienen diferencias muy marcadas, y que si aprendemos a utilizarlos bien, podemos explotar los mejores aspectos de cada método y lograr aplicaciones con una capa de datos robusta y veloz.

Uno de los enfoques (SOAP) es a través de exposiciones de metodos remotos para que puedan ser llamadas desde otras computadoras, si quieres aprender un poco mas sobre eso puedes entrar a mi tutorial Video tutorial WebService basico con php donde lo explico as detalladamente.

El otro enfoque, que utilizaremos en este tutorial, tiene que ver con los metodos mas primitivos que existen en el protocolo http, que seguramente los que han trabajado con formularios web han escuchado algunos de estos: POST, GET, PUT, DELETE, etc. Un ejemplo de arquitectura web que utiliza este enfoque es llamado REST.

Vamos a emprezar, la aplicación que vamos a desarrollar va a tener dos lados, cliente y servidor. Del lado del cliente se creará una aplicacion flex llamada myHTTPService.mxml que se utilizará para visualizar todos los usuarios insertados en una base de datos y existirá un formulario para la insercion de un nuevo usuario. Del lado del servidor se creará una archivo PHP llamado request.php que permitirá acceder a la base de datos para realizar las consultas e inserciones pedidas por el cliente flex.



El lado del Cliente
Código myHTTPService.mxml


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="send_data()" height="503">
<mx:Script>
<![CDATA[
import mx.utils.ObjectProxy;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.http.HTTPService;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;

private var service:HTTPService


[Bindable]
private var usuarios : ArrayCollection = new ArrayCollection();

[Bindable]
public var cards: Array = ["PUT","POST","GET","DELETE"];

[Bindable]
public var selectedItem:Object = "GET";


public function send_data() : void
{
var obj : Object = new Object();
useHttpService(obj);
}

public function procesar() : void
{
if(nombre.text.length>0)
{
var obj : Object = new Object();
obj.nombre = nombre.text;
obj.id = codigo.text;

useHttpService(obj);
}
else
{
Alert.show("El nombre es obligatorio");
}
}

public function traspasar() : void
{
var a : Object = dg.selectedItem;
nombre.text = a.nombre;
codigo.text = a.id;
}

public function useHttpService(parameters:Object):void {
service = new HTTPService();
//service.destination = "http://localhost/tutoriales/httpservice/request.php";
service.url = "http://ejemplos.net78.net/httpservice/request.php";
service.method = "POST";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.useProxy = false;
service.send(parameters);
}


public function httpResult(event:ResultEvent):void {
var result:Object = event.result;
//Do something with the result.
if(result.users.user is ObjectProxy)
usuarios = new ArrayCollection([{nombre:result.users.user.nombre , id:result.users.user.id}]);
else
usuarios = result.users.user;
}


public function httpFault(event:FaultEvent):void {
var faultstring:String = event.fault.faultString;
Alert.show(faultstring);
}
]]>
</mx:Script>
<mx:DataGrid id="dg" x="10" y="10" dataProvider="{usuarios}" click="traspasar()"/>
<mx:Canvas x="10" y="182" width="260" height="98" backgroundColor="#FFFFFF">
<mx:Label x="10" y="10" text="Nombre:"/>
<mx:Label x="10" y="42" text="Id:"/>
<mx:TextInput x="90" y="8" id="nombre"/>
<mx:TextInput x="90" y="40" id="codigo" enabled="false"/>
<mx:Button x="173" y="66" label="Insertar" click="procesar()"/>
</mx:Canvas>


</mx:Application>




Ahora, que debemos destacar de esta aplicacion, la esencia de todo esta en la funcion useHttpService: Esta funcion se encarga de crear una peticion a un servicio http, para eso creamos un objeto de tipo HTTPService que va a simular un comportamiento parecido al que sucede cuando le damos a submit en un formulario web estandar, pero en este caso, en lugar de colocar varios input text, comboboxes, etc. Vamos a armar un objeto (en esta funcion lo llamamos "parameters") donde cada atributo de este objeto se comportara como una variable independiente en el lado de php, es decir, si al objeto le colocamos la propiedad nombre, entonces en php haremos $_POST['nombre'] para recibir el valor de esa propiedad.

Recuerden que en Flex un objeto de la clase Object puede tener cualquier atributo que nosotros queramos, solo debemos asignarle un valor a ese atributo inventado y a partir de ese momento el objeto contiene ese atributo con ese valor que le dimos.


Ahora vamos a analizar esa funcion paso por paso:

public function useHttpService(parameters:Object):void {
service = new HTTPService();
service.url = "http://ejemplos.net78.net/httpservice/request.php";
service.method = "POST";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
}

El objeto service que acabamos de crear debemos pasarle varios parametros:
  1. URL: la direccion de la pagina que va a recibir nuestro formulario.
  2. Method: puede ser POST, GET, PUT, DELETE, ETC.
  3. send(parameters): Recuerden que el objeto parameters contiene todas las variables que queremos pasar al lado de PHP.
  4. Por ultimo escuchamos dos eventos "result" y "fault", el primero de ellos se disparará si el servicio se invoca correctamente (si encontro el URL que pusimos arriba y si en el lado del servidor PHP nos devolvio un resultado coherente) y nos llevará a la funcion httpresult donde procesaremos los resultados, el segundo de los eventos se disparará si la llamada al servicio no puede ser procesada y nos llevará al método httpfault.
El lado del servidor

En el lado del servidor vamos a crear un archivo php llamado reques.php, este archivo deberá procesar correctamente las peticios POST que haga el lado del cliente y deberá devolver la lista de usuarios que han sido insertados dentro de la base de datos:

Código request.php


//connect to the database
$mysql = mysql_connect("localhost", "root", "");
mysql_select_db( "phprestsql" );


//if the username and email address are filled out
if( $_POST["nombre"])
{
//add the user
$Query = "INSERT INTO user VALUES ('".$_POST['nombre']."','')";
$Result = mysql_query( $Query );
}


//return a list of all the users
$Query = "SELECT * from user";
$Result = mysql_query( $Query );


$Return = "<users>";


while ( $User = mysql_fetch_object( $Result ) )
{
$Return .= "<user><id>".$User->id."</id><nombre>".$User->nombre."</nombre></user>";
}
$Return .= "</users>";
mysql_free_result( $Result );
print ($Return);



Como pueden ver el lado de php es muy basico y es similar al que se utilizaria si estubieramos trabajando con formularios comunes y corrientes. Debemos recibir la variable "nombre" que pasamos desde flex y luego realizar una insercion en la base de datos. Luego de realizar la insercion consultamos toda la tabla de usuarios para implimir un xml en la pantalla que sera lo que constituirá el objeto de respuesta de vuelta hacia flex, ese se recibira como parametro del metodo httpresult en caso de que la llamada al servicio se haya ejecutado correctamente.

Espero que hayan entendido todo prefectamente, trate de ser lo mas claro posible, cualquier pregunta no duden en preguntarme a través de los comentarios de este blog. Les dejo un ejemplo funcionando de la aplicacion y los codigos fuentes de ambos lados (cliente y servidor).




10 comentarios:

  1. una consulta :
    como puedes ingresar la eñe y los acentos?
    a mi no me resulta agregue headers como muestran algunos ejemplos en la red pero aun asi no me resulta latin1 .
    gracias

    ResponderEliminar
  2. el ejemplo no funciona , actualiza los id pero no muestra ni guarda los nombres en la db.

    ResponderEliminar
  3. ya lo solucione grx , lo de la cabecera

    ResponderEliminar
  4. QUE SE PUEDE INTERPRETAR POR LA CONDICION:

    IF (result.users.user is ObjectProxy)

    ResponderEliminar
  5. Para agregar la ñ y los acentos, puedes usar este código:
    public function correctLinux(e:Event):void
    {
    var str:String;
    var ik:String=String.fromCharCode(173);
    var regEx:RegExp=new RegExp(ik, "g");
    var altgr:String=String.fromCharCode(03);
    var regEx2:RegExp=new RegExp(altgr, "g");

    str=e.currentTarget.text;

    //import mx.controls.Alert.show("Current Target: " + str);

    str=str.replace("á", "á");
    str=str.replace("é", "é");
    str=str.replace("ó", "ó");
    str=str.replace("ú", "ú");
    str=str.replace("ñ", "ñ");
    str=str.replace("Ñ", "Ñ");
    str=str.replace(regEx, "í");
    str=str.replace("Ã", "");
    str=str.replace(regEx2, "");

    e.currentTarget.text=str;
    }

    y lo llamas por ejemplo desde los TextInput:

    TextInput id="username" change="correctLinux(event)"
    TextInput id="password" change="correctLinux(event)"
    --
    JR

    ResponderEliminar
  6. hola excelente tuto me sirvio de gran ayuda

    ResponderEliminar
  7. Mil gracias crack! suerte!!!

    ResponderEliminar
  8. gracias amigo, pero oye hay veces que no actualiza los datos. le eh quitado el insert sólo para recibirlos y no me actualiza o tengo que darle dos o tres veces para que lo haga :/. sabras alguna solución?

    ResponderEliminar
  9. Hola soy novato, hago la seleccion de un solo registro pero lo que quiero es mandarlo a un label o text no a un datagrid.
    Como lo hago?
    Agradeciendo de Antemano su colaboracion

    Miguel

    ResponderEliminar
  10. ayuda por favor, como paso variable de un radio button httpservice a un php agradecer muchisimo saludos todos

    ResponderEliminar