lunes, 27 de octubre de 2008

Flex: Ejemplo de acceso a datos remotos

El objetivo de este interesante artículo es demostrar cuán sencillo y potente es el uso de la tecnología Flex. En esta ocasión procederemos a invocar a datos almacenados remotamente, y visualizarlos en varios componentes, como una lista o un DataGrid.



El escenario será, por un lado, un sistema remoto (o local) basado en Apache, en donde se ha instalado un servidor de base de datos MySQL y el motor de PHP. Este sistema contendrá un servicio que retornará un XML con la información recogida, la cual será interpretada por la aplicación Flex, que mostrará dicha información.

En primer lugar, se ha creado una base de datos con una tabla muy sencilla que contendrá una relación de categorías. Esta tabla tiene la siguiente estructura:


TABLA: gallery_categories
CAMPO: id_category - unsigned integer, not null, primary key
CAMPO: category_name - varchar(16), not null
CAMPO: category_directory - varchar(255), not null

Para acceder a la base de datos, utilizaremos PHP, el cual se ha instalado sobre el servidor web Apache. En el directorio "htdocs" de Apache, se ha creado el fichero "service_categories.php". Este fichero contendrá el siguiente código:


<?php
function getCategories() {
$xml = "";
mysql_select_db('basedatos');
$qry_categories = "select id_category, category_name
from gallery_categories";
$result_categories = mysql_query($qry_categories);
$num_categories = mysql_num_rows($result_categories);
if ($num_categories>0) {
$xml="<gallery_categories>\n";

for ($i=0; $i<$num_categories; $i++)
{
$row_categories = mysql_fetch_array($result_categories);
$category_name = $row_categories['category_name'];
$xml = $xml." <category>\n";
$xml = $xml." <label>".$row_categories['category_name'].
"</label>\n";
$xml = $xml." <data>".$row_categories['id_category'].
"</data>\n";
$xml = $xml." </category>\n";
}

$xml= $xml."</gallery_categories>\n";
}

return $xml;
}


@ $db = mysql_pconnect('localhost', 'usuario', 'password');

if ($db)
{
$categories = getCategories();
echo "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n\n";
echo $categories;
mysql_close($db);
}

?>

El código PHP conecta con la base de datos (mysql_pconnect), invoca a la función getCategories(), la cual accede a la tabla, leyendo todos sus registros, y componiendo un XML, el cual será retornado por PHP. Este XML será como el siguiente:


<?xml version="1.0" encoding="ISO-8859-1" ?>

<gallery_categories>
<category>
<label>Categoria1</label>
<data>1</data>
</category>
<category>
<label>Categoria2</label>
<data>2</data>
</category>
</gallery_categories>

Podríamos haber usado los nombres de los campos en el XML. El uso de los tags "label" y "data" es debido a que el componente lista de Flex, utiliza estos tags clave para formar automáticamente la lista, mostrando el texto (label) y asociando el código correspondiente (data).


Una vez resuelta la lógica de negocio, le toca el turno a la presentación, en la cual Flex es el protagonista. Se comienza con la siguiente estructura de código:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="categoriesRequest.send()">

</mx:Application>

Flex utiliza el lenguaje MXML, basado en un juego especial de códigos en formato XML. Por ello, la primera línea (<?xml...), corresponde a un fichero en sintaxis XML. Tras esta línea, comienza la aplicación, la cual está representada por los tags <mx:Application> y </mx:Application>, y entre estos tags iría toda nuestra aplicación. A modo aclaratorio, todos los tags de Flex utilizan el prefijo "mx:", seguido de un tag correspondiente a un comando del lenguaje MXML.


El atributo "<xmlns..." apunta al juego de comandos del lenguaje XML.


El atributo "layout", indica la forma en que se distribuirán los componentes en el espacio de visualización de la aplicación. El valor "absolute" indica que la posición estará basada en coordenadas X e Y, desde la esquina superior izquierda, expresada en píxeles.


El atributo "creationComplete" indica qué debe hacer la aplicación una vez haya sido creada la instancia de la misma. En este caso, invocará al método send() del objeto "categoriesRequest", el cual se verá a continuación, y que se encargará de invocar al servicio creado en PHP.


El primer comando a utilizar dentro de nuestra aplicación será la siguiente:


<mx:HTTPService
id="categoriesRequest"
url="http://localhost/service_categories.php"
resultFormat="e4x"
useProxy="false"
/>

Este comando crear un servicio HTTP, el cual invocará al servicio creado en PHP, indicando la ubicación de éste en el atributo "url". El atributo "id" genera el nombre de cualquier objeto. En este caso, el objeto "categoriesRequest" es invocado a través de su método send() una vez creada la aplicación (ver el atributo creationComplete()". El atributo "resultFormat" establece el formato del XML a ser tratado, que, en este caso, es el "e4x", el cual permitirá tratar el XML de forma sencilla e intuitiva. Por último, el atributo "useProxy" determinará el uso de un proxy en caso de ser necesario (en nuestro caso no lo es).


Para probar el correcto funcionamiento de este servicio, utilizaremos el componente TextArea, el cual mostrará el XML recuperado por el objeto "categoriesRequest". Se incluirá el siguiente código justo después del anterior:


<mx:TextArea
width="300" height="200"
text="{categoriesRequest.lastResult.toString()}"/>

El componente TextArea mostrará una caja de texto grande que permite visualizar varias líneas. El atributo "width" establece el ancho (en píxeles) del componente. El atributo "height" establece el ancho. El atributo "text" contiene el texto a visualizar en el componente. En este caso, el resultado del comando ejecutado entre las llaves será lo que se visualice. El comando en cuestión es el texto devuelto por el método toString(), correspondiente al XML invocado por el objeto "categoriesRequest". "lastResult" permite posicionarse al inicio del XML obtenido.


El resultado sería el siguiente:



Una vez verificado que se recoge bien el XML, se procede a utilizar el mismo para utilizar los datos obtenidos de forma funcional. En el primer ejemplo se utilizará una lista, la cual mostrará los valores legibles, uno debajo de otro. Cuando se selecciona uno de estos valores legibles, internamente tendrá asociado un valor clave, como un código o un identificador. Para ello, el XML debe tener los tags clave <label> y <data>. Para ello, se sustituirá el código del componente TextArea por este otro código:


<mx:List
id="lst_categories"
dataProvider="{categoriesRequest.lastResult.category}"/>

El componente List accederá al nivel del tags "category" dentro del XML, recogiendo de cada uno encontrado los atributos "label" y "data", y aplicando el texto y el valor correspondientes a la lista. El atributo "dataProvider" se encargará de acceder a dicho nivel, dentro del XML obtenido en el objeto "categoriesRequest".


El último componente a probar será DataGrid, que mostrará una tabla con los datos. En este caso, no sería necesario que utilice los tags clave "label" y "data", pudiendo utilizarse los tags deseados. El código para este componente será el siguiente:


<mx:DataGrid
dataProvider="{categoriesRequest.lastResult.category}">
<mx:columns>
<mx:DataGridColumn
headerText="ID"
dataField="data"/>
<mx:DataGridColumn
headerText="Nombre"
dataField="label"/>
</mx:columns>
</mx:DataGrid>

"DataGrid" define el objeto de tabla, que se alimentará de los niveles "category" del XML (dataProvider). El tag "mx:columns" define la estructura de columnas de la tabla, cada una de las cuales está representada por el tag "mx:DataGridColumn", estableciendo el texto de cabecera (headerText) y el campo origen de los datos (dataField).


El resultado sería el siguiente: